@0xsquid/ui 0.7.3 → 0.7.4

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/cjs/index.js CHANGED
@@ -2532,6 +2532,24 @@ const twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);
2532
2532
  const cn = (...inputs) => {
2533
2533
  return twMerge(clsx(inputs));
2534
2534
  };
2535
+ function debounce(func, delay) {
2536
+ let timeoutId;
2537
+ const debounced = function (...args) {
2538
+ // @ts-expect-error - 'this' implicitly has type 'any' because it does not have a type annotation.
2539
+ const context = this;
2540
+ const later = () => {
2541
+ timeoutId = null;
2542
+ func.apply(context, args);
2543
+ };
2544
+ clearTimeout(timeoutId);
2545
+ timeoutId = setTimeout(later, delay);
2546
+ };
2547
+ debounced.cancel = () => {
2548
+ clearTimeout(timeoutId);
2549
+ timeoutId = null;
2550
+ };
2551
+ return debounced;
2552
+ }
2535
2553
 
2536
2554
  const badgeSizeClassMap = {
2537
2555
  sm: 'tw-w-4 tw-h-4',
@@ -2794,6 +2812,135 @@ const PasteButton = () => {
2794
2812
  return (jsxRuntime.jsx("button", { className: "tw-h-[30px] tw-rounded-full tw-border tw-border-grey-700 tw-bg-grey-800 tw-px-2 tw-text-grey-300", children: jsxRuntime.jsx(CaptionText, { children: "Paste" }) }));
2795
2813
  };
2796
2814
 
2815
+ const NumericInput = (_a) => {
2816
+ var _b;
2817
+ var { onParsedValueChanged, initialValue = '', forcedUpdateValue, maxDecimals, balance, sourceTokenUsdPrice } = _a, props = __rest(_a, ["onParsedValueChanged", "initialValue", "forcedUpdateValue", "maxDecimals", "balance", "sourceTokenUsdPrice"]);
2818
+ const [inputValue, setInputValue] = react.useState(initialValue);
2819
+ // Probably a better way to handle this
2820
+ // This was introduce to handle the "MAX" button setting an amount
2821
+ // Other than that, this component is only sending value to the exterior
2822
+ // Without this, we were losing inputs such as ".05" that were forced parsed to "0.05" after debounce
2823
+ react.useEffect(() => {
2824
+ if (forcedUpdateValue && forcedUpdateValue !== '0') {
2825
+ setInputValue(forcedUpdateValue);
2826
+ }
2827
+ }, [forcedUpdateValue]);
2828
+ /**
2829
+ * Get the number of decimals of inputValue
2830
+ * If there are more decimals than the maxDecimals
2831
+ * remove the extra decimals
2832
+ */
2833
+ react.useEffect(() => {
2834
+ var _a;
2835
+ const split = inputValue.split('.');
2836
+ if (split.length > 1) {
2837
+ const decimals = (_a = split[1]) !== null && _a !== void 0 ? _a : '';
2838
+ if (maxDecimals && decimals.length > maxDecimals) {
2839
+ const newValue = `${split[0]}.${decimals.slice(0, maxDecimals)}`;
2840
+ setInputValue(newValue);
2841
+ onParsedValueChanged(newValue);
2842
+ }
2843
+ }
2844
+ }, [maxDecimals]);
2845
+ const debouncePriceChanged = (value = '') => {
2846
+ if (value.endsWith('.'))
2847
+ return;
2848
+ onParsedValueChanged(value);
2849
+ };
2850
+ // useCallback to memoizes the debounce function, prevents recreating it
2851
+ const debouncePriceUpdate = react.useCallback(debounce(debouncePriceChanged, 700), []);
2852
+ const handlePriceChanged = (event) => {
2853
+ var _a;
2854
+ try {
2855
+ const formattedInput = event.currentTarget.value
2856
+ .replace(/[^0-9\.\,$%]/g, '')
2857
+ .replace(',', '.');
2858
+ if (formattedInput.includes('$') || formattedInput.includes('%')) {
2859
+ let cleanedInput = formattedInput;
2860
+ if (formattedInput.includes('$') && formattedInput.includes('%')) {
2861
+ // only allow one of them
2862
+ cleanedInput = formattedInput
2863
+ .replaceAll('$', '')
2864
+ .replaceAll('%', '')
2865
+ .concat('%');
2866
+ }
2867
+ else if (formattedInput.includes('%')) {
2868
+ // remove duplicates & always add % at the end
2869
+ cleanedInput = formattedInput.replaceAll('%', '').concat('%');
2870
+ }
2871
+ else if (formattedInput.includes('$')) {
2872
+ // Always add $ at the beginning
2873
+ cleanedInput = formattedInput.replaceAll('$', '');
2874
+ cleanedInput = `$${cleanedInput}`;
2875
+ }
2876
+ setInputValue(cleanedInput);
2877
+ debouncePriceUpdate.cancel();
2878
+ return;
2879
+ }
2880
+ // This is to prevent the user from typing more decimals than the decimals attribute of the token
2881
+ if (maxDecimals !== undefined) {
2882
+ const split = formattedInput.split('.');
2883
+ if (split.length > 1) {
2884
+ const decimals = (_a = split[1]) !== null && _a !== void 0 ? _a : '';
2885
+ if (decimals.length > maxDecimals) {
2886
+ // Don't update anything
2887
+ return;
2888
+ }
2889
+ }
2890
+ }
2891
+ // if input includes at least one character different than `0` (zero), `.` (dot), or `,` (comma)
2892
+ // means that user is typing a valid amount, for example: 1.02 or 0.005
2893
+ // if so, then update the input value and fetch the price
2894
+ if (/[^0,.]/.test(formattedInput)) {
2895
+ setInputValue(formattedInput);
2896
+ debouncePriceUpdate(formattedInput);
2897
+ }
2898
+ else if (
2899
+ // Means the user is currently typing and will add decimal, no need to fetch or parse
2900
+ // example input: 0.00
2901
+ (formattedInput.includes('.') && formattedInput.endsWith('0')) ||
2902
+ formattedInput.endsWith('.') ||
2903
+ (formattedInput === '0' && (inputValue === '' || inputValue === '0'))) {
2904
+ setInputValue(formattedInput);
2905
+ }
2906
+ else if (!isNaN(+formattedInput)) {
2907
+ setInputValue(formattedInput.toString());
2908
+ debouncePriceUpdate(formattedInput.toString());
2909
+ // onParsedValueChanged(formattedInput.toString());
2910
+ }
2911
+ else {
2912
+ setInputValue('');
2913
+ }
2914
+ }
2915
+ catch (error) {
2916
+ setInputValue('');
2917
+ }
2918
+ };
2919
+ const handleSubmit = (event) => {
2920
+ event.preventDefault();
2921
+ if (inputValue.includes('%')) {
2922
+ const percentage = Number(inputValue.replace('%', ''));
2923
+ // If the percentage is greater than 100, set it to 100
2924
+ const formattedPercentage = percentage > 100 ? 100 : percentage;
2925
+ const valueByPercentage = Number(balance) * (formattedPercentage / 100);
2926
+ // If the value is 0, we want to show 0, not 0.0000
2927
+ const formattedValue = valueByPercentage === 0 ? '0' : valueByPercentage.toFixed(4);
2928
+ setInputValue(formattedValue);
2929
+ onParsedValueChanged(formattedValue);
2930
+ }
2931
+ if (inputValue.includes('$')) {
2932
+ const usdAmount = Number(inputValue.replace('$', ''));
2933
+ if (usdAmount > 0) {
2934
+ const newValue = usdAmount / Number(sourceTokenUsdPrice !== null && sourceTokenUsdPrice !== void 0 ? sourceTokenUsdPrice : 0);
2935
+ const newValueFormatted = newValue.toFixed(4);
2936
+ setInputValue(newValueFormatted);
2937
+ onParsedValueChanged(newValueFormatted);
2938
+ }
2939
+ }
2940
+ };
2941
+ return (jsxRuntime.jsx("form", { className: "tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", onSubmit: handleSubmit, children: jsxRuntime.jsx("input", Object.assign({}, props, { onChange: handlePriceChanged, value: inputValue, type: "string", placeholder: (_b = props.placeholder) !== null && _b !== void 0 ? _b : '0', className: "tw-h-[55px] tw-w-full tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300 placeholder:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin focus:tw-text-royal-400 focus:tw-outline-none" })) }));
2942
+ };
2943
+
2797
2944
  // font size, line height, and letter spacing classes
2798
2945
  const textClassMap = {
2799
2946
  small: 'tw-text-heading-small tw-tracking-heading-small tw-leading-heading-small',
@@ -3144,7 +3291,7 @@ function SwapInputsIcon() {
3144
3291
  return (jsxRuntime.jsxs("svg", { width: "20", height: "21", viewBox: "0 0 20 21", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsx("g", { "clip-path": "url(#clip0_40_7936)", children: jsxRuntime.jsx("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M20 10.5C20 16.0228 15.5228 20.5 10 20.5C4.47715 20.5 0 16.0228 0 10.5C0 4.97715 4.47715 0.5 10 0.5C15.5228 0.5 20 4.97715 20 10.5ZM8.38268 4.57612C8.75636 4.7309 9 5.09554 9 5.5V15.5C9 16.0523 8.55228 16.5 8 16.5C7.44772 16.5 7 16.0523 7 15.5V7.91421L5.70711 9.20711C5.31658 9.59763 4.68342 9.59763 4.29289 9.20711C3.90237 8.81658 3.90237 8.18342 4.29289 7.79289L7.29289 4.79289C7.57889 4.5069 8.00901 4.42134 8.38268 4.57612ZM11 15.5C11 15.9045 11.2436 16.2691 11.6173 16.4239C11.991 16.5787 12.4211 16.4931 12.7071 16.2071L15.7071 13.2071C16.0976 12.8166 16.0976 12.1834 15.7071 11.7929C15.3166 11.4024 14.6834 11.4024 14.2929 11.7929L13 13.0858V5.5C13 4.94771 12.5523 4.5 12 4.5C11.4477 4.5 11 4.94771 11 5.5V15.5Z", fill: "currentColor" }) }), jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("clipPath", { id: "clip0_40_7936", children: jsxRuntime.jsx("rect", { width: "20", height: "20", fill: "white", transform: "translate(0 0.5)" }) }) })] }));
3145
3292
  }
3146
3293
 
3147
- function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd = '0', balance = '0', isFetching = false, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, address, error, }) {
3294
+ function SwapConfiguration({ priceImpactPercentage, amount, forcedAmount, swapAmountUsd = '0', balance = '0', isFetching = false, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, onBalanceButtonClick, address, error, }) {
3148
3295
  var _a;
3149
3296
  const priceImpactClass = ((_a = Number(priceImpactPercentage)) !== null && _a !== void 0 ? _a : 0) > 5
3150
3297
  ? 'tw-text-status-negative'
@@ -3152,7 +3299,9 @@ function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd = '0',
3152
3299
  const isInteractive = direction === 'from';
3153
3300
  // improve accessibility
3154
3301
  const BalanceButtonTag = isInteractive ? 'button' : 'div';
3155
- return (jsxRuntime.jsxs("section", { className: "tw-h-[205px] tw-max-h-[205px] tw-bg-grey-900 tw-pb-squid-m", children: [jsxRuntime.jsx("header", { className: "tw-flex tw-items-center tw-gap-1 tw-px-squid-l tw-py-squid-xs tw-leading-5 tw-text-grey-300", children: jsxRuntime.jsxs("button", { onClick: onWalletButtonClick, className: "-tw-ml-squid-xs tw-flex tw-h-squid-l tw-items-center tw-gap-squid-xxs tw-rounded-squid-s tw-px-squid-xs tw-text-grey-600 hover:tw-bg-material-light-thin", children: [jsxRuntime.jsx(BodyText, { className: "tw-text-grey-500", size: "small", children: direction === 'from' ? 'Pay' : 'Receive' }), jsxRuntime.jsx(BodyText, { size: "small", children: ":" }), jsxRuntime.jsxs("div", { className: "tw-flex tw-items-center tw-gap-1", children: [jsxRuntime.jsx(BodyText, { size: "small", className: address ? 'tw-text-grey-300' : 'tw-text-royal-400', children: address ? address : 'Connect wallet' }), jsxRuntime.jsx(ChevronArrowIcon, { className: address ? 'tw-text-grey-600' : 'tw-text-royal-400' })] })] }) }), jsxRuntime.jsx("div", { className: "tw-px-squid-l", children: jsxRuntime.jsx(AssetsButton, { onClick: onAssetsButtonClick, chainImageUrl: chain === null || chain === void 0 ? void 0 : chain.iconUrl, tokenImageUrl: token === null || token === void 0 ? void 0 : token.iconUrl, tokenSymbol: token === null || token === void 0 ? void 0 : token.symbol, chainBgColor: chain === null || chain === void 0 ? void 0 : chain.bgColor, tokenBgColor: token === null || token === void 0 ? void 0 : token.bgColor, tokenTextColor: token === null || token === void 0 ? void 0 : token.textColor }) }), direction === 'from' ? (jsxRuntime.jsx("div", { className: "tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsxRuntime.jsx("input", { className: "tw-h-[55px] tw-w-full tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300 placeholder:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin focus:tw-text-royal-400 focus:tw-outline-none", placeholder: "0", value: amount, onChange: onAmountChange }) })) : (jsxRuntime.jsx("div", { className: "tw-w-full tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsxRuntime.jsx("div", { className: "tw-flex tw-h-[55px] tw-w-full tw-items-center tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300", children: jsxRuntime.jsx("span", { children: amount }) }) })), !(token === null || token === void 0 ? void 0 : token.iconUrl) || isFetching ? null : (jsxRuntime.jsxs("footer", { className: "tw-flex tw-h-squid-m tw-max-h-squid-m tw-items-center tw-justify-between tw-gap-2 tw-px-squid-m tw-text-grey-500", children: [error ? (jsxRuntime.jsx("div", { className: "tw-px-squid-xs", children: jsxRuntime.jsx(ErrorMessage, { message: error.message }) })) : (jsxRuntime.jsxs("div", { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin'), children: [jsxRuntime.jsx(SwapInputsIcon, {}), jsxRuntime.jsx(UsdAmount, { usdAmount: swapAmountUsd }), priceImpactPercentage && direction === 'to' ? (jsxRuntime.jsxs("span", { className: clsx('tw-flex tw-items-center', priceImpactClass), children: [jsxRuntime.jsx(ArrowTriangle, {}), jsxRuntime.jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxRuntime.jsxs(BalanceButtonTag, { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin', direction === 'to' && 'tw-pointer-events-none'), children: [jsxRuntime.jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsxRuntime.jsx(CaptionText, { children: balance }), jsxRuntime.jsx(MaxIcon, {})] })] }))] }));
3302
+ return (jsxRuntime.jsxs("section", { className: "tw-h-[205px] tw-max-h-[205px] tw-bg-grey-900 tw-pb-squid-m", children: [jsxRuntime.jsx("header", { className: "tw-flex tw-items-center tw-gap-1 tw-px-squid-l tw-py-squid-xs tw-leading-5 tw-text-grey-300", children: jsxRuntime.jsxs("button", { onClick: onWalletButtonClick, className: "-tw-ml-squid-xs tw-flex tw-h-squid-l tw-items-center tw-gap-squid-xxs tw-rounded-squid-s tw-px-squid-xs tw-text-grey-600 hover:tw-bg-material-light-thin", children: [jsxRuntime.jsx(BodyText, { className: "tw-text-grey-500", size: "small", children: direction === 'from' ? 'Pay' : 'Receive' }), jsxRuntime.jsx(BodyText, { size: "small", children: ":" }), jsxRuntime.jsxs("div", { className: "tw-flex tw-items-center tw-gap-1", children: [jsxRuntime.jsx(BodyText, { size: "small", className: address ? 'tw-text-grey-300' : 'tw-text-royal-400', children: address ? address : 'Connect wallet' }), jsxRuntime.jsx(ChevronArrowIcon, { className: address ? 'tw-text-grey-600' : 'tw-text-royal-400' })] })] }) }), jsxRuntime.jsx("div", { className: "tw-px-squid-l", children: jsxRuntime.jsx(AssetsButton, { onClick: onAssetsButtonClick, chainImageUrl: chain === null || chain === void 0 ? void 0 : chain.iconUrl, tokenImageUrl: token === null || token === void 0 ? void 0 : token.iconUrl, tokenSymbol: token === null || token === void 0 ? void 0 : token.symbol, chainBgColor: chain === null || chain === void 0 ? void 0 : chain.bgColor, tokenBgColor: token === null || token === void 0 ? void 0 : token.bgColor, tokenTextColor: token === null || token === void 0 ? void 0 : token.textColor }) }), direction === 'from' ? (jsxRuntime.jsx(NumericInput, { forcedUpdateValue: forcedAmount, initialValue: amount, onParsedValueChanged: (value) => onAmountChange === null || onAmountChange === void 0 ? void 0 : onAmountChange(value) })) : (jsxRuntime.jsx("div", { className: "tw-w-full tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsxRuntime.jsx("div", { className: "tw-flex tw-h-[55px] tw-w-full tw-items-center tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300", children: jsxRuntime.jsx("span", { children: amount }) }) })), !(token === null || token === void 0 ? void 0 : token.iconUrl) || isFetching ? null : (jsxRuntime.jsxs("footer", { className: "tw-flex tw-h-squid-m tw-max-h-squid-m tw-items-center tw-justify-between tw-gap-2 tw-px-squid-m tw-text-grey-500", children: [error ? (jsxRuntime.jsx("div", { className: "tw-px-squid-xs", children: jsxRuntime.jsx(ErrorMessage, { message: error.message }) })) : (jsxRuntime.jsxs("div", { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin'), children: [jsxRuntime.jsx(SwapInputsIcon, {}), jsxRuntime.jsx(UsdAmount, { usdAmount: swapAmountUsd }), priceImpactPercentage && direction === 'to' ? (jsxRuntime.jsxs("span", { className: clsx('tw-flex tw-items-center', priceImpactClass), children: [jsxRuntime.jsx(ArrowTriangle, {}), jsxRuntime.jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxRuntime.jsxs(BalanceButtonTag, { onClick: onBalanceButtonClick, className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive
3303
+ ? 'hover:tw-bg-material-light-thin'
3304
+ : 'tw-pointer-events-none'), children: [jsxRuntime.jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsxRuntime.jsx(CaptionText, { children: balance }), jsxRuntime.jsx(MaxIcon, {})] })] }))] }));
3156
3305
  }
3157
3306
 
3158
3307
  function SwapProgressViewHeader({ title, description, }) {
@@ -3279,6 +3428,7 @@ exports.Menu = Menu;
3279
3428
  exports.MenuItem = MenuItem;
3280
3429
  exports.Modal = Modal;
3281
3430
  exports.NavigationBar = NavigationBar;
3431
+ exports.NumericInput = NumericInput;
3282
3432
  exports.ProductCard = ProductCard;
3283
3433
  exports.SectionTitle = SectionTitle;
3284
3434
  exports.SettingsButton = SettingsButton;
@@ -0,0 +1,11 @@
1
+ import type { InputHTMLAttributes } from 'react';
2
+ interface Props extends InputHTMLAttributes<HTMLInputElement> {
3
+ onParsedValueChanged: (value: string) => void;
4
+ initialValue?: string;
5
+ forcedUpdateValue?: string;
6
+ maxDecimals?: number;
7
+ balance?: string;
8
+ sourceTokenUsdPrice?: number;
9
+ }
10
+ export declare const NumericInput: ({ onParsedValueChanged, initialValue, forcedUpdateValue, maxDecimals, balance, sourceTokenUsdPrice, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -1,4 +1,5 @@
1
1
  export * from './Input';
2
+ export * from './NumericInput';
2
3
  export * from './SettingsSlider';
3
4
  export * from './Switch';
4
5
  export * from './Tooltip';
@@ -1,9 +1,9 @@
1
- /// <reference types="react" />
2
1
  import { SwapDirection } from '../../types/components';
3
2
  interface SwapConfigurationProps {
4
3
  direction: SwapDirection;
5
4
  priceImpactPercentage?: string;
6
5
  amount?: string;
6
+ forcedAmount?: string;
7
7
  swapAmountUsd?: string;
8
8
  balance?: string;
9
9
  isFetching?: boolean;
@@ -18,12 +18,13 @@ interface SwapConfigurationProps {
18
18
  textColor: string;
19
19
  };
20
20
  address?: string;
21
- onAmountChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
21
+ onAmountChange?: (amount: string) => void;
22
22
  onWalletButtonClick?: () => void;
23
23
  onAssetsButtonClick?: () => void;
24
+ onBalanceButtonClick?: () => void;
24
25
  error?: {
25
26
  message: string;
26
27
  };
27
28
  }
28
- export declare function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, address, error, }: SwapConfigurationProps): import("react/jsx-runtime").JSX.Element;
29
+ export declare function SwapConfiguration({ priceImpactPercentage, amount, forcedAmount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, onBalanceButtonClick, address, error, }: SwapConfigurationProps): import("react/jsx-runtime").JSX.Element;
29
30
  export {};
@@ -8,3 +8,10 @@ import { ClassValue } from 'clsx';
8
8
  * @returns The combined class names as a string.
9
9
  */
10
10
  export declare const cn: (...inputs: ClassValue[]) => string;
11
+ type AnyFunction = (...args: any[]) => any;
12
+ interface DebouncedFunction<F extends AnyFunction> {
13
+ (...args: Parameters<F>): void;
14
+ cancel: () => void;
15
+ }
16
+ export declare function debounce<F extends AnyFunction>(func: F, delay: number): DebouncedFunction<F>;
17
+ export {};
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useMemo, useRef, useState, useEffect, useCallback } from 'react';
2
+ import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
3
3
 
4
4
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
5
5
 
@@ -2530,6 +2530,24 @@ const twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);
2530
2530
  const cn = (...inputs) => {
2531
2531
  return twMerge(clsx(inputs));
2532
2532
  };
2533
+ function debounce(func, delay) {
2534
+ let timeoutId;
2535
+ const debounced = function (...args) {
2536
+ // @ts-expect-error - 'this' implicitly has type 'any' because it does not have a type annotation.
2537
+ const context = this;
2538
+ const later = () => {
2539
+ timeoutId = null;
2540
+ func.apply(context, args);
2541
+ };
2542
+ clearTimeout(timeoutId);
2543
+ timeoutId = setTimeout(later, delay);
2544
+ };
2545
+ debounced.cancel = () => {
2546
+ clearTimeout(timeoutId);
2547
+ timeoutId = null;
2548
+ };
2549
+ return debounced;
2550
+ }
2533
2551
 
2534
2552
  const badgeSizeClassMap = {
2535
2553
  sm: 'tw-w-4 tw-h-4',
@@ -2792,6 +2810,135 @@ const PasteButton = () => {
2792
2810
  return (jsx("button", { className: "tw-h-[30px] tw-rounded-full tw-border tw-border-grey-700 tw-bg-grey-800 tw-px-2 tw-text-grey-300", children: jsx(CaptionText, { children: "Paste" }) }));
2793
2811
  };
2794
2812
 
2813
+ const NumericInput = (_a) => {
2814
+ var _b;
2815
+ var { onParsedValueChanged, initialValue = '', forcedUpdateValue, maxDecimals, balance, sourceTokenUsdPrice } = _a, props = __rest(_a, ["onParsedValueChanged", "initialValue", "forcedUpdateValue", "maxDecimals", "balance", "sourceTokenUsdPrice"]);
2816
+ const [inputValue, setInputValue] = useState(initialValue);
2817
+ // Probably a better way to handle this
2818
+ // This was introduce to handle the "MAX" button setting an amount
2819
+ // Other than that, this component is only sending value to the exterior
2820
+ // Without this, we were losing inputs such as ".05" that were forced parsed to "0.05" after debounce
2821
+ useEffect(() => {
2822
+ if (forcedUpdateValue && forcedUpdateValue !== '0') {
2823
+ setInputValue(forcedUpdateValue);
2824
+ }
2825
+ }, [forcedUpdateValue]);
2826
+ /**
2827
+ * Get the number of decimals of inputValue
2828
+ * If there are more decimals than the maxDecimals
2829
+ * remove the extra decimals
2830
+ */
2831
+ useEffect(() => {
2832
+ var _a;
2833
+ const split = inputValue.split('.');
2834
+ if (split.length > 1) {
2835
+ const decimals = (_a = split[1]) !== null && _a !== void 0 ? _a : '';
2836
+ if (maxDecimals && decimals.length > maxDecimals) {
2837
+ const newValue = `${split[0]}.${decimals.slice(0, maxDecimals)}`;
2838
+ setInputValue(newValue);
2839
+ onParsedValueChanged(newValue);
2840
+ }
2841
+ }
2842
+ }, [maxDecimals]);
2843
+ const debouncePriceChanged = (value = '') => {
2844
+ if (value.endsWith('.'))
2845
+ return;
2846
+ onParsedValueChanged(value);
2847
+ };
2848
+ // useCallback to memoizes the debounce function, prevents recreating it
2849
+ const debouncePriceUpdate = useCallback(debounce(debouncePriceChanged, 700), []);
2850
+ const handlePriceChanged = (event) => {
2851
+ var _a;
2852
+ try {
2853
+ const formattedInput = event.currentTarget.value
2854
+ .replace(/[^0-9\.\,$%]/g, '')
2855
+ .replace(',', '.');
2856
+ if (formattedInput.includes('$') || formattedInput.includes('%')) {
2857
+ let cleanedInput = formattedInput;
2858
+ if (formattedInput.includes('$') && formattedInput.includes('%')) {
2859
+ // only allow one of them
2860
+ cleanedInput = formattedInput
2861
+ .replaceAll('$', '')
2862
+ .replaceAll('%', '')
2863
+ .concat('%');
2864
+ }
2865
+ else if (formattedInput.includes('%')) {
2866
+ // remove duplicates & always add % at the end
2867
+ cleanedInput = formattedInput.replaceAll('%', '').concat('%');
2868
+ }
2869
+ else if (formattedInput.includes('$')) {
2870
+ // Always add $ at the beginning
2871
+ cleanedInput = formattedInput.replaceAll('$', '');
2872
+ cleanedInput = `$${cleanedInput}`;
2873
+ }
2874
+ setInputValue(cleanedInput);
2875
+ debouncePriceUpdate.cancel();
2876
+ return;
2877
+ }
2878
+ // This is to prevent the user from typing more decimals than the decimals attribute of the token
2879
+ if (maxDecimals !== undefined) {
2880
+ const split = formattedInput.split('.');
2881
+ if (split.length > 1) {
2882
+ const decimals = (_a = split[1]) !== null && _a !== void 0 ? _a : '';
2883
+ if (decimals.length > maxDecimals) {
2884
+ // Don't update anything
2885
+ return;
2886
+ }
2887
+ }
2888
+ }
2889
+ // if input includes at least one character different than `0` (zero), `.` (dot), or `,` (comma)
2890
+ // means that user is typing a valid amount, for example: 1.02 or 0.005
2891
+ // if so, then update the input value and fetch the price
2892
+ if (/[^0,.]/.test(formattedInput)) {
2893
+ setInputValue(formattedInput);
2894
+ debouncePriceUpdate(formattedInput);
2895
+ }
2896
+ else if (
2897
+ // Means the user is currently typing and will add decimal, no need to fetch or parse
2898
+ // example input: 0.00
2899
+ (formattedInput.includes('.') && formattedInput.endsWith('0')) ||
2900
+ formattedInput.endsWith('.') ||
2901
+ (formattedInput === '0' && (inputValue === '' || inputValue === '0'))) {
2902
+ setInputValue(formattedInput);
2903
+ }
2904
+ else if (!isNaN(+formattedInput)) {
2905
+ setInputValue(formattedInput.toString());
2906
+ debouncePriceUpdate(formattedInput.toString());
2907
+ // onParsedValueChanged(formattedInput.toString());
2908
+ }
2909
+ else {
2910
+ setInputValue('');
2911
+ }
2912
+ }
2913
+ catch (error) {
2914
+ setInputValue('');
2915
+ }
2916
+ };
2917
+ const handleSubmit = (event) => {
2918
+ event.preventDefault();
2919
+ if (inputValue.includes('%')) {
2920
+ const percentage = Number(inputValue.replace('%', ''));
2921
+ // If the percentage is greater than 100, set it to 100
2922
+ const formattedPercentage = percentage > 100 ? 100 : percentage;
2923
+ const valueByPercentage = Number(balance) * (formattedPercentage / 100);
2924
+ // If the value is 0, we want to show 0, not 0.0000
2925
+ const formattedValue = valueByPercentage === 0 ? '0' : valueByPercentage.toFixed(4);
2926
+ setInputValue(formattedValue);
2927
+ onParsedValueChanged(formattedValue);
2928
+ }
2929
+ if (inputValue.includes('$')) {
2930
+ const usdAmount = Number(inputValue.replace('$', ''));
2931
+ if (usdAmount > 0) {
2932
+ const newValue = usdAmount / Number(sourceTokenUsdPrice !== null && sourceTokenUsdPrice !== void 0 ? sourceTokenUsdPrice : 0);
2933
+ const newValueFormatted = newValue.toFixed(4);
2934
+ setInputValue(newValueFormatted);
2935
+ onParsedValueChanged(newValueFormatted);
2936
+ }
2937
+ }
2938
+ };
2939
+ return (jsx("form", { className: "tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", onSubmit: handleSubmit, children: jsx("input", Object.assign({}, props, { onChange: handlePriceChanged, value: inputValue, type: "string", placeholder: (_b = props.placeholder) !== null && _b !== void 0 ? _b : '0', className: "tw-h-[55px] tw-w-full tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300 placeholder:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin focus:tw-text-royal-400 focus:tw-outline-none" })) }));
2940
+ };
2941
+
2795
2942
  // font size, line height, and letter spacing classes
2796
2943
  const textClassMap = {
2797
2944
  small: 'tw-text-heading-small tw-tracking-heading-small tw-leading-heading-small',
@@ -3142,7 +3289,7 @@ function SwapInputsIcon() {
3142
3289
  return (jsxs("svg", { width: "20", height: "21", viewBox: "0 0 20 21", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("g", { "clip-path": "url(#clip0_40_7936)", children: jsx("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M20 10.5C20 16.0228 15.5228 20.5 10 20.5C4.47715 20.5 0 16.0228 0 10.5C0 4.97715 4.47715 0.5 10 0.5C15.5228 0.5 20 4.97715 20 10.5ZM8.38268 4.57612C8.75636 4.7309 9 5.09554 9 5.5V15.5C9 16.0523 8.55228 16.5 8 16.5C7.44772 16.5 7 16.0523 7 15.5V7.91421L5.70711 9.20711C5.31658 9.59763 4.68342 9.59763 4.29289 9.20711C3.90237 8.81658 3.90237 8.18342 4.29289 7.79289L7.29289 4.79289C7.57889 4.5069 8.00901 4.42134 8.38268 4.57612ZM11 15.5C11 15.9045 11.2436 16.2691 11.6173 16.4239C11.991 16.5787 12.4211 16.4931 12.7071 16.2071L15.7071 13.2071C16.0976 12.8166 16.0976 12.1834 15.7071 11.7929C15.3166 11.4024 14.6834 11.4024 14.2929 11.7929L13 13.0858V5.5C13 4.94771 12.5523 4.5 12 4.5C11.4477 4.5 11 4.94771 11 5.5V15.5Z", fill: "currentColor" }) }), jsx("defs", { children: jsx("clipPath", { id: "clip0_40_7936", children: jsx("rect", { width: "20", height: "20", fill: "white", transform: "translate(0 0.5)" }) }) })] }));
3143
3290
  }
3144
3291
 
3145
- function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd = '0', balance = '0', isFetching = false, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, address, error, }) {
3292
+ function SwapConfiguration({ priceImpactPercentage, amount, forcedAmount, swapAmountUsd = '0', balance = '0', isFetching = false, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, onBalanceButtonClick, address, error, }) {
3146
3293
  var _a;
3147
3294
  const priceImpactClass = ((_a = Number(priceImpactPercentage)) !== null && _a !== void 0 ? _a : 0) > 5
3148
3295
  ? 'tw-text-status-negative'
@@ -3150,7 +3297,9 @@ function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd = '0',
3150
3297
  const isInteractive = direction === 'from';
3151
3298
  // improve accessibility
3152
3299
  const BalanceButtonTag = isInteractive ? 'button' : 'div';
3153
- return (jsxs("section", { className: "tw-h-[205px] tw-max-h-[205px] tw-bg-grey-900 tw-pb-squid-m", children: [jsx("header", { className: "tw-flex tw-items-center tw-gap-1 tw-px-squid-l tw-py-squid-xs tw-leading-5 tw-text-grey-300", children: jsxs("button", { onClick: onWalletButtonClick, className: "-tw-ml-squid-xs tw-flex tw-h-squid-l tw-items-center tw-gap-squid-xxs tw-rounded-squid-s tw-px-squid-xs tw-text-grey-600 hover:tw-bg-material-light-thin", children: [jsx(BodyText, { className: "tw-text-grey-500", size: "small", children: direction === 'from' ? 'Pay' : 'Receive' }), jsx(BodyText, { size: "small", children: ":" }), jsxs("div", { className: "tw-flex tw-items-center tw-gap-1", children: [jsx(BodyText, { size: "small", className: address ? 'tw-text-grey-300' : 'tw-text-royal-400', children: address ? address : 'Connect wallet' }), jsx(ChevronArrowIcon, { className: address ? 'tw-text-grey-600' : 'tw-text-royal-400' })] })] }) }), jsx("div", { className: "tw-px-squid-l", children: jsx(AssetsButton, { onClick: onAssetsButtonClick, chainImageUrl: chain === null || chain === void 0 ? void 0 : chain.iconUrl, tokenImageUrl: token === null || token === void 0 ? void 0 : token.iconUrl, tokenSymbol: token === null || token === void 0 ? void 0 : token.symbol, chainBgColor: chain === null || chain === void 0 ? void 0 : chain.bgColor, tokenBgColor: token === null || token === void 0 ? void 0 : token.bgColor, tokenTextColor: token === null || token === void 0 ? void 0 : token.textColor }) }), direction === 'from' ? (jsx("div", { className: "tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsx("input", { className: "tw-h-[55px] tw-w-full tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300 placeholder:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin focus:tw-text-royal-400 focus:tw-outline-none", placeholder: "0", value: amount, onChange: onAmountChange }) })) : (jsx("div", { className: "tw-w-full tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsx("div", { className: "tw-flex tw-h-[55px] tw-w-full tw-items-center tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300", children: jsx("span", { children: amount }) }) })), !(token === null || token === void 0 ? void 0 : token.iconUrl) || isFetching ? null : (jsxs("footer", { className: "tw-flex tw-h-squid-m tw-max-h-squid-m tw-items-center tw-justify-between tw-gap-2 tw-px-squid-m tw-text-grey-500", children: [error ? (jsx("div", { className: "tw-px-squid-xs", children: jsx(ErrorMessage, { message: error.message }) })) : (jsxs("div", { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin'), children: [jsx(SwapInputsIcon, {}), jsx(UsdAmount, { usdAmount: swapAmountUsd }), priceImpactPercentage && direction === 'to' ? (jsxs("span", { className: clsx('tw-flex tw-items-center', priceImpactClass), children: [jsx(ArrowTriangle, {}), jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxs(BalanceButtonTag, { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin', direction === 'to' && 'tw-pointer-events-none'), children: [jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsx(CaptionText, { children: balance }), jsx(MaxIcon, {})] })] }))] }));
3300
+ return (jsxs("section", { className: "tw-h-[205px] tw-max-h-[205px] tw-bg-grey-900 tw-pb-squid-m", children: [jsx("header", { className: "tw-flex tw-items-center tw-gap-1 tw-px-squid-l tw-py-squid-xs tw-leading-5 tw-text-grey-300", children: jsxs("button", { onClick: onWalletButtonClick, className: "-tw-ml-squid-xs tw-flex tw-h-squid-l tw-items-center tw-gap-squid-xxs tw-rounded-squid-s tw-px-squid-xs tw-text-grey-600 hover:tw-bg-material-light-thin", children: [jsx(BodyText, { className: "tw-text-grey-500", size: "small", children: direction === 'from' ? 'Pay' : 'Receive' }), jsx(BodyText, { size: "small", children: ":" }), jsxs("div", { className: "tw-flex tw-items-center tw-gap-1", children: [jsx(BodyText, { size: "small", className: address ? 'tw-text-grey-300' : 'tw-text-royal-400', children: address ? address : 'Connect wallet' }), jsx(ChevronArrowIcon, { className: address ? 'tw-text-grey-600' : 'tw-text-royal-400' })] })] }) }), jsx("div", { className: "tw-px-squid-l", children: jsx(AssetsButton, { onClick: onAssetsButtonClick, chainImageUrl: chain === null || chain === void 0 ? void 0 : chain.iconUrl, tokenImageUrl: token === null || token === void 0 ? void 0 : token.iconUrl, tokenSymbol: token === null || token === void 0 ? void 0 : token.symbol, chainBgColor: chain === null || chain === void 0 ? void 0 : chain.bgColor, tokenBgColor: token === null || token === void 0 ? void 0 : token.bgColor, tokenTextColor: token === null || token === void 0 ? void 0 : token.textColor }) }), direction === 'from' ? (jsx(NumericInput, { forcedUpdateValue: forcedAmount, initialValue: amount, onParsedValueChanged: (value) => onAmountChange === null || onAmountChange === void 0 ? void 0 : onAmountChange(value) })) : (jsx("div", { className: "tw-w-full tw-px-squid-m tw-pb-[15px] tw-pt-[5px]", children: jsx("div", { className: "tw-flex tw-h-[55px] tw-w-full tw-items-center tw-rounded-squid-s tw-bg-transparent tw-px-squid-xs tw-py-squid-s tw-text-heading-small tw-font-heading-regular tw-text-grey-300", children: jsx("span", { children: amount }) }) })), !(token === null || token === void 0 ? void 0 : token.iconUrl) || isFetching ? null : (jsxs("footer", { className: "tw-flex tw-h-squid-m tw-max-h-squid-m tw-items-center tw-justify-between tw-gap-2 tw-px-squid-m tw-text-grey-500", children: [error ? (jsx("div", { className: "tw-px-squid-xs", children: jsx(ErrorMessage, { message: error.message }) })) : (jsxs("div", { className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive && 'hover:tw-bg-material-light-thin'), children: [jsx(SwapInputsIcon, {}), jsx(UsdAmount, { usdAmount: swapAmountUsd }), priceImpactPercentage && direction === 'to' ? (jsxs("span", { className: clsx('tw-flex tw-items-center', priceImpactClass), children: [jsx(ArrowTriangle, {}), jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxs(BalanceButtonTag, { onClick: onBalanceButtonClick, className: cn('tw-flex tw-h-squid-l tw-items-center tw-gap-1.5 tw-rounded-squid-s tw-px-squid-xs', isInteractive
3301
+ ? 'hover:tw-bg-material-light-thin'
3302
+ : 'tw-pointer-events-none'), children: [jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsx(CaptionText, { children: balance }), jsx(MaxIcon, {})] })] }))] }));
3154
3303
  }
3155
3304
 
3156
3305
  function SwapProgressViewHeader({ title, description, }) {
@@ -3254,4 +3403,4 @@ function SquidConfigProvider({ theme, children, themeType = 'light', }) {
3254
3403
  return (jsx("div", { style: parsedStyle, "data-squid-theme-type": themeType, className: clsx('tw-text-base-content tw-group tw-relative tw-font-geist'), children: children }));
3255
3404
  }
3256
3405
 
3257
- export { AddressButton, ArrowButton, AssetsButton, BadgeImage, BodyText, Boost, BoostButton, Button, CaptionText, Chip, DetailsToolbar, DropdownMenu, DropdownMenuItem, ErrorMessage, FeeButton, HeadingText, HistoryItem, Input, ListItem, Menu, MenuItem, Modal, NavigationBar, ProductCard, SectionTitle, SettingsButton, SettingsItem, SettingsSlider, SquidConfigProvider, SwapConfiguration, SwapDetailListItem, SwapProgressViewHeader, SwapStepItem, SwapStepsCollapsed, Switch, TokenPair, Tooltip, UsdAmount, useModal };
3406
+ export { AddressButton, ArrowButton, AssetsButton, BadgeImage, BodyText, Boost, BoostButton, Button, CaptionText, Chip, DetailsToolbar, DropdownMenu, DropdownMenuItem, ErrorMessage, FeeButton, HeadingText, HistoryItem, Input, ListItem, Menu, MenuItem, Modal, NavigationBar, NumericInput, ProductCard, SectionTitle, SettingsButton, SettingsItem, SettingsSlider, SquidConfigProvider, SwapConfiguration, SwapDetailListItem, SwapProgressViewHeader, SwapStepItem, SwapStepsCollapsed, Switch, TokenPair, Tooltip, UsdAmount, useModal };
@@ -0,0 +1,11 @@
1
+ import type { InputHTMLAttributes } from 'react';
2
+ interface Props extends InputHTMLAttributes<HTMLInputElement> {
3
+ onParsedValueChanged: (value: string) => void;
4
+ initialValue?: string;
5
+ forcedUpdateValue?: string;
6
+ maxDecimals?: number;
7
+ balance?: string;
8
+ sourceTokenUsdPrice?: number;
9
+ }
10
+ export declare const NumericInput: ({ onParsedValueChanged, initialValue, forcedUpdateValue, maxDecimals, balance, sourceTokenUsdPrice, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -1,4 +1,5 @@
1
1
  export * from './Input';
2
+ export * from './NumericInput';
2
3
  export * from './SettingsSlider';
3
4
  export * from './Switch';
4
5
  export * from './Tooltip';
@@ -1,9 +1,9 @@
1
- /// <reference types="react" />
2
1
  import { SwapDirection } from '../../types/components';
3
2
  interface SwapConfigurationProps {
4
3
  direction: SwapDirection;
5
4
  priceImpactPercentage?: string;
6
5
  amount?: string;
6
+ forcedAmount?: string;
7
7
  swapAmountUsd?: string;
8
8
  balance?: string;
9
9
  isFetching?: boolean;
@@ -18,12 +18,13 @@ interface SwapConfigurationProps {
18
18
  textColor: string;
19
19
  };
20
20
  address?: string;
21
- onAmountChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
21
+ onAmountChange?: (amount: string) => void;
22
22
  onWalletButtonClick?: () => void;
23
23
  onAssetsButtonClick?: () => void;
24
+ onBalanceButtonClick?: () => void;
24
25
  error?: {
25
26
  message: string;
26
27
  };
27
28
  }
28
- export declare function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, address, error, }: SwapConfigurationProps): import("react/jsx-runtime").JSX.Element;
29
+ export declare function SwapConfiguration({ priceImpactPercentage, amount, forcedAmount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, onBalanceButtonClick, address, error, }: SwapConfigurationProps): import("react/jsx-runtime").JSX.Element;
29
30
  export {};
@@ -8,3 +8,10 @@ import { ClassValue } from 'clsx';
8
8
  * @returns The combined class names as a string.
9
9
  */
10
10
  export declare const cn: (...inputs: ClassValue[]) => string;
11
+ type AnyFunction = (...args: any[]) => any;
12
+ interface DebouncedFunction<F extends AnyFunction> {
13
+ (...args: Parameters<F>): void;
14
+ cancel: () => void;
15
+ }
16
+ export declare function debounce<F extends AnyFunction>(func: F, delay: number): DebouncedFunction<F>;
17
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import React$1 from 'react';
3
+ import React$1, { InputHTMLAttributes } from 'react';
4
4
 
5
5
  interface BadgeImageProps {
6
6
  imageUrl?: string;
@@ -103,6 +103,16 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
103
103
  }
104
104
  declare function Input({ placeholder, showIcon, showPasteButton, className, icon, ...props }: InputProps): react_jsx_runtime.JSX.Element;
105
105
 
106
+ interface Props extends InputHTMLAttributes<HTMLInputElement> {
107
+ onParsedValueChanged: (value: string) => void;
108
+ initialValue?: string;
109
+ forcedUpdateValue?: string;
110
+ maxDecimals?: number;
111
+ balance?: string;
112
+ sourceTokenUsdPrice?: number;
113
+ }
114
+ declare const NumericInput: ({ onParsedValueChanged, initialValue, forcedUpdateValue, maxDecimals, balance, sourceTokenUsdPrice, ...props }: Props) => react_jsx_runtime.JSX.Element;
115
+
106
116
  interface SettingsSliderProps {
107
117
  value: number;
108
118
  type: 'percentage' | 'amount';
@@ -291,6 +301,7 @@ interface SwapConfigurationProps {
291
301
  direction: SwapDirection;
292
302
  priceImpactPercentage?: string;
293
303
  amount?: string;
304
+ forcedAmount?: string;
294
305
  swapAmountUsd?: string;
295
306
  balance?: string;
296
307
  isFetching?: boolean;
@@ -305,14 +316,15 @@ interface SwapConfigurationProps {
305
316
  textColor: string;
306
317
  };
307
318
  address?: string;
308
- onAmountChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
319
+ onAmountChange?: (amount: string) => void;
309
320
  onWalletButtonClick?: () => void;
310
321
  onAssetsButtonClick?: () => void;
322
+ onBalanceButtonClick?: () => void;
311
323
  error?: {
312
324
  message: string;
313
325
  };
314
326
  }
315
- declare function SwapConfiguration({ priceImpactPercentage, amount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, address, error, }: SwapConfigurationProps): react_jsx_runtime.JSX.Element;
327
+ declare function SwapConfiguration({ priceImpactPercentage, amount, forcedAmount, swapAmountUsd, balance, isFetching, chain, token, direction, onAmountChange, onWalletButtonClick, onAssetsButtonClick, onBalanceButtonClick, address, error, }: SwapConfigurationProps): react_jsx_runtime.JSX.Element;
316
328
 
317
329
  interface SwapProgressViewHeaderProps {
318
330
  title: string;
@@ -408,4 +420,4 @@ declare function useModal(props?: {
408
420
  openModalButtonRef: React.RefObject<HTMLButtonElement>;
409
421
  };
410
422
 
411
- export { AddressButton, ArrowButton, AssetsButton, BadgeImage, BodyText, Boost, BoostButton, Button, CaptionText, Chip, DetailsToolbar, DropdownMenu, DropdownMenuItem, type DropdownMenuItemProps, ErrorMessage, FeeButton, HeadingText, HistoryItem, Input, ListItem, Menu, MenuItem, Modal, NavigationBar, ProductCard, SectionTitle, SettingsButton, type SettingsButtonProps, SettingsItem, type SettingsItemProps, SettingsSlider, type SettingsSliderProps, SquidConfigProvider, SwapConfiguration, SwapDetailListItem, SwapProgressViewHeader, SwapStepItem, SwapStepsCollapsed, Switch, TokenPair, Tooltip, type TooltipThreshold, type TooltipWidth, UsdAmount, useModal };
423
+ export { AddressButton, ArrowButton, AssetsButton, BadgeImage, BodyText, Boost, BoostButton, Button, CaptionText, Chip, DetailsToolbar, DropdownMenu, DropdownMenuItem, type DropdownMenuItemProps, ErrorMessage, FeeButton, HeadingText, HistoryItem, Input, ListItem, Menu, MenuItem, Modal, NavigationBar, NumericInput, ProductCard, SectionTitle, SettingsButton, type SettingsButtonProps, SettingsItem, type SettingsItemProps, SettingsSlider, type SettingsSliderProps, SquidConfigProvider, SwapConfiguration, SwapDetailListItem, SwapProgressViewHeader, SwapStepItem, SwapStepsCollapsed, Switch, TokenPair, Tooltip, type TooltipThreshold, type TooltipWidth, UsdAmount, useModal };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "git+https://github.com/0xsquid/squid-ui.git"
6
6
  },
7
7
  "description": "Squid's UI components",
8
- "version": "0.7.3",
8
+ "version": "0.7.4",
9
9
  "author": "",
10
10
  "license": "MIT",
11
11
  "scripts": {