@lifi/widget 4.1.0 → 4.2.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.
Files changed (204) hide show
  1. package/dist/esm/AppDefault.js +14 -0
  2. package/dist/esm/AppDefault.js.map +1 -1
  3. package/dist/esm/components/AmountInput/AmountInput.js +2 -1
  4. package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
  5. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +4 -2
  6. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  7. package/dist/esm/components/AmountInput/AmountInputEndAdornment.style.js +1 -1
  8. package/dist/esm/components/AmountInput/AmountInputEndAdornment.style.js.map +1 -1
  9. package/dist/esm/components/AmountInput/PriceFormHelperText.js +4 -2
  10. package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
  11. package/dist/esm/components/AmountInputCard/AmountInputCard.style.js +98 -0
  12. package/dist/esm/components/AmountInputCard/AmountInputCard.style.js.map +1 -0
  13. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js +25 -0
  14. package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -0
  15. package/dist/esm/components/AmountInputCard/BalanceDisplay.js +35 -0
  16. package/dist/esm/components/AmountInputCard/BalanceDisplay.js.map +1 -0
  17. package/dist/esm/components/AmountInputCard/BalanceDisplay.style.js +11 -0
  18. package/dist/esm/components/AmountInputCard/BalanceDisplay.style.js.map +1 -0
  19. package/dist/esm/components/AmountInputCard/FiatValueToggle.js +41 -0
  20. package/dist/esm/components/AmountInputCard/FiatValueToggle.js.map +1 -0
  21. package/dist/esm/components/AmountInputCard/PercentageChips.js +80 -0
  22. package/dist/esm/components/AmountInputCard/PercentageChips.js.map +1 -0
  23. package/dist/esm/components/AmountInputCard/PercentageChips.style.js +43 -0
  24. package/dist/esm/components/AmountInputCard/PercentageChips.style.js.map +1 -0
  25. package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js +137 -0
  26. package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js.map +1 -0
  27. package/dist/esm/components/AmountInputCard/SendAmountCard.js +102 -0
  28. package/dist/esm/components/AmountInputCard/SendAmountCard.js.map +1 -0
  29. package/dist/esm/components/Avatar/Avatar.js +12 -3
  30. package/dist/esm/components/Avatar/Avatar.js.map +1 -1
  31. package/dist/esm/components/Chains/VirtualizedChainList.js +2 -1
  32. package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
  33. package/dist/esm/components/Header/HeaderNavigationTabs.js +14 -1
  34. package/dist/esm/components/Header/HeaderNavigationTabs.js.map +1 -1
  35. package/dist/esm/components/IconCircle/IconCircle.style.js +1 -1
  36. package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.js +99 -0
  37. package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.js.map +1 -0
  38. package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.style.js +52 -0
  39. package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.style.js.map +1 -0
  40. package/dist/esm/components/LimitPriceCard/LimitPriceCard.js +115 -0
  41. package/dist/esm/components/LimitPriceCard/LimitPriceCard.js.map +1 -0
  42. package/dist/esm/components/LimitPriceCard/LimitPriceCard.style.js +89 -0
  43. package/dist/esm/components/LimitPriceCard/LimitPriceCard.style.js.map +1 -0
  44. package/dist/esm/components/LimitPriceCard/LimitPricePresets.js +91 -0
  45. package/dist/esm/components/LimitPriceCard/LimitPricePresets.js.map +1 -0
  46. package/dist/esm/components/RouteCard/RouteProviderCard.js +118 -0
  47. package/dist/esm/components/RouteCard/RouteProviderCard.js.map +1 -0
  48. package/dist/esm/components/Routes/LimitOrderRoutes.js +34 -0
  49. package/dist/esm/components/Routes/LimitOrderRoutes.js.map +1 -0
  50. package/dist/esm/components/Routes/Routes.js +2 -2
  51. package/dist/esm/components/Routes/Routes.js.map +1 -1
  52. package/dist/esm/components/SettingsPanel/SettingsPanel.js +51 -0
  53. package/dist/esm/components/SettingsPanel/SettingsPanel.js.map +1 -0
  54. package/dist/esm/components/SettingsPanel/SettingsPanel.style.js +33 -0
  55. package/dist/esm/components/SettingsPanel/SettingsPanel.style.js.map +1 -0
  56. package/dist/esm/components/SettingsPanel/utils.js +14 -0
  57. package/dist/esm/components/SettingsPanel/utils.js.map +1 -0
  58. package/dist/esm/components/SwapButton/SwapButton.js +50 -0
  59. package/dist/esm/components/SwapButton/SwapButton.js.map +1 -0
  60. package/dist/esm/components/SwapButton/SwapButton.style.js +24 -0
  61. package/dist/esm/components/SwapButton/SwapButton.style.js.map +1 -0
  62. package/dist/esm/components/TokenPillButton/TokenPillButton.js +52 -0
  63. package/dist/esm/components/TokenPillButton/TokenPillButton.js.map +1 -0
  64. package/dist/esm/components/TokenPillButton/TokenPillButton.style.js +39 -0
  65. package/dist/esm/components/TokenPillButton/TokenPillButton.style.js.map +1 -0
  66. package/dist/esm/config/version.d.ts +1 -1
  67. package/dist/esm/config/version.js +1 -1
  68. package/dist/esm/config/version.js.map +1 -1
  69. package/dist/esm/hooks/useChainSearch.js +2 -1
  70. package/dist/esm/hooks/useChainSearch.js.map +1 -1
  71. package/dist/esm/hooks/useLimitMarketRate.js +24 -0
  72. package/dist/esm/hooks/useLimitMarketRate.js.map +1 -0
  73. package/dist/esm/hooks/useLinkedLimitFields.js +49 -0
  74. package/dist/esm/hooks/useLinkedLimitFields.js.map +1 -0
  75. package/dist/esm/hooks/useRoutes.js +23 -6
  76. package/dist/esm/hooks/useRoutes.js.map +1 -1
  77. package/dist/esm/hooks/useTokens.js +16 -14
  78. package/dist/esm/hooks/useTokens.js.map +1 -1
  79. package/dist/esm/hooks/useWideVariant.js +5 -2
  80. package/dist/esm/hooks/useWideVariant.js.map +1 -1
  81. package/dist/esm/i18n/en.json +22 -0
  82. package/dist/esm/index.d.ts +2 -2
  83. package/dist/esm/pages/MainPage/LimitPageContent.js +23 -0
  84. package/dist/esm/pages/MainPage/LimitPageContent.js.map +1 -0
  85. package/dist/esm/pages/MainPage/MainPage.js +19 -22
  86. package/dist/esm/pages/MainPage/MainPage.js.map +1 -1
  87. package/dist/esm/pages/MainPage/MainPageActions.js +28 -0
  88. package/dist/esm/pages/MainPage/MainPageActions.js.map +1 -0
  89. package/dist/esm/pages/MainPage/ReviewButton.js +9 -2
  90. package/dist/esm/pages/MainPage/ReviewButton.js.map +1 -1
  91. package/dist/esm/pages/RoutePriorityPage.js +48 -0
  92. package/dist/esm/pages/RoutePriorityPage.js.map +1 -0
  93. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js +2 -2
  94. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js.map +1 -1
  95. package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js +12 -27
  96. package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js.map +1 -1
  97. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippagePage.js +133 -0
  98. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippagePage.js.map +1 -0
  99. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js +14 -72
  100. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js.map +1 -1
  101. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.style.js +26 -14
  102. package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.style.js.map +1 -1
  103. package/dist/esm/pages/SettingsPage/ThemeSettings.js +4 -0
  104. package/dist/esm/pages/SettingsPage/ThemeSettings.js.map +1 -1
  105. package/dist/esm/pages/TransactionPage/TransactionReview.js +4 -1
  106. package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
  107. package/dist/esm/providers/I18nProvider/I18nProvider.js +1 -1
  108. package/dist/esm/providers/I18nProvider/enResource.d.ts +1 -1
  109. package/dist/esm/providers/I18nProvider/enResource.js +1 -1
  110. package/dist/esm/providers/I18nProvider/types.d.ts +2 -2
  111. package/dist/esm/providers/SDKClientProvider.js +25 -24
  112. package/dist/esm/providers/SDKClientProvider.js.map +1 -1
  113. package/dist/esm/providers/WidgetProvider/WidgetProvider.js +22 -21
  114. package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
  115. package/dist/esm/stores/form/URLSearchParamsBuilder.js +14 -3
  116. package/dist/esm/stores/form/URLSearchParamsBuilder.js.map +1 -1
  117. package/dist/esm/stores/form/createFormStore.js +6 -2
  118. package/dist/esm/stores/form/createFormStore.js.map +1 -1
  119. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js +3 -0
  120. package/dist/esm/stores/form/getDefaultValuesFromQueryString.js.map +1 -1
  121. package/dist/esm/stores/form/types.d.ts +9 -1
  122. package/dist/esm/stores/form/types.d.ts.map +1 -1
  123. package/dist/esm/stores/form/types.js.map +1 -1
  124. package/dist/esm/stores/form/useClearAmountFields.js +1 -0
  125. package/dist/esm/stores/form/useClearAmountFields.js.map +1 -1
  126. package/dist/esm/stores/navigationTabs/useNavigationTabsStore.js +4 -2
  127. package/dist/esm/stores/navigationTabs/useNavigationTabsStore.js.map +1 -1
  128. package/dist/esm/stores/navigationTabs/utils.js +38 -8
  129. package/dist/esm/stores/navigationTabs/utils.js.map +1 -1
  130. package/dist/esm/types/events.d.ts +10 -1
  131. package/dist/esm/types/events.d.ts.map +1 -1
  132. package/dist/esm/types/events.js +2 -0
  133. package/dist/esm/types/events.js.map +1 -1
  134. package/dist/esm/types/widget.d.ts +9 -0
  135. package/dist/esm/types/widget.d.ts.map +1 -1
  136. package/dist/esm/types/widget.js.map +1 -1
  137. package/dist/esm/utils/format.d.ts +1 -1
  138. package/dist/esm/utils/format.d.ts.map +1 -1
  139. package/dist/esm/utils/format.js +2 -2
  140. package/dist/esm/utils/format.js.map +1 -1
  141. package/dist/esm/utils/limitOrder.js +61 -0
  142. package/dist/esm/utils/limitOrder.js.map +1 -0
  143. package/dist/esm/utils/navigationRoutes.d.ts +2 -0
  144. package/dist/esm/utils/navigationRoutes.d.ts.map +1 -1
  145. package/dist/esm/utils/navigationRoutes.js +6 -0
  146. package/dist/esm/utils/navigationRoutes.js.map +1 -1
  147. package/package.json +11 -11
  148. package/src/AppDefault.tsx +16 -0
  149. package/src/components/AmountInput/AmountInputEndAdornment.style.ts +1 -1
  150. package/src/components/AmountInput/AmountInputEndAdornment.tsx +5 -2
  151. package/src/components/AmountInputCard/AmountInputCard.style.tsx +157 -0
  152. package/src/components/AmountInputCard/AmountInputCardPair.tsx +25 -0
  153. package/src/components/AmountInputCard/BalanceDisplay.style.tsx +9 -0
  154. package/src/components/AmountInputCard/BalanceDisplay.tsx +46 -0
  155. package/src/components/AmountInputCard/FiatValueToggle.tsx +55 -0
  156. package/src/components/AmountInputCard/PercentageChips.style.tsx +60 -0
  157. package/src/components/AmountInputCard/PercentageChips.tsx +100 -0
  158. package/src/components/AmountInputCard/ReceiveAmountCard.tsx +219 -0
  159. package/src/components/AmountInputCard/SendAmountCard.tsx +179 -0
  160. package/src/components/Avatar/Avatar.tsx +8 -3
  161. package/src/components/Header/HeaderNavigationTabs.tsx +19 -2
  162. package/src/components/LimitOrderSettings/LimitOrderSettings.style.tsx +69 -0
  163. package/src/components/LimitOrderSettings/LimitOrderSettings.tsx +124 -0
  164. package/src/components/LimitPriceCard/LimitPriceCard.style.tsx +103 -0
  165. package/src/components/LimitPriceCard/LimitPriceCard.tsx +153 -0
  166. package/src/components/LimitPriceCard/LimitPricePresets.tsx +139 -0
  167. package/src/components/RouteCard/RouteProviderCard.tsx +113 -0
  168. package/src/components/Routes/LimitOrderRoutes.tsx +64 -0
  169. package/src/components/Routes/Routes.tsx +3 -2
  170. package/src/components/SettingsPanel/SettingsPanel.style.tsx +41 -0
  171. package/src/components/SettingsPanel/SettingsPanel.tsx +73 -0
  172. package/src/components/SettingsPanel/utils.ts +27 -0
  173. package/src/components/SwapButton/SwapButton.style.tsx +28 -0
  174. package/src/components/SwapButton/SwapButton.tsx +71 -0
  175. package/src/components/TokenPillButton/TokenPillButton.style.tsx +50 -0
  176. package/src/components/TokenPillButton/TokenPillButton.tsx +81 -0
  177. package/src/config/version.ts +1 -1
  178. package/src/hooks/useLimitMarketRate.ts +39 -0
  179. package/src/hooks/useLinkedLimitFields.ts +74 -0
  180. package/src/hooks/useRoutes.ts +45 -4
  181. package/src/hooks/useWideVariant.ts +8 -2
  182. package/src/pages/MainPage/LimitPageContent.tsx +18 -0
  183. package/src/pages/MainPage/MainPage.tsx +43 -30
  184. package/src/pages/MainPage/MainPageActions.tsx +35 -0
  185. package/src/pages/MainPage/ReviewButton.tsx +13 -1
  186. package/src/pages/RoutePriorityPage.tsx +55 -0
  187. package/src/pages/SettingsPage/RoutePrioritySettings.tsx +14 -38
  188. package/src/pages/SettingsPage/SlippageSettings/SlippagePage.tsx +176 -0
  189. package/src/pages/SettingsPage/SlippageSettings/SlippageSettings.style.tsx +32 -25
  190. package/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx +14 -128
  191. package/src/pages/SettingsPage/ThemeSettings.tsx +4 -0
  192. package/src/stores/form/URLSearchParamsBuilder.tsx +25 -3
  193. package/src/stores/form/createFormStore.ts +7 -3
  194. package/src/stores/form/getDefaultValuesFromQueryString.ts +11 -0
  195. package/src/stores/form/types.ts +14 -1
  196. package/src/stores/form/useClearAmountFields.ts +1 -0
  197. package/src/stores/navigationTabs/types.ts +6 -0
  198. package/src/stores/navigationTabs/useNavigationTabsStore.tsx +8 -3
  199. package/src/stores/navigationTabs/utils.ts +67 -5
  200. package/src/types/events.ts +12 -0
  201. package/src/types/widget.ts +9 -0
  202. package/src/utils/format.ts +6 -2
  203. package/src/utils/limitOrder.ts +88 -0
  204. package/src/utils/navigationRoutes.ts +6 -0
@@ -0,0 +1,99 @@
1
+ import { useFieldActions } from "../../stores/form/useFieldActions.js";
2
+ import { formatDuration } from "../../utils/format.js";
3
+ import { useFieldValues } from "../../stores/form/useFieldValues.js";
4
+ import { Card as Card$1 } from "../Card/Card.js";
5
+ import { Switch as Switch$1 } from "../Switch.js";
6
+ import { Container as Container$1, ExpiryValue, SettingItemButton, SettingItemTitle, SettingItemValue, SettingsRow, ToggleLabel } from "./LimitOrderSettings.style.js";
7
+ import { useState } from "react";
8
+ import { Menu, MenuItem } from "@mui/material";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { useTranslation } from "react-i18next";
11
+ import Check from "@mui/icons-material/Check";
12
+ import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
13
+ //#region src/components/LimitOrderSettings/LimitOrderSettings.tsx
14
+ /** Selectable order-validity durations, in seconds. */
15
+ const DURATIONS = [
16
+ 3600,
17
+ 86400,
18
+ 604800,
19
+ 2592e3,
20
+ 31536e3
21
+ ];
22
+ const LimitOrderSettings = (props) => {
23
+ const { t, i18n } = useTranslation();
24
+ const [validUntil, partiallyFillable] = useFieldValues("validUntil", "partiallyFillable");
25
+ const { setFieldValue } = useFieldActions();
26
+ const [anchorEl, setAnchorEl] = useState(null);
27
+ const open = Boolean(anchorEl);
28
+ const handleOpen = (event) => {
29
+ setAnchorEl(event.currentTarget);
30
+ };
31
+ const handleClose = () => {
32
+ setAnchorEl(null);
33
+ };
34
+ const handleSelect = (duration) => {
35
+ setFieldValue("validUntil", duration);
36
+ setAnchorEl(null);
37
+ };
38
+ const handlePartiallyFillableChange = (event) => {
39
+ setFieldValue("partiallyFillable", event.target.checked);
40
+ };
41
+ return /* @__PURE__ */ jsxs(Container$1, {
42
+ ...props,
43
+ children: [
44
+ /* @__PURE__ */ jsx(Card$1, { children: /* @__PURE__ */ jsxs(SettingItemButton, {
45
+ onClick: handleOpen,
46
+ disableRipple: true,
47
+ "aria-haspopup": "menu",
48
+ "aria-expanded": open,
49
+ children: [/* @__PURE__ */ jsx(SettingItemTitle, { children: t("limitOrder.expiresIn") }), /* @__PURE__ */ jsxs(ExpiryValue, { children: [/* @__PURE__ */ jsx(SettingItemValue, { children: formatDuration(validUntil, i18n.language, "long") }), /* @__PURE__ */ jsx(KeyboardArrowDownIcon, { sx: {
50
+ fontSize: 20,
51
+ height: "18px",
52
+ marginTop: "2px"
53
+ } })] })]
54
+ }) }),
55
+ /* @__PURE__ */ jsx(Menu, {
56
+ anchorEl,
57
+ open,
58
+ onClose: handleClose,
59
+ anchorOrigin: {
60
+ vertical: "bottom",
61
+ horizontal: "right"
62
+ },
63
+ transformOrigin: {
64
+ vertical: "top",
65
+ horizontal: "right"
66
+ },
67
+ slotProps: { paper: { sx: (theme) => ({
68
+ border: `1px solid ${theme.vars.palette.grey[300]}`,
69
+ boxShadow: "none",
70
+ ...theme.applyStyles("dark", { borderColor: theme.vars.palette.grey[800] })
71
+ }) } },
72
+ children: DURATIONS.map((duration) => /* @__PURE__ */ jsxs(MenuItem, {
73
+ onClick: () => handleSelect(duration),
74
+ sx: (theme) => ({
75
+ justifyContent: "space-between",
76
+ gap: 4,
77
+ fontSize: 14,
78
+ fontWeight: 700,
79
+ lineHeight: "18px",
80
+ color: theme.vars.palette.text.primary
81
+ }),
82
+ children: [formatDuration(duration, i18n.language, "long"), duration === validUntil ? /* @__PURE__ */ jsx(Check, {
83
+ color: "primary",
84
+ fontSize: "small"
85
+ }) : null]
86
+ }, duration))
87
+ }),
88
+ /* @__PURE__ */ jsx(Card$1, { children: /* @__PURE__ */ jsxs(SettingsRow, { children: [/* @__PURE__ */ jsx(ToggleLabel, { children: t("limitOrder.partiallyFillable") }), /* @__PURE__ */ jsx(Switch$1, {
89
+ checked: partiallyFillable,
90
+ onChange: handlePartiallyFillableChange,
91
+ "aria-label": t("limitOrder.partiallyFillable")
92
+ })] }) })
93
+ ]
94
+ });
95
+ };
96
+ //#endregion
97
+ export { LimitOrderSettings };
98
+
99
+ //# sourceMappingURL=LimitOrderSettings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitOrderSettings.js","names":["Container","Card","Switch"],"sources":["../../../../src/components/LimitOrderSettings/LimitOrderSettings.tsx"],"sourcesContent":["import Check from '@mui/icons-material/Check'\nimport KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'\nimport type { BoxProps } from '@mui/material'\nimport { Menu, MenuItem } from '@mui/material'\nimport { type ChangeEvent, type JSX, type MouseEvent, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { formatDuration } from '../../utils/format.js'\nimport { Card } from '../Card/Card.js'\nimport { Switch } from '../Switch.js'\nimport {\n Container,\n ExpiryValue,\n SettingItemButton,\n SettingItemTitle,\n SettingItemValue,\n SettingsRow,\n ToggleLabel,\n} from './LimitOrderSettings.style.js'\n\n/** Selectable order-validity durations, in seconds. */\nconst DURATIONS = [3600, 86400, 604800, 2592000, 31536000]\n\nexport const LimitOrderSettings: React.FC<BoxProps> = (props): JSX.Element => {\n const { t, i18n } = useTranslation()\n const [validUntil, partiallyFillable] = useFieldValues(\n 'validUntil',\n 'partiallyFillable'\n )\n const { setFieldValue } = useFieldActions()\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)\n const open = Boolean(anchorEl)\n\n const handleOpen = (event: MouseEvent<HTMLElement>): void => {\n setAnchorEl(event.currentTarget)\n }\n\n const handleClose = (): void => {\n setAnchorEl(null)\n }\n\n const handleSelect = (duration: number): void => {\n setFieldValue('validUntil', duration)\n setAnchorEl(null)\n }\n\n const handlePartiallyFillableChange = (\n event: ChangeEvent<HTMLInputElement>\n ): void => {\n setFieldValue('partiallyFillable', event.target.checked)\n }\n\n return (\n <Container {...props}>\n <Card>\n <SettingItemButton\n onClick={handleOpen}\n disableRipple\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n <SettingItemTitle>{t('limitOrder.expiresIn')}</SettingItemTitle>\n <ExpiryValue>\n <SettingItemValue>\n {formatDuration(validUntil, i18n.language, 'long')}\n </SettingItemValue>\n <KeyboardArrowDownIcon\n sx={{ fontSize: 20, height: '18px', marginTop: '2px' }}\n />\n </ExpiryValue>\n </SettingItemButton>\n </Card>\n <Menu\n anchorEl={anchorEl}\n open={open}\n onClose={handleClose}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n slotProps={{\n paper: {\n sx: (theme) => ({\n border: `1px solid ${theme.vars.palette.grey[300]}`,\n boxShadow: 'none',\n ...theme.applyStyles('dark', {\n borderColor: theme.vars.palette.grey[800],\n }),\n }),\n },\n }}\n >\n {DURATIONS.map((duration) => (\n <MenuItem\n key={duration}\n onClick={() => handleSelect(duration)}\n sx={(theme) => ({\n justifyContent: 'space-between',\n gap: 4,\n fontSize: 14,\n fontWeight: 700,\n lineHeight: '18px',\n color: theme.vars.palette.text.primary,\n })}\n >\n {formatDuration(duration, i18n.language, 'long')}\n {duration === validUntil ? (\n <Check color=\"primary\" fontSize=\"small\" />\n ) : null}\n </MenuItem>\n ))}\n </Menu>\n <Card>\n <SettingsRow>\n <ToggleLabel>{t('limitOrder.partiallyFillable')}</ToggleLabel>\n <Switch\n checked={partiallyFillable}\n onChange={handlePartiallyFillableChange}\n aria-label={t('limitOrder.partiallyFillable')}\n />\n </SettingsRow>\n </Card>\n </Container>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,MAAM,YAAY;CAAC;CAAM;CAAO;CAAQ;CAAS;AAAQ;AAEzD,MAAa,sBAA0C,UAAuB;CAC5E,MAAM,EAAE,GAAG,SAAS,eAAe;CACnC,MAAM,CAAC,YAAY,qBAAqB,eACtC,cACA,mBACF;CACA,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,CAAC,UAAU,eAAe,SAA6B,IAAI;CACjE,MAAM,OAAO,QAAQ,QAAQ;CAE7B,MAAM,cAAc,UAAyC;EAC3D,YAAY,MAAM,aAAa;CACjC;CAEA,MAAM,oBAA0B;EAC9B,YAAY,IAAI;CAClB;CAEA,MAAM,gBAAgB,aAA2B;EAC/C,cAAc,cAAc,QAAQ;EACpC,YAAY,IAAI;CAClB;CAEA,MAAM,iCACJ,UACS;EACT,cAAc,qBAAqB,MAAM,OAAO,OAAO;CACzD;CAEA,OACE,qBAACA,aAAD;EAAW,GAAI;YAAf;GACE,oBAACC,QAAD,EAAA,UACE,qBAAC,mBAAD;IACE,SAAS;IACT,eAAA;IACA,iBAAc;IACd,iBAAe;cAJjB,CAME,oBAAC,kBAAD,EAAA,UAAmB,EAAE,sBAAsB,EAAoB,CAAA,GAC/D,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,kBAAD,EAAA,UACG,eAAe,YAAY,KAAK,UAAU,MAAM,EACjC,CAAA,GAClB,oBAAC,uBAAD,EACE,IAAI;KAAE,UAAU;KAAI,QAAQ;KAAQ,WAAW;IAAM,EACtD,CAAA,CACU,EAAA,CAAA,CACI;MACf,CAAA;GACN,oBAAC,MAAD;IACY;IACJ;IACN,SAAS;IACT,cAAc;KAAE,UAAU;KAAU,YAAY;IAAQ;IACxD,iBAAiB;KAAE,UAAU;KAAO,YAAY;IAAQ;IACxD,WAAW,EACT,OAAO,EACL,KAAK,WAAW;KACd,QAAQ,aAAa,MAAM,KAAK,QAAQ,KAAK;KAC7C,WAAW;KACX,GAAG,MAAM,YAAY,QAAQ,EAC3B,aAAa,MAAM,KAAK,QAAQ,KAAK,KACvC,CAAC;IACH,GACF,EACF;cAEC,UAAU,KAAK,aACd,qBAAC,UAAD;KAEE,eAAe,aAAa,QAAQ;KACpC,KAAK,WAAW;MACd,gBAAgB;MAChB,KAAK;MACL,UAAU;MACV,YAAY;MACZ,YAAY;MACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;KACjC;eAVF,CAYG,eAAe,UAAU,KAAK,UAAU,MAAM,GAC9C,aAAa,aACZ,oBAAC,OAAD;MAAO,OAAM;MAAU,UAAS;KAAS,CAAA,IACvC,IACI;OAfH,QAeG,CACX;GACG,CAAA;GACN,oBAACA,QAAD,EAAA,UACE,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,aAAD,EAAA,UAAc,EAAE,8BAA8B,EAAe,CAAA,GAC7D,oBAACC,UAAD;IACE,SAAS;IACT,UAAU;IACV,cAAY,EAAE,8BAA8B;GAC7C,CAAA,CACU,EAAA,CAAA,EACT,CAAA;EACG;;AAEf"}
@@ -0,0 +1,52 @@
1
+ import { Box, ButtonBase, Typography, styled } from "@mui/material";
2
+ //#region src/components/LimitOrderSettings/LimitOrderSettings.style.tsx
3
+ const Container$1 = styled(Box)(({ theme }) => ({
4
+ display: "flex",
5
+ flexDirection: "column",
6
+ gap: theme.spacing(1)
7
+ }));
8
+ const SettingsRow = styled(Box)(({ theme }) => ({
9
+ display: "flex",
10
+ justifyContent: "space-between",
11
+ alignItems: "center",
12
+ gap: theme.spacing(2),
13
+ padding: theme.spacing(1.5, 2)
14
+ }));
15
+ const ToggleLabel = styled(Box)(({ theme }) => ({
16
+ fontSize: 14,
17
+ fontWeight: 700,
18
+ lineHeight: 1,
19
+ color: theme.vars.palette.text.primary,
20
+ flex: "1 0 0",
21
+ minWidth: 0
22
+ }));
23
+ const ExpiryValue = styled(Box)(({ theme }) => ({
24
+ display: "flex",
25
+ alignItems: "center",
26
+ gap: theme.spacing(.5),
27
+ color: theme.vars.palette.text.secondary,
28
+ height: 14
29
+ }));
30
+ const SettingItemButton = styled(ButtonBase)(({ theme }) => ({
31
+ display: "flex",
32
+ justifyContent: "space-between",
33
+ alignItems: "center",
34
+ width: "100%",
35
+ padding: theme.spacing(2),
36
+ borderRadius: theme.vars.shape.borderRadius
37
+ }));
38
+ const SettingItemTitle = styled(Typography)(({ theme }) => ({
39
+ fontSize: 14,
40
+ fontWeight: 700,
41
+ color: theme.vars.palette.text.primary,
42
+ lineHeight: 1
43
+ }));
44
+ const SettingItemValue = styled(Typography)(({ theme }) => ({
45
+ fontSize: 14,
46
+ fontWeight: 700,
47
+ color: theme.vars.palette.text.primary
48
+ }));
49
+ //#endregion
50
+ export { Container$1 as Container, ExpiryValue, SettingItemButton, SettingItemTitle, SettingItemValue, SettingsRow, ToggleLabel };
51
+
52
+ //# sourceMappingURL=LimitOrderSettings.style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitOrderSettings.style.js","names":["Container"],"sources":["../../../../src/components/LimitOrderSettings/LimitOrderSettings.style.tsx"],"sourcesContent":["import { Box, ButtonBase, styled, Typography } from '@mui/material'\nimport type React from 'react'\n\nexport const Container: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n}))\n\nexport const SettingsRow: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: theme.spacing(2),\n padding: theme.spacing(1.5, 2),\n}))\n\nexport const ToggleLabel: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n fontSize: 14,\n fontWeight: 700,\n lineHeight: 1,\n color: theme.vars.palette.text.primary,\n flex: '1 0 0',\n minWidth: 0,\n}))\n\nexport const ExpiryValue: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(0.5),\n color: theme.vars.palette.text.secondary,\n height: 14,\n}))\n\nexport const SettingItemButton: React.FC<\n React.ComponentProps<typeof ButtonBase>\n> = styled(ButtonBase)(({ theme }) => ({\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n width: '100%',\n padding: theme.spacing(2),\n borderRadius: theme.vars.shape.borderRadius,\n}))\n\nexport const SettingItemTitle: React.FC<\n React.ComponentProps<typeof Typography>\n> = styled(Typography)(({ theme }) => ({\n fontSize: 14,\n fontWeight: 700,\n color: theme.vars.palette.text.primary,\n lineHeight: 1,\n}))\n\nexport const SettingItemValue: React.FC<\n React.ComponentProps<typeof Typography>\n> = styled(Typography)(({ theme }) => ({\n fontSize: 14,\n fontWeight: 700,\n color: theme.vars.palette.text.primary,\n}))\n"],"mappings":";;AAGA,MAAaA,cAAwD,OACnE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,SAAS;CACT,eAAe;CACf,KAAK,MAAM,QAAQ,CAAC;AACtB,EAAE;AAEF,MAAa,cAA0D,OACrE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,SAAS;CACT,gBAAgB;CAChB,YAAY;CACZ,KAAK,MAAM,QAAQ,CAAC;CACpB,SAAS,MAAM,QAAQ,KAAK,CAAC;AAC/B,EAAE;AAEF,MAAa,cAA0D,OACrE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,MAAM;CACN,UAAU;AACZ,EAAE;AAEF,MAAa,cAA0D,OACrE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,SAAS;CACT,YAAY;CACZ,KAAK,MAAM,QAAQ,EAAG;CACtB,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,QAAQ;AACV,EAAE;AAEF,MAAa,oBAET,OAAO,UAAU,CAAC,EAAE,EAAE,aAAa;CACrC,SAAS;CACT,gBAAgB;CAChB,YAAY;CACZ,OAAO;CACP,SAAS,MAAM,QAAQ,CAAC;CACxB,cAAc,MAAM,KAAK,MAAM;AACjC,EAAE;AAEF,MAAa,mBAET,OAAO,UAAU,CAAC,EAAE,EAAE,aAAa;CACrC,UAAU;CACV,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,YAAY;AACd,EAAE;AAEF,MAAa,mBAET,OAAO,UAAU,CAAC,EAAE,EAAE,aAAa;CACrC,UAAU;CACV,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;AACjC,EAAE"}
@@ -0,0 +1,115 @@
1
+ import { useFieldActions } from "../../stores/form/useFieldActions.js";
2
+ import { formatInputAmount } from "../../utils/format.js";
3
+ import { FormKeyHelper } from "../../stores/form/types.js";
4
+ import { useFieldValues } from "../../stores/form/useFieldValues.js";
5
+ import { useToken } from "../../hooks/useToken.js";
6
+ import { useRoutes } from "../../hooks/useRoutes.js";
7
+ import { CardTitle } from "../Card/CardTitle.js";
8
+ import { useLimitMarketRate } from "../../hooks/useLimitMarketRate.js";
9
+ import { applyPriceOffset, invertPrice } from "../../utils/limitOrder.js";
10
+ import { useLinkedLimitFields } from "../../hooks/useLinkedLimitFields.js";
11
+ import { AmountCard, CardBodyRow, CardHeaderRow, LargeInput } from "../AmountInputCard/AmountInputCard.style.js";
12
+ import { InvertChip } from "./LimitPriceCard.style.js";
13
+ import { LimitPricePresets } from "./LimitPricePresets.js";
14
+ import { useEffect, useRef, useState } from "react";
15
+ import { Skeleton } from "@mui/material";
16
+ import { jsx, jsxs } from "react/jsx-runtime";
17
+ import { useTranslation } from "react-i18next";
18
+ import SwapHorizIcon from "@mui/icons-material/SwapHoriz";
19
+ //#region src/components/LimitPriceCard/LimitPriceCard.tsx
20
+ const cleanDisplay = (value) => value ? formatInputAmount(value, 8) : "";
21
+ const LimitPriceCard = (props) => {
22
+ const { t } = useTranslation();
23
+ const isEditingRef = useRef(false);
24
+ const [inputValue, setInputValue] = useState("");
25
+ const [fromChainId, fromTokenAddress, toChainId, toTokenAddress, priceInverted] = useFieldValues(FormKeyHelper.getChainKey("from"), FormKeyHelper.getTokenKey("from"), FormKeyHelper.getChainKey("to"), FormKeyHelper.getTokenKey("to"), "priceInverted");
26
+ const { token: fromToken } = useToken(fromChainId, fromTokenAddress);
27
+ const { token: toToken } = useToken(toChainId, toTokenAddress);
28
+ const { isFetching } = useRoutes();
29
+ const { limitPrice, setLimitPrice } = useLinkedLimitFields();
30
+ const { setFieldValue } = useFieldActions();
31
+ const hasTokens = Boolean(fromToken && toToken);
32
+ const showSkeleton = isFetching && !limitPrice;
33
+ const leadToken = priceInverted ? toToken : fromToken;
34
+ const unitToken = priceInverted ? fromToken : toToken;
35
+ const marketCanonical = useLimitMarketRate();
36
+ const displayPrice = priceInverted ? invertPrice(limitPrice) : limitPrice;
37
+ useEffect(() => {
38
+ setFieldValue("toAmount", "", {
39
+ isDirty: false,
40
+ isTouched: false
41
+ });
42
+ setFieldValue("selectedRouteId", void 0);
43
+ }, [
44
+ fromChainId,
45
+ fromTokenAddress,
46
+ toChainId,
47
+ toTokenAddress
48
+ ]);
49
+ useEffect(() => {
50
+ if (!isEditingRef.current) setInputValue(cleanDisplay(displayPrice));
51
+ }, [displayPrice]);
52
+ const handleChange = (event) => {
53
+ isEditingRef.current = true;
54
+ const formatted = formatInputAmount(event.target.value, 18, true);
55
+ setInputValue(formatted);
56
+ const numeric = Number(formatted);
57
+ if (!formatted || Number.isNaN(numeric) || numeric <= 0) {
58
+ setLimitPrice("");
59
+ return;
60
+ }
61
+ const canonical = priceInverted ? 1 / numeric : numeric;
62
+ setLimitPrice(String(canonical));
63
+ };
64
+ const handleBlur = () => {
65
+ isEditingRef.current = false;
66
+ setInputValue(cleanDisplay(displayPrice));
67
+ };
68
+ const handleInvert = () => {
69
+ isEditingRef.current = false;
70
+ setFieldValue("priceInverted", !priceInverted);
71
+ };
72
+ const handlePreset = (pct) => {
73
+ if (marketCanonical === void 0) return;
74
+ isEditingRef.current = false;
75
+ setLimitPrice(applyPriceOffset(String(marketCanonical), pct));
76
+ };
77
+ const label = hasTokens ? t("limitOrder.priceLabel", { symbol: leadToken?.symbol }) : t("limitOrder.price");
78
+ return /* @__PURE__ */ jsxs(AmountCard, {
79
+ ...props,
80
+ mask: false,
81
+ children: [
82
+ /* @__PURE__ */ jsxs(CardHeaderRow, { children: [/* @__PURE__ */ jsx(CardTitle, {
83
+ sx: { padding: 0 },
84
+ children: label
85
+ }), hasTokens ? /* @__PURE__ */ jsxs(InvertChip, {
86
+ onClick: handleInvert,
87
+ "aria-label": "invert price",
88
+ children: [unitToken?.symbol, /* @__PURE__ */ jsx(SwapHorizIcon, { sx: { fontSize: 16 } })]
89
+ }) : null] }),
90
+ /* @__PURE__ */ jsx(CardBodyRow, { children: showSkeleton ? /* @__PURE__ */ jsx(Skeleton, {
91
+ variant: "rounded",
92
+ height: 32,
93
+ sx: { flex: 1 }
94
+ }) : /* @__PURE__ */ jsx(LargeInput, {
95
+ size: "small",
96
+ autoComplete: "off",
97
+ placeholder: "0",
98
+ inputProps: { inputMode: "decimal" },
99
+ onChange: handleChange,
100
+ onBlur: handleBlur,
101
+ value: inputValue,
102
+ name: "limitPrice",
103
+ disabled: !hasTokens
104
+ }) }),
105
+ /* @__PURE__ */ jsx(LimitPricePresets, {
106
+ onSelect: handlePreset,
107
+ disabled: !hasTokens || marketCanonical === void 0
108
+ })
109
+ ]
110
+ });
111
+ };
112
+ //#endregion
113
+ export { LimitPriceCard };
114
+
115
+ //# sourceMappingURL=LimitPriceCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitPriceCard.js","names":[],"sources":["../../../../src/components/LimitPriceCard/LimitPriceCard.tsx"],"sourcesContent":["import SwapHorizIcon from '@mui/icons-material/SwapHoriz'\nimport type { CardProps } from '@mui/material'\nimport { Skeleton } from '@mui/material'\nimport { type ChangeEvent, type JSX, useEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useLimitMarketRate } from '../../hooks/useLimitMarketRate.js'\nimport { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js'\nimport { useRoutes } from '../../hooks/useRoutes.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { formatInputAmount } from '../../utils/format.js'\nimport { applyPriceOffset, invertPrice } from '../../utils/limitOrder.js'\nimport {\n AmountCard,\n amountHeight,\n CardBodyRow,\n CardHeaderRow,\n LargeInput,\n} from '../AmountInputCard/AmountInputCard.style.js'\nimport { CardTitle } from '../Card/CardTitle.js'\nimport { InvertChip } from './LimitPriceCard.style.js'\nimport { LimitPricePresets } from './LimitPricePresets.js'\n\nconst cleanDisplay = (value: string): string =>\n value ? formatInputAmount(value, 8) : ''\n\nexport const LimitPriceCard: React.FC<CardProps> = (props): JSX.Element => {\n const { t } = useTranslation()\n const isEditingRef = useRef(false)\n const [inputValue, setInputValue] = useState('')\n\n const [\n fromChainId,\n fromTokenAddress,\n toChainId,\n toTokenAddress,\n priceInverted,\n ] = useFieldValues(\n FormKeyHelper.getChainKey('from'),\n FormKeyHelper.getTokenKey('from'),\n FormKeyHelper.getChainKey('to'),\n FormKeyHelper.getTokenKey('to'),\n 'priceInverted'\n )\n const { token: fromToken } = useToken(fromChainId, fromTokenAddress)\n const { token: toToken } = useToken(toChainId, toTokenAddress)\n\n const { isFetching } = useRoutes()\n\n // limitPrice is derived from the from/to amount fields, not stored.\n const { limitPrice, setLimitPrice } = useLinkedLimitFields()\n const { setFieldValue } = useFieldActions()\n\n const hasTokens = Boolean(fromToken && toToken)\n const showSkeleton = isFetching && !limitPrice\n const leadToken = priceInverted ? toToken : fromToken\n const unitToken = priceInverted ? fromToken : toToken\n\n const marketCanonical = useLimitMarketRate()\n\n // Canonical price is orientation-independent; flip only for display.\n const displayPrice = priceInverted ? invertPrice(limitPrice) : limitPrice\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: pair fields are intentional re-run triggers, not read in the body\n useEffect(() => {\n setFieldValue('toAmount', '', { isDirty: false, isTouched: false })\n setFieldValue('selectedRouteId', undefined)\n }, [fromChainId, fromTokenAddress, toChainId, toTokenAddress])\n\n // Keep the input in sync with derived/preset/invert updates, but never yank\n // the value out from under an actively-typing user.\n useEffect(() => {\n if (!isEditingRef.current) {\n setInputValue(cleanDisplay(displayPrice))\n }\n }, [displayPrice])\n\n const handleChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ): void => {\n isEditingRef.current = true\n const formatted = formatInputAmount(event.target.value, 18, true)\n setInputValue(formatted)\n const numeric = Number(formatted)\n if (!formatted || Number.isNaN(numeric) || numeric <= 0) {\n setLimitPrice('')\n return\n }\n // Canonical price is orientation-independent; un-flip the displayed value.\n const canonical = priceInverted ? 1 / numeric : numeric\n setLimitPrice(String(canonical))\n }\n\n const handleBlur = (): void => {\n isEditingRef.current = false\n setInputValue(cleanDisplay(displayPrice))\n }\n\n const handleInvert = (): void => {\n isEditingRef.current = false\n setFieldValue('priceInverted', !priceInverted)\n }\n\n // Apply a percentage offset to the canonical market rate (0 = at market).\n const handlePreset = (pct: number): void => {\n if (marketCanonical === undefined) {\n return\n }\n isEditingRef.current = false\n setLimitPrice(applyPriceOffset(String(marketCanonical), pct))\n }\n\n const label = hasTokens\n ? t('limitOrder.priceLabel', { symbol: leadToken?.symbol })\n : t('limitOrder.price')\n\n return (\n <AmountCard {...props} mask={false}>\n <CardHeaderRow>\n <CardTitle sx={{ padding: 0 }}>{label}</CardTitle>\n {hasTokens ? (\n <InvertChip onClick={handleInvert} aria-label=\"invert price\">\n {unitToken?.symbol}\n <SwapHorizIcon sx={{ fontSize: 16 }} />\n </InvertChip>\n ) : null}\n </CardHeaderRow>\n <CardBodyRow>\n {showSkeleton ? (\n <Skeleton variant=\"rounded\" height={amountHeight} sx={{ flex: 1 }} />\n ) : (\n <LargeInput\n size=\"small\"\n autoComplete=\"off\"\n placeholder=\"0\"\n inputProps={{ inputMode: 'decimal' }}\n onChange={handleChange}\n onBlur={handleBlur}\n value={inputValue}\n name=\"limitPrice\"\n disabled={!hasTokens}\n />\n )}\n </CardBodyRow>\n <LimitPricePresets\n onSelect={handlePreset}\n disabled={!hasTokens || marketCanonical === undefined}\n />\n </AmountCard>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,MAAM,gBAAgB,UACpB,QAAQ,kBAAkB,OAAO,CAAC,IAAI;AAExC,MAAa,kBAAuC,UAAuB;CACzE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,eAAe,OAAO,KAAK;CACjC,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAE/C,MAAM,CACJ,aACA,kBACA,WACA,gBACA,iBACE,eACF,cAAc,YAAY,MAAM,GAChC,cAAc,YAAY,MAAM,GAChC,cAAc,YAAY,IAAI,GAC9B,cAAc,YAAY,IAAI,GAC9B,eACF;CACA,MAAM,EAAE,OAAO,cAAc,SAAS,aAAa,gBAAgB;CACnE,MAAM,EAAE,OAAO,YAAY,SAAS,WAAW,cAAc;CAE7D,MAAM,EAAE,eAAe,UAAU;CAGjC,MAAM,EAAE,YAAY,kBAAkB,qBAAqB;CAC3D,MAAM,EAAE,kBAAkB,gBAAgB;CAE1C,MAAM,YAAY,QAAQ,aAAa,OAAO;CAC9C,MAAM,eAAe,cAAc,CAAC;CACpC,MAAM,YAAY,gBAAgB,UAAU;CAC5C,MAAM,YAAY,gBAAgB,YAAY;CAE9C,MAAM,kBAAkB,mBAAmB;CAG3C,MAAM,eAAe,gBAAgB,YAAY,UAAU,IAAI;CAG/D,gBAAgB;EACd,cAAc,YAAY,IAAI;GAAE,SAAS;GAAO,WAAW;EAAM,CAAC;EAClE,cAAc,mBAAmB,KAAA,CAAS;CAC5C,GAAG;EAAC;EAAa;EAAkB;EAAW;CAAc,CAAC;CAI7D,gBAAgB;EACd,IAAI,CAAC,aAAa,SAChB,cAAc,aAAa,YAAY,CAAC;CAE5C,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,gBACJ,UACS;EACT,aAAa,UAAU;EACvB,MAAM,YAAY,kBAAkB,MAAM,OAAO,OAAO,IAAI,IAAI;EAChE,cAAc,SAAS;EACvB,MAAM,UAAU,OAAO,SAAS;EAChC,IAAI,CAAC,aAAa,OAAO,MAAM,OAAO,KAAK,WAAW,GAAG;GACvD,cAAc,EAAE;GAChB;EACF;EAEA,MAAM,YAAY,gBAAgB,IAAI,UAAU;EAChD,cAAc,OAAO,SAAS,CAAC;CACjC;CAEA,MAAM,mBAAyB;EAC7B,aAAa,UAAU;EACvB,cAAc,aAAa,YAAY,CAAC;CAC1C;CAEA,MAAM,qBAA2B;EAC/B,aAAa,UAAU;EACvB,cAAc,iBAAiB,CAAC,aAAa;CAC/C;CAGA,MAAM,gBAAgB,QAAsB;EAC1C,IAAI,oBAAoB,KAAA,GACtB;EAEF,aAAa,UAAU;EACvB,cAAc,iBAAiB,OAAO,eAAe,GAAG,GAAG,CAAC;CAC9D;CAEA,MAAM,QAAQ,YACV,EAAE,yBAAyB,EAAE,QAAQ,WAAW,OAAO,CAAC,IACxD,EAAE,kBAAkB;CAExB,OACE,qBAAC,YAAD;EAAY,GAAI;EAAO,MAAM;YAA7B;GACE,qBAAC,eAAD,EAAA,UAAA,CACE,oBAAC,WAAD;IAAW,IAAI,EAAE,SAAS,EAAE;cAAI;GAAiB,CAAA,GAChD,YACC,qBAAC,YAAD;IAAY,SAAS;IAAc,cAAW;cAA9C,CACG,WAAW,QACZ,oBAAC,eAAD,EAAe,IAAI,EAAE,UAAU,GAAG,EAAI,CAAA,CAC5B;QACV,IACS,EAAA,CAAA;GACf,oBAAC,aAAD,EAAA,UACG,eACC,oBAAC,UAAD;IAAU,SAAQ;IAAU,QAAA;IAAsB,IAAI,EAAE,MAAM,EAAE;GAAI,CAAA,IAEpE,oBAAC,YAAD;IACE,MAAK;IACL,cAAa;IACb,aAAY;IACZ,YAAY,EAAE,WAAW,UAAU;IACnC,UAAU;IACV,QAAQ;IACR,OAAO;IACP,MAAK;IACL,UAAU,CAAC;GACZ,CAAA,EAEQ,CAAA;GACb,oBAAC,mBAAD;IACE,UAAU;IACV,UAAU,CAAC,aAAa,oBAAoB,KAAA;GAC7C,CAAA;EACS;;AAEhB"}
@@ -0,0 +1,89 @@
1
+ import { Box, Button, ButtonBase, Typography, styled } from "@mui/material";
2
+ //#region src/components/LimitPriceCard/LimitPriceCard.style.tsx
3
+ /**
4
+ * Quick-set preset pill. Mirrors the percentage chips' pill look but is always
5
+ * visible (no reveal-on-hover), since presets are the card's primary control.
6
+ */
7
+ const PriceChip = styled(Button)(({ theme }) => ({
8
+ minWidth: 0,
9
+ padding: theme.spacing(.5, 1.5),
10
+ fontSize: 12,
11
+ fontWeight: 700,
12
+ lineHeight: 1.3334,
13
+ backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,
14
+ color: theme.vars.palette.text.primary,
15
+ transition: "background-color 200ms ease",
16
+ "&:hover": { backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)` }
17
+ }));
18
+ /**
19
+ * Editable variant of the preset pill: looks identical to {@link PriceChip} but
20
+ * wraps an inline input so the user can type an arbitrary percentage premium
21
+ * (`+__%`) instead of picking a fixed preset.
22
+ */
23
+ const EditablePriceChip = styled(Box)(({ theme }) => ({
24
+ display: "inline-flex",
25
+ alignItems: "center",
26
+ minWidth: 0,
27
+ padding: theme.spacing(.5, 1.5),
28
+ borderRadius: theme.vars.shape.borderRadius,
29
+ fontSize: 12,
30
+ fontWeight: 700,
31
+ lineHeight: 1.3334,
32
+ color: theme.vars.palette.text.primary,
33
+ backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,
34
+ transition: "background-color 200ms ease",
35
+ cursor: "text",
36
+ "&:hover, &:focus-within": { backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)` },
37
+ "&[aria-disabled=\"true\"]": {
38
+ opacity: .5,
39
+ pointerEvents: "none"
40
+ }
41
+ }));
42
+ /** Bare input inside {@link EditablePriceChip}; inherits the pill's typography. */
43
+ const PriceChipInput = styled("input")(({ theme }) => ({
44
+ appearance: "none",
45
+ border: "none",
46
+ outline: "none",
47
+ background: "transparent",
48
+ padding: 0,
49
+ margin: 0,
50
+ font: "inherit",
51
+ color: "inherit",
52
+ textAlign: "right",
53
+ minWidth: "1ch",
54
+ "&::placeholder": {
55
+ color: theme.vars.palette.text.secondary,
56
+ opacity: 1
57
+ }
58
+ }));
59
+ styled(Typography)(({ theme }) => ({
60
+ fontSize: 18,
61
+ fontWeight: 600,
62
+ lineHeight: 1.4,
63
+ whiteSpace: "nowrap",
64
+ color: theme.vars.palette.text.primary
65
+ }));
66
+ /**
67
+ * Invert affordance anchored to the far right of the lead row. Styled as a
68
+ * pill to mirror the percentage chips, but always visible (no reveal-on-hover).
69
+ */
70
+ const InvertChip = styled(ButtonBase)(({ theme }) => ({
71
+ display: "flex",
72
+ alignItems: "center",
73
+ justifyContent: "center",
74
+ gap: theme.spacing(.5),
75
+ minWidth: 0,
76
+ padding: theme.spacing(.5, 1.5),
77
+ borderRadius: "9999px",
78
+ fontSize: 12,
79
+ fontWeight: 700,
80
+ lineHeight: 1.3334,
81
+ color: theme.vars.palette.text.primary,
82
+ backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,
83
+ transition: "background-color 200ms ease",
84
+ "&:hover": { backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)` }
85
+ }));
86
+ //#endregion
87
+ export { EditablePriceChip, InvertChip, PriceChip, PriceChipInput };
88
+
89
+ //# sourceMappingURL=LimitPriceCard.style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitPriceCard.style.js","names":[],"sources":["../../../../src/components/LimitPriceCard/LimitPriceCard.style.tsx"],"sourcesContent":["import { Box, Button, ButtonBase, styled, Typography } from '@mui/material'\nimport type React from 'react'\n\n/**\n * Quick-set preset pill. Mirrors the percentage chips' pill look but is always\n * visible (no reveal-on-hover), since presets are the card's primary control.\n */\nexport const PriceChip: React.FC<React.ComponentProps<typeof Button>> = styled(\n Button\n)(({ theme }) => ({\n minWidth: 0,\n padding: theme.spacing(0.5, 1.5),\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.3334,\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,\n color: theme.vars.palette.text.primary,\n transition: 'background-color 200ms ease',\n '&:hover': {\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,\n },\n}))\n\n/**\n * Editable variant of the preset pill: looks identical to {@link PriceChip} but\n * wraps an inline input so the user can type an arbitrary percentage premium\n * (`+__%`) instead of picking a fixed preset.\n */\nexport const EditablePriceChip: React.FC<React.ComponentProps<typeof Box>> =\n styled(Box)(({ theme }) => ({\n display: 'inline-flex',\n alignItems: 'center',\n minWidth: 0,\n padding: theme.spacing(0.5, 1.5),\n borderRadius: theme.vars.shape.borderRadius,\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.3334,\n color: theme.vars.palette.text.primary,\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,\n transition: 'background-color 200ms ease',\n cursor: 'text',\n '&:hover, &:focus-within': {\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,\n },\n '&[aria-disabled=\"true\"]': {\n opacity: 0.5,\n pointerEvents: 'none',\n },\n }))\n\n/** Bare input inside {@link EditablePriceChip}; inherits the pill's typography. */\nexport const PriceChipInput: React.FC<React.ComponentProps<'input'>> = styled(\n 'input'\n)(({ theme }) => ({\n appearance: 'none',\n border: 'none',\n outline: 'none',\n background: 'transparent',\n padding: 0,\n margin: 0,\n font: 'inherit',\n color: 'inherit',\n textAlign: 'right',\n minWidth: '1ch',\n '&::placeholder': {\n color: theme.vars.palette.text.secondary,\n opacity: 1,\n },\n}))\n\nexport const UnitSymbol: React.FC<React.ComponentProps<typeof Typography>> =\n styled(Typography)(({ theme }) => ({\n fontSize: 18,\n fontWeight: 600,\n lineHeight: 1.4,\n whiteSpace: 'nowrap',\n color: theme.vars.palette.text.primary,\n }))\n\n/**\n * Invert affordance anchored to the far right of the lead row. Styled as a\n * pill to mirror the percentage chips, but always visible (no reveal-on-hover).\n */\nexport const InvertChip: React.FC<React.ComponentProps<typeof ButtonBase>> =\n styled(ButtonBase)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: theme.spacing(0.5),\n minWidth: 0,\n padding: theme.spacing(0.5, 1.5),\n borderRadius: '9999px',\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.3334,\n color: theme.vars.palette.text.primary,\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,\n transition: 'background-color 200ms ease',\n '&:hover': {\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,\n },\n }))\n"],"mappings":";;;;;;AAOA,MAAa,YAA2D,OACtE,MACF,CAAC,EAAE,EAAE,aAAa;CAChB,UAAU;CACV,SAAS,MAAM,QAAQ,IAAK,GAAG;CAC/B,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa;CAC9E,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,YAAY;CACZ,WAAW,EACT,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa,mBAChF;AACF,EAAE;;;;;;AAOF,MAAa,oBACX,OAAO,GAAG,CAAC,EAAE,EAAE,aAAa;CAC1B,SAAS;CACT,YAAY;CACZ,UAAU;CACV,SAAS,MAAM,QAAQ,IAAK,GAAG;CAC/B,cAAc,MAAM,KAAK,MAAM;CAC/B,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa;CAC9E,YAAY;CACZ,QAAQ;CACR,2BAA2B,EACzB,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa,mBAChF;CACA,6BAA2B;EACzB,SAAS;EACT,eAAe;CACjB;AACF,EAAE;;AAGJ,MAAa,iBAA0D,OACrE,OACF,CAAC,EAAE,EAAE,aAAa;CAChB,YAAY;CACZ,QAAQ;CACR,SAAS;CACT,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,MAAM;CACN,OAAO;CACP,WAAW;CACX,UAAU;CACV,kBAAkB;EAChB,OAAO,MAAM,KAAK,QAAQ,KAAK;EAC/B,SAAS;CACX;AACF,EAAE;AAGA,OAAO,UAAU,CAAC,EAAE,EAAE,aAAa;CACjC,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;AACjC,EAAE;;;;;AAMJ,MAAa,aACX,OAAO,UAAU,CAAC,EAAE,EAAE,aAAa;CACjC,SAAS;CACT,YAAY;CACZ,gBAAgB;CAChB,KAAK,MAAM,QAAQ,EAAG;CACtB,UAAU;CACV,SAAS,MAAM,QAAQ,IAAK,GAAG;CAC/B,cAAc;CACd,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa;CAC9E,YAAY;CACZ,WAAW,EACT,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa,mBAChF;AACF,EAAE"}
@@ -0,0 +1,91 @@
1
+ import { EditablePriceChip, PriceChip, PriceChipInput } from "./LimitPriceCard.style.js";
2
+ import { ChipContainer } from "../AmountInputCard/PercentageChips.style.js";
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { useTranslation } from "react-i18next";
6
+ //#region src/components/LimitPriceCard/LimitPricePresets.tsx
7
+ /** Quick-set presets, as percentage offsets from market (0 = at market). */
8
+ const PRESETS = [
9
+ 0,
10
+ 1,
11
+ 5,
12
+ 10
13
+ ];
14
+ /**
15
+ * Row of quick-set price controls: fixed percentage presets plus a free-form
16
+ * "custom %" pill that collapses to a button until engaged. Owns its own
17
+ * custom-input state so the card only deals with applying an offset.
18
+ */
19
+ const LimitPricePresets = ({ onSelect, disabled }) => {
20
+ const { t } = useTranslation();
21
+ const customInputRef = useRef(null);
22
+ const [customPct, setCustomPct] = useState("");
23
+ const [customFocused, setCustomFocused] = useState(false);
24
+ useEffect(() => {
25
+ if (customFocused) customInputRef.current?.focus();
26
+ }, [customFocused]);
27
+ const handlePresetClick = (pct) => {
28
+ setCustomPct("");
29
+ setCustomFocused(false);
30
+ onSelect(pct);
31
+ };
32
+ const handleCustomChange = (event) => {
33
+ const raw = event.target.value;
34
+ if (raw && !/^[+-]?\d*\.?\d*$/.test(raw)) return;
35
+ setCustomPct(raw);
36
+ const numeric = Number(raw);
37
+ if (raw === "" || Number.isNaN(numeric)) return;
38
+ onSelect(numeric);
39
+ };
40
+ const handleCustomKeyDown = (event) => {
41
+ if (event.key === "Enter") event.currentTarget.blur();
42
+ };
43
+ const handleCustomBlur = () => {
44
+ setCustomFocused(false);
45
+ setCustomPct((prev) => {
46
+ if (!prev || prev.startsWith("+") || prev.startsWith("-")) return prev;
47
+ return Number.isNaN(Number(prev)) ? prev : `+${prev}`;
48
+ });
49
+ };
50
+ const showCustomLabel = customPct === "" && !customFocused;
51
+ return /* @__PURE__ */ jsxs(ChipContainer, {
52
+ sx: {
53
+ marginTop: .5,
54
+ flexWrap: "wrap"
55
+ },
56
+ children: [PRESETS.map((pct) => /* @__PURE__ */ jsx(PriceChip, {
57
+ onClick: () => handlePresetClick(pct),
58
+ children: pct === 0 ? t("limitOrder.market") : `+${pct}%`
59
+ }, pct)), showCustomLabel ? /* @__PURE__ */ jsx(PriceChip, {
60
+ disabled,
61
+ onClick: () => setCustomFocused(true),
62
+ children: t("limitOrder.custom")
63
+ }) : /* @__PURE__ */ jsxs(EditablePriceChip, {
64
+ "aria-disabled": disabled,
65
+ onClick: (event) => {
66
+ if (disabled) return;
67
+ event.currentTarget.querySelector("input")?.focus();
68
+ const numeric = Number(customPct);
69
+ if (customPct && !Number.isNaN(numeric)) onSelect(numeric);
70
+ },
71
+ children: [/* @__PURE__ */ jsx(PriceChipInput, {
72
+ ref: customInputRef,
73
+ inputMode: "decimal",
74
+ autoComplete: "off",
75
+ placeholder: "0",
76
+ "aria-label": t("limitOrder.custom"),
77
+ value: customPct,
78
+ onChange: handleCustomChange,
79
+ onKeyDown: handleCustomKeyDown,
80
+ onFocus: () => setCustomFocused(true),
81
+ onBlur: handleCustomBlur,
82
+ disabled,
83
+ style: { width: `${Math.max(customPct.length, 1)}ch` }
84
+ }), "%"]
85
+ })]
86
+ });
87
+ };
88
+ //#endregion
89
+ export { LimitPricePresets };
90
+
91
+ //# sourceMappingURL=LimitPricePresets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitPricePresets.js","names":[],"sources":["../../../../src/components/LimitPriceCard/LimitPricePresets.tsx"],"sourcesContent":["import { type ChangeEvent, type JSX, useEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { ChipContainer } from '../AmountInputCard/PercentageChips.style.js'\nimport {\n EditablePriceChip,\n PriceChip,\n PriceChipInput,\n} from './LimitPriceCard.style.js'\n\n/** Quick-set presets, as percentage offsets from market (0 = at market). */\nconst PRESETS = [0, 1, 5, 10] as const\n\ninterface LimitPricePresetsProps {\n /** Apply a percentage offset from the market rate (0 = at market). */\n onSelect: (pct: number) => void\n /** Disables the free-form custom pill (no tokens / no market rate yet). */\n disabled: boolean\n}\n\n/**\n * Row of quick-set price controls: fixed percentage presets plus a free-form\n * \"custom %\" pill that collapses to a button until engaged. Owns its own\n * custom-input state so the card only deals with applying an offset.\n */\nexport const LimitPricePresets = ({\n onSelect,\n disabled,\n}: LimitPricePresetsProps): JSX.Element => {\n const { t } = useTranslation()\n const customInputRef = useRef<HTMLInputElement>(null)\n const [customPct, setCustomPct] = useState('')\n const [customFocused, setCustomFocused] = useState(false)\n\n // The custom pill renders as a plain button until engaged; when it flips into\n // edit mode (focused), move the caret into the freshly-mounted input.\n useEffect(() => {\n if (customFocused) {\n customInputRef.current?.focus()\n }\n }, [customFocused])\n\n // Picking a fixed preset clears any custom value so the custom pill collapses\n // back to its \"Custom\" button instead of showing a stale, no-longer-applied %.\n const handlePresetClick = (pct: number): void => {\n setCustomPct('')\n setCustomFocused(false)\n onSelect(pct)\n }\n\n // Free-form offset pill: apply the typed percentage live so the price input\n // tracks the offset as the user types. Accepts an optional leading +/- sign\n // so the price can be set above (premium) or below (discount) market.\n const handleCustomChange = (event: ChangeEvent<HTMLInputElement>): void => {\n const raw = event.target.value\n if (raw && !/^[+-]?\\d*\\.?\\d*$/.test(raw)) {\n return\n }\n setCustomPct(raw)\n const numeric = Number(raw)\n // Bare '', '+', '-', '.' etc. aren't applicable numbers yet — Number() maps\n // the signs/dot to NaN, and '' to 0, so guard both.\n if (raw === '' || Number.isNaN(numeric)) {\n return\n }\n onSelect(numeric)\n }\n\n const handleCustomKeyDown = (\n event: React.KeyboardEvent<HTMLInputElement>\n ): void => {\n if (event.key === 'Enter') {\n event.currentTarget.blur()\n }\n }\n\n // On blur, surface an explicit sign: a bare positive entry like \"10\" reads as\n // \"+10\" so the direction (above/below market) is unambiguous once collapsed.\n const handleCustomBlur = (): void => {\n setCustomFocused(false)\n setCustomPct((prev) => {\n if (!prev || prev.startsWith('+') || prev.startsWith('-')) {\n return prev\n }\n return Number.isNaN(Number(prev)) ? prev : `+${prev}`\n })\n }\n\n // Collapse to a plain \"Custom\" label only while empty and unfocused; once the\n // user engages (focus) or has typed a value, reveal the `+__%` affixes.\n const showCustomLabel = customPct === '' && !customFocused\n\n return (\n <ChipContainer sx={{ marginTop: 0.5, flexWrap: 'wrap' }}>\n {PRESETS.map((pct) => (\n <PriceChip key={pct} onClick={() => handlePresetClick(pct)}>\n {pct === 0 ? t('limitOrder.market') : `+${pct}%`}\n </PriceChip>\n ))}\n {showCustomLabel ? (\n <PriceChip disabled={disabled} onClick={() => setCustomFocused(true)}>\n {t('limitOrder.custom')}\n </PriceChip>\n ) : (\n <EditablePriceChip\n aria-disabled={disabled}\n onClick={(event) => {\n // `aria-disabled` only announces the state; enforce it so a\n // programmatic click can't apply an offset while disabled.\n if (disabled) {\n return\n }\n const input = event.currentTarget.querySelector('input')\n input?.focus()\n const numeric = Number(customPct)\n if (customPct && !Number.isNaN(numeric)) {\n onSelect(numeric)\n }\n }}\n >\n <PriceChipInput\n ref={customInputRef}\n inputMode=\"decimal\"\n autoComplete=\"off\"\n placeholder=\"0\"\n aria-label={t('limitOrder.custom')}\n value={customPct}\n onChange={handleCustomChange}\n onKeyDown={handleCustomKeyDown}\n onFocus={() => setCustomFocused(true)}\n onBlur={handleCustomBlur}\n disabled={disabled}\n style={{ width: `${Math.max(customPct.length, 1)}ch` }}\n />\n %\n </EditablePriceChip>\n )}\n </ChipContainer>\n )\n}\n"],"mappings":";;;;;;;AAUA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;AAAE;;;;;;AAc5B,MAAa,qBAAqB,EAChC,UACA,eACyC;CACzC,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,iBAAiB,OAAyB,IAAI;CACpD,MAAM,CAAC,WAAW,gBAAgB,SAAS,EAAE;CAC7C,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CAIxD,gBAAgB;EACd,IAAI,eACF,eAAe,SAAS,MAAM;CAElC,GAAG,CAAC,aAAa,CAAC;CAIlB,MAAM,qBAAqB,QAAsB;EAC/C,aAAa,EAAE;EACf,iBAAiB,KAAK;EACtB,SAAS,GAAG;CACd;CAKA,MAAM,sBAAsB,UAA+C;EACzE,MAAM,MAAM,MAAM,OAAO;EACzB,IAAI,OAAO,CAAC,mBAAmB,KAAK,GAAG,GACrC;EAEF,aAAa,GAAG;EAChB,MAAM,UAAU,OAAO,GAAG;EAG1B,IAAI,QAAQ,MAAM,OAAO,MAAM,OAAO,GACpC;EAEF,SAAS,OAAO;CAClB;CAEA,MAAM,uBACJ,UACS;EACT,IAAI,MAAM,QAAQ,SAChB,MAAM,cAAc,KAAK;CAE7B;CAIA,MAAM,yBAA+B;EACnC,iBAAiB,KAAK;EACtB,cAAc,SAAS;GACrB,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GACtD,OAAO;GAET,OAAO,OAAO,MAAM,OAAO,IAAI,CAAC,IAAI,OAAO,IAAI;EACjD,CAAC;CACH;CAIA,MAAM,kBAAkB,cAAc,MAAM,CAAC;CAE7C,OACE,qBAAC,eAAD;EAAe,IAAI;GAAE,WAAW;GAAK,UAAU;EAAO;YAAtD,CACG,QAAQ,KAAK,QACZ,oBAAC,WAAD;GAAqB,eAAe,kBAAkB,GAAG;aACtD,QAAQ,IAAI,EAAE,mBAAmB,IAAI,IAAI,IAAI;EACrC,GAFK,GAEL,CACZ,GACA,kBACC,oBAAC,WAAD;GAAqB;GAAU,eAAe,iBAAiB,IAAI;aAChE,EAAE,mBAAmB;EACb,CAAA,IAEX,qBAAC,mBAAD;GACE,iBAAe;GACf,UAAU,UAAU;IAGlB,IAAI,UACF;IAGF,MADoB,cAAc,cAAc,OAC5C,CAAC,EAAE,MAAM;IACb,MAAM,UAAU,OAAO,SAAS;IAChC,IAAI,aAAa,CAAC,OAAO,MAAM,OAAO,GACpC,SAAS,OAAO;GAEpB;aAdF,CAgBE,oBAAC,gBAAD;IACE,KAAK;IACL,WAAU;IACV,cAAa;IACb,aAAY;IACZ,cAAY,EAAE,mBAAmB;IACjC,OAAO;IACP,UAAU;IACV,WAAW;IACX,eAAe,iBAAiB,IAAI;IACpC,QAAQ;IACE;IACV,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,QAAQ,CAAC,EAAE,IAAI;GACtD,CAAA,GAAC,GAEe;IAER;;AAEnB"}
@@ -0,0 +1,118 @@
1
+ import { Card as Card$1 } from "../Card/Card.js";
2
+ import { getAccumulatedFeeCostsBreakdown } from "../../utils/fees.js";
3
+ import { SmallAvatar } from "../Avatar/SmallAvatar.js";
4
+ import { IconTypography } from "../IconTypography.js";
5
+ import { Box, Skeleton, Typography } from "@mui/material";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { useTranslation } from "react-i18next";
8
+ import LocalGasStationRounded from "@mui/icons-material/LocalGasStationRounded";
9
+ //#region src/components/RouteCard/RouteProviderCard.tsx
10
+ const RouteProviderCard = ({ route, active, onClick, ...other }) => {
11
+ const { t } = useTranslation();
12
+ const provider = route.steps[0]?.toolDetails;
13
+ const { gasCostUSD } = getAccumulatedFeeCostsBreakdown(route);
14
+ return /* @__PURE__ */ jsx(Card$1, {
15
+ type: active ? "selected" : "default",
16
+ selectionColor: "secondary",
17
+ onClick,
18
+ sx: {
19
+ py: 1.5,
20
+ px: 2,
21
+ ...onClick ? { cursor: "pointer" } : {}
22
+ },
23
+ ...other,
24
+ children: /* @__PURE__ */ jsxs(Box, {
25
+ sx: {
26
+ display: "flex",
27
+ alignItems: "center",
28
+ justifyContent: "space-between",
29
+ gap: 1
30
+ },
31
+ children: [/* @__PURE__ */ jsxs(Box, {
32
+ sx: {
33
+ display: "flex",
34
+ alignItems: "center",
35
+ gap: 1,
36
+ minWidth: 0
37
+ },
38
+ children: [/* @__PURE__ */ jsx(SmallAvatar, {
39
+ src: provider?.logoURI,
40
+ alt: provider?.name,
41
+ size: 20,
42
+ children: provider?.name?.[0]
43
+ }), /* @__PURE__ */ jsx(Typography, {
44
+ noWrap: true,
45
+ sx: {
46
+ fontSize: 14,
47
+ fontWeight: 600,
48
+ color: "text.primary"
49
+ },
50
+ children: provider?.name
51
+ })]
52
+ }), /* @__PURE__ */ jsxs(Box, {
53
+ sx: {
54
+ display: "flex",
55
+ alignItems: "center"
56
+ },
57
+ children: [/* @__PURE__ */ jsx(IconTypography, {
58
+ component: "span",
59
+ sx: {
60
+ mr: .5,
61
+ fontSize: 16
62
+ },
63
+ children: /* @__PURE__ */ jsx(LocalGasStationRounded, { fontSize: "inherit" })
64
+ }), /* @__PURE__ */ jsx(Typography, {
65
+ "data-value": gasCostUSD,
66
+ sx: {
67
+ fontSize: 14,
68
+ color: "text.primary",
69
+ fontWeight: 600,
70
+ lineHeight: 1
71
+ },
72
+ children: !gasCostUSD ? t("main.fees.free") : t("format.currency", { value: gasCostUSD })
73
+ })]
74
+ })]
75
+ })
76
+ });
77
+ };
78
+ const RouteProviderCardSkeleton = (props) => {
79
+ return /* @__PURE__ */ jsx(Card$1, {
80
+ sx: {
81
+ py: 1.5,
82
+ px: 2
83
+ },
84
+ ...props,
85
+ children: /* @__PURE__ */ jsxs(Box, {
86
+ sx: {
87
+ display: "flex",
88
+ alignItems: "center",
89
+ justifyContent: "space-between",
90
+ gap: 1
91
+ },
92
+ children: [/* @__PURE__ */ jsxs(Box, {
93
+ sx: {
94
+ display: "flex",
95
+ alignItems: "center",
96
+ gap: 1
97
+ },
98
+ children: [/* @__PURE__ */ jsx(Skeleton, {
99
+ variant: "circular",
100
+ width: 20,
101
+ height: 20
102
+ }), /* @__PURE__ */ jsx(Skeleton, {
103
+ variant: "text",
104
+ width: 80,
105
+ height: 20
106
+ })]
107
+ }), /* @__PURE__ */ jsx(Skeleton, {
108
+ variant: "text",
109
+ width: 56,
110
+ height: 20
111
+ })]
112
+ })
113
+ });
114
+ };
115
+ //#endregion
116
+ export { RouteProviderCard, RouteProviderCardSkeleton };
117
+
118
+ //# sourceMappingURL=RouteProviderCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteProviderCard.js","names":["Card"],"sources":["../../../../src/components/RouteCard/RouteProviderCard.tsx"],"sourcesContent":["import type { Route } from '@lifi/sdk'\nimport LocalGasStationRounded from '@mui/icons-material/LocalGasStationRounded'\nimport { Box, Skeleton, Typography } from '@mui/material'\nimport { useTranslation } from 'react-i18next'\nimport { getAccumulatedFeeCostsBreakdown } from '../../utils/fees.js'\nimport { SmallAvatar } from '../Avatar/SmallAvatar.js'\nimport type { CardProps } from '../Card/Card.js'\nimport { Card } from '../Card/Card.js'\nimport { IconTypography } from '../IconTypography.js'\n\ninterface RouteProviderCardProps {\n route: Route\n active?: boolean\n}\n\nexport const RouteProviderCard: React.FC<\n RouteProviderCardProps & Omit<CardProps, 'variant'>\n> = ({ route, active, onClick, ...other }) => {\n const { t } = useTranslation()\n\n const provider = route.steps[0]?.toolDetails\n const { gasCostUSD } = getAccumulatedFeeCostsBreakdown(route)\n\n return (\n <Card\n type={active ? 'selected' : 'default'}\n selectionColor=\"secondary\"\n onClick={onClick}\n sx={{ py: 1.5, px: 2, ...(onClick ? { cursor: 'pointer' } : {}) }}\n {...other}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 1,\n }}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n minWidth: 0,\n }}\n >\n <SmallAvatar src={provider?.logoURI} alt={provider?.name} size={20}>\n {provider?.name?.[0]}\n </SmallAvatar>\n <Typography\n noWrap\n sx={{\n fontSize: 14,\n fontWeight: 600,\n color: 'text.primary',\n }}\n >\n {provider?.name}\n </Typography>\n </Box>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n }}\n >\n <IconTypography component=\"span\" sx={{ mr: 0.5, fontSize: 16 }}>\n <LocalGasStationRounded fontSize=\"inherit\" />\n </IconTypography>\n <Typography\n data-value={gasCostUSD}\n sx={{\n fontSize: 14,\n color: 'text.primary',\n fontWeight: 600,\n lineHeight: 1,\n }}\n >\n {!gasCostUSD\n ? t('main.fees.free')\n : t('format.currency', {\n value: gasCostUSD,\n })}\n </Typography>\n </Box>\n </Box>\n </Card>\n )\n}\n\nexport const RouteProviderCardSkeleton: React.FC<Omit<CardProps, 'variant'>> = (\n props\n) => {\n return (\n <Card sx={{ py: 1.5, px: 2 }} {...props}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 1,\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Skeleton variant=\"circular\" width={20} height={20} />\n <Skeleton variant=\"text\" width={80} height={20} />\n </Box>\n <Skeleton variant=\"text\" width={56} height={20} />\n </Box>\n </Card>\n )\n}\n"],"mappings":";;;;;;;;;AAeA,MAAa,qBAER,EAAE,OAAO,QAAQ,SAAS,GAAG,YAAY;CAC5C,MAAM,EAAE,MAAM,eAAe;CAE7B,MAAM,WAAW,MAAM,MAAM,EAAE,EAAE;CACjC,MAAM,EAAE,eAAe,gCAAgC,KAAK;CAE5D,OACE,oBAACA,QAAD;EACE,MAAM,SAAS,aAAa;EAC5B,gBAAe;EACN;EACT,IAAI;GAAE,IAAI;GAAK,IAAI;GAAG,GAAI,UAAU,EAAE,QAAQ,UAAU,IAAI,CAAC;EAAG;EAChE,GAAI;YAEJ,qBAAC,KAAD;GACE,IAAI;IACF,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,KAAK;GACP;aANF,CAQE,qBAAC,KAAD;IACE,IAAI;KACF,SAAS;KACT,YAAY;KACZ,KAAK;KACL,UAAU;IACZ;cANF,CAQE,oBAAC,aAAD;KAAa,KAAK,UAAU;KAAS,KAAK,UAAU;KAAM,MAAM;eAC7D,UAAU,OAAO;IACP,CAAA,GACb,oBAAC,YAAD;KACE,QAAA;KACA,IAAI;MACF,UAAU;MACV,YAAY;MACZ,OAAO;KACT;eAEC,UAAU;IACD,CAAA,CACT;OACL,qBAAC,KAAD;IACE,IAAI;KACF,SAAS;KACT,YAAY;IACd;cAJF,CAME,oBAAC,gBAAD;KAAgB,WAAU;KAAO,IAAI;MAAE,IAAI;MAAK,UAAU;KAAG;eAC3D,oBAAC,wBAAD,EAAwB,UAAS,UAAW,CAAA;IAC9B,CAAA,GAChB,oBAAC,YAAD;KACE,cAAY;KACZ,IAAI;MACF,UAAU;MACV,OAAO;MACP,YAAY;MACZ,YAAY;KACd;eAEC,CAAC,aACE,EAAE,gBAAgB,IAClB,EAAE,mBAAmB,EACnB,OAAO,WACT,CAAC;IACK,CAAA,CACT;KACF;;CACD,CAAA;AAEV;AAEA,MAAa,6BACX,UACG;CACH,OACE,oBAACA,QAAD;EAAM,IAAI;GAAE,IAAI;GAAK,IAAI;EAAE;EAAG,GAAI;YAChC,qBAAC,KAAD;GACE,IAAI;IACF,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,KAAK;GACP;aANF,CAQE,qBAAC,KAAD;IAAK,IAAI;KAAE,SAAS;KAAQ,YAAY;KAAU,KAAK;IAAE;cAAzD,CACE,oBAAC,UAAD;KAAU,SAAQ;KAAW,OAAO;KAAI,QAAQ;IAAK,CAAA,GACrD,oBAAC,UAAD;KAAU,SAAQ;KAAO,OAAO;KAAI,QAAQ;IAAK,CAAA,CAC9C;OACL,oBAAC,UAAD;IAAU,SAAQ;IAAO,OAAO;IAAI,QAAQ;GAAK,CAAA,CAC9C;;CACD,CAAA;AAEV"}