@0xsquid/ui 0.15.6 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -2918,11 +2918,12 @@ function SearchIcon() {
2918
2918
  }
2919
2919
 
2920
2920
  function Input(_a) {
2921
- var { placeholder = 'Search', showIcon = true, showPasteButton = false, className, icon, isError = false, onPasteButtonClick, containerClassName } = _a, props = __rest(_a, ["placeholder", "showIcon", "showPasteButton", "className", "icon", "isError", "onPasteButtonClick", "containerClassName"]);
2922
- return (jsxRuntime.jsxs("div", { className: cn('tw-relative tw-w-full tw-text-grey-600', containerClassName), children: [jsxRuntime.jsx("input", Object.assign({}, props, { "aria-invalid": isError, className: cn('tw-relative tw-h-10 tw-w-full tw-rounded-full tw-border tw-border-material-light-thin tw-bg-grey-900 tw-text-body-small tw-font-typography-regular tw-text-grey-300 placeholder:tw-text-grey-600 invalid:tw-outline-status-negative', showIcon ? 'tw-pl-[44px]' : 'tw-px-2.5', showPasteButton ? 'tw-px-[70px]' : 'tw-pr-2.5', isError && '!tw-outline-status-negative', className), placeholder: placeholder })), showIcon ? (jsxRuntime.jsx("div", { className: "tw-absolute tw-inset-y-0 tw-left-0 tw-flex tw-h-full tw-w-[44px] tw-items-center tw-justify-center tw-px-squid-xs", children: icon || jsxRuntime.jsx(SearchIcon, {}) })) : null, showPasteButton ? (jsxRuntime.jsx("div", { className: "tw-absolute tw-inset-y-0 tw-right-1.5 tw-flex tw-items-center tw-justify-center", children: jsxRuntime.jsx(PasteButton, { onClick: onPasteButtonClick }) })) : null] }));
2921
+ var { placeholder = 'Search', showIcon = true, className, icon, isError = false, containerClassName, actionButtonProps } = _a, props = __rest(_a, ["placeholder", "showIcon", "className", "icon", "isError", "containerClassName", "actionButtonProps"]);
2922
+ const showActionButton = !!actionButtonProps;
2923
+ return (jsxRuntime.jsxs("div", { className: cn('tw-relative tw-w-full tw-text-grey-600', containerClassName), children: [jsxRuntime.jsx("input", Object.assign({}, props, { "aria-invalid": isError, className: cn('tw-relative tw-h-10 tw-w-full tw-rounded-full tw-border tw-border-material-light-thin tw-bg-grey-900 tw-text-body-small tw-font-typography-regular tw-text-grey-300 placeholder:tw-text-grey-600 invalid:tw-outline-status-negative', showIcon ? 'tw-pl-[40px]' : 'tw-px-2.5', showActionButton ? 'tw-pr-[70px]' : 'tw-pr-2.5', isError && '!tw-outline-status-negative', className), placeholder: placeholder })), showIcon ? (jsxRuntime.jsx("div", { className: "tw-absolute tw-inset-y-0 tw-left-0 tw-flex tw-h-full tw-w-[44px] tw-items-center tw-justify-center tw-px-squid-xs", children: icon || jsxRuntime.jsx(SearchIcon, {}) })) : null, showActionButton ? (jsxRuntime.jsx("div", { className: "tw-absolute tw-inset-y-0 tw-right-1.5 tw-flex tw-items-center tw-justify-center", children: jsxRuntime.jsx(InputActionButton, Object.assign({}, actionButtonProps)) })) : null] }));
2923
2924
  }
2924
- const PasteButton = ({ onClick }) => {
2925
- return (jsxRuntime.jsx(Button, { size: "md", variant: "tertiary", onClick: onClick, className: "!tw-h-[30px] !tw-w-fit tw-min-w-0 !tw-px-2", children: jsxRuntime.jsx(CaptionText, { children: "Paste" }) }));
2925
+ const InputActionButton = ({ onClick, variant = 'tertiary', label = 'Paste', }) => {
2926
+ return (jsxRuntime.jsx(Button, { size: "md", variant: variant, onClick: onClick, className: "!tw-h-[30px] !tw-w-fit !tw-min-w-0", children: jsxRuntime.jsx(CaptionText, { children: label }) }));
2926
2927
  };
2927
2928
 
2928
2929
  /*
@@ -7154,18 +7155,65 @@ function NumericInput({ priceImpactPercentage, balance = '0', error, criticalPri
7154
7155
  : amountFormatted }), ' ', jsxRuntime.jsx(CaptionText, { className: "tw-opacity-66", children: token.symbol })] })), priceImpactPercentage && direction === 'to' ? (jsxRuntime.jsxs("span", { className: cn('tw-flex tw-items-center', priceImpactClass), children: [jsxRuntime.jsx(ArrowTriangle, {}), jsxRuntime.jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxRuntime.jsxs(BalanceChipTag, { onClick: onBalanceButtonClick, className: cn(buttonClassName, isInteractive && interactiveChipClassName), children: [jsxRuntime.jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsxRuntime.jsxs(CaptionText, { children: [balanceFormatted, " ", token.symbol] }), jsxRuntime.jsx(MaxIcon, {})] })] }))] }));
7155
7156
  }
7156
7157
 
7157
- function SettingsSlider({ value, type, onChange, hasDecimals, max, min, }) {
7158
- return (jsxRuntime.jsxs("div", { className: "tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-rounded-squid-xs", children: [jsxRuntime.jsx("input", { min: min !== null && min !== void 0 ? min : 0, max: max !== null && max !== void 0 ? max : 99, step: hasDecimals ? 0.1 : 1, placeholder: "0", type: "number", onChange: (e) => {
7159
- onChange === null || onChange === void 0 ? void 0 : onChange(Number(e.target.value));
7160
- }, className: cn('tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-self-stretch tw-rounded-squid-xs tw-bg-transparent tw-p-squid-xs tw-text-caption !tw-font-medium tw-leading-[10px] tw-text-grey-300 placeholder-shown:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin', type === 'percentage'
7161
- ? 'tw-w-[84px] tw-pr-[52px] tw-text-right'
7162
- : 'tw-w-[80px] tw-pl-[20px] tw-pr-[32px] tw-text-left'), value: value }), type === 'percentage' && jsxRuntime.jsx(PercentageDecorator, {}), type === 'amount' && jsxRuntime.jsx(AmountDecorator, {})] }));
7163
- }
7164
- function PercentageDecorator() {
7165
- return (jsxRuntime.jsxs("div", { className: "tw-absolute tw-right-squid-xs tw-flex tw-items-center tw-justify-center tw-gap-squid-xs !tw-font-medium tw-leading-[10px]", children: [jsxRuntime.jsx(CaptionText, { className: "tw-translate-y-[0.5px] !tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: "%" }), jsxRuntime.jsx(Chip, { icon: jsxRuntime.jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) })] }));
7166
- }
7167
- function AmountDecorator() {
7168
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(CaptionText, { className: "tw-absolute tw-left-squid-xs tw-translate-y-[0.5px] !tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: "$" }), jsxRuntime.jsx("div", { className: "tw-absolute tw-right-squid-xs tw-flex tw-items-center tw-justify-center tw-gap-squid-xs !tw-font-medium tw-leading-[10px]", children: jsxRuntime.jsx(Chip, { icon: jsxRuntime.jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) }) })] }));
7158
+ function SettingsSlider({ value, type, onChange, decimalsFormat, max, min, }) {
7159
+ const [isInputVisible, setIsInputVisible] = React.useState(false);
7160
+ const [inputValue, setInputValue] = React.useState(String(value !== null && value !== void 0 ? value : 0));
7161
+ React.useEffect(() => {
7162
+ if (!isInputVisible)
7163
+ return;
7164
+ const handleOutsideClick = (event) => {
7165
+ var _a;
7166
+ const clickedElementIsDifferentThanMenu = event.target !== menuRef.current;
7167
+ const clickedElementIsDifferentThanSlider = event.target !== sliderRef.current;
7168
+ const sliderContainsClickedElement = (_a = sliderRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target);
7169
+ const hideInput = clickedElementIsDifferentThanMenu &&
7170
+ (!clickedElementIsDifferentThanSlider || !sliderContainsClickedElement);
7171
+ if (hideInput) {
7172
+ handleCloseInput();
7173
+ }
7174
+ };
7175
+ document.addEventListener('click', handleOutsideClick);
7176
+ return () => {
7177
+ document.removeEventListener('click', handleOutsideClick);
7178
+ };
7179
+ }, [isInputVisible]);
7180
+ const menuRef = React.useRef(null);
7181
+ const sliderRef = React.useRef(null);
7182
+ const handleSubmit = React.useCallback((value) => {
7183
+ handleCloseInput();
7184
+ onChange === null || onChange === void 0 ? void 0 : onChange(value === '' ? undefined : Number(value));
7185
+ }, [onChange]);
7186
+ const handleKeyDown = React.useCallback((e) => {
7187
+ // block unwanted (but still valid) characters
7188
+ if (['e', 'E', '+', '-'].includes(e.key))
7189
+ return e.preventDefault();
7190
+ // close input when pressing escape
7191
+ if (e.key === 'Escape')
7192
+ return handleCloseInput();
7193
+ }, []);
7194
+ const handleOpenInput = React.useCallback(() => {
7195
+ setIsInputVisible(true);
7196
+ }, []);
7197
+ const handleCloseInput = React.useCallback(() => {
7198
+ setIsInputVisible(false);
7199
+ }, []);
7200
+ return (jsxRuntime.jsxs("div", { ref: sliderRef, className: "tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-rounded-squid-xs", children: [jsxRuntime.jsxs("button", { className: cn('tw-relative tw-flex tw-h-[32px] tw-items-center tw-justify-center tw-self-stretch tw-rounded-squid-xs tw-p-squid-xs tw-pr-[40px] tw-text-left tw-text-caption !tw-font-medium tw-leading-[10px] placeholder-shown:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin', value === 0 || value === undefined
7201
+ ? 'tw-text-grey-600'
7202
+ : 'tw-text-grey-300', isInputVisible ? 'tw-bg-material-light-thin' : 'tw-bg-transparent'), children: [value !== null && value !== void 0 ? value : 0, jsxRuntime.jsx(CaptionText, { className: "!tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: type === 'percentage' ? '%' : '$' })] }), jsxRuntime.jsx("button", { onClick: handleOpenInput, className: "tw-absolute tw-right-squid-xs tw-flex tw-h-[26px] tw-w-[26px] tw-items-center tw-justify-center tw-gap-squid-xs tw-rounded-squid-xxs !tw-font-medium tw-leading-[10px] hover:tw-bg-material-light-thin", children: jsxRuntime.jsx(Chip, { icon: jsxRuntime.jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) }) }), isInputVisible && (jsxRuntime.jsx(Menu, { menuRef: menuRef, containerClassName: "tw-absolute tw-bottom-full tw-z-10 tw-pb-squid-m tw-w-[160px]", children: jsxRuntime.jsx("form", { onSubmit: (e) => {
7203
+ e.preventDefault();
7204
+ handleSubmit(inputValue);
7205
+ }, children: jsxRuntime.jsx(Input, { autoFocus: true, min: min, max: max, onKeyDown: handleKeyDown, step: decimalsFormat, placeholder: "0", type: "number", defaultValue: value, value: inputValue, onChange: (e) => {
7206
+ const isValid = e.target.checkValidity();
7207
+ if (!isValid)
7208
+ return;
7209
+ setInputValue(e.target.value);
7210
+ }, showIcon: false, actionButtonProps: {
7211
+ label: 'Ok',
7212
+ onClick: () => {
7213
+ handleSubmit(inputValue);
7214
+ },
7215
+ variant: 'primary',
7216
+ } }) }) }))] }));
7169
7217
  }
7170
7218
 
7171
7219
  const switchSizeClassMap = {
@@ -1,12 +1,17 @@
1
1
  /// <reference types="react" />
2
+ import { ButtonVariant } from '../../types/components';
2
3
  interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
4
  placeholder?: string;
4
5
  showIcon?: boolean;
5
- showPasteButton?: boolean;
6
6
  icon?: React.ReactNode;
7
7
  isError?: boolean;
8
- onPasteButtonClick?: () => void;
9
8
  containerClassName?: string;
9
+ actionButtonProps?: InputActionButtonProps;
10
10
  }
11
- export declare function Input({ placeholder, showIcon, showPasteButton, className, icon, isError, onPasteButtonClick, containerClassName, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function Input({ placeholder, showIcon, className, icon, isError, containerClassName, actionButtonProps, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
12
+ type InputActionButtonProps = {
13
+ onClick?: () => void;
14
+ variant?: ButtonVariant;
15
+ label?: string;
16
+ };
12
17
  export {};
@@ -1,9 +1,9 @@
1
1
  export interface SettingsSliderProps {
2
2
  value: number;
3
3
  type: 'percentage' | 'amount';
4
- onChange?: (value: number) => void;
5
- hasDecimals?: boolean;
4
+ onChange?: (value: number | undefined) => void;
5
+ decimalsFormat?: number;
6
6
  min?: number;
7
7
  max?: number;
8
8
  }
9
- export declare function SettingsSlider({ value, type, onChange, hasDecimals, max, min, }: SettingsSliderProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function SettingsSlider({ value, type, onChange, decimalsFormat, max, min, }: SettingsSliderProps): import("react/jsx-runtime").JSX.Element;
@@ -5,5 +5,5 @@ export default meta;
5
5
  type Story = StoryObj<typeof meta>;
6
6
  export declare const Default: Story;
7
7
  export declare const WithoutIcon: Story;
8
- export declare const WithPasteButton: Story;
8
+ export declare const WithActionButton: Story;
9
9
  export declare const Error: Story;
@@ -5,3 +5,7 @@ export default meta;
5
5
  type Story = StoryObj<typeof meta>;
6
6
  export declare const Percentage: Story;
7
7
  export declare const Amount: Story;
8
+ export declare const PercentageWith1DecimalPlaceAllowed: Story;
9
+ export declare const AmountWith2DecimalPlacesAllowed: Story;
10
+ export declare const PercentageMax50: Story;
11
+ export declare const AmountMax999: Story;
package/dist/esm/index.js CHANGED
@@ -2898,11 +2898,12 @@ function SearchIcon() {
2898
2898
  }
2899
2899
 
2900
2900
  function Input(_a) {
2901
- var { placeholder = 'Search', showIcon = true, showPasteButton = false, className, icon, isError = false, onPasteButtonClick, containerClassName } = _a, props = __rest(_a, ["placeholder", "showIcon", "showPasteButton", "className", "icon", "isError", "onPasteButtonClick", "containerClassName"]);
2902
- return (jsxs("div", { className: cn('tw-relative tw-w-full tw-text-grey-600', containerClassName), children: [jsx("input", Object.assign({}, props, { "aria-invalid": isError, className: cn('tw-relative tw-h-10 tw-w-full tw-rounded-full tw-border tw-border-material-light-thin tw-bg-grey-900 tw-text-body-small tw-font-typography-regular tw-text-grey-300 placeholder:tw-text-grey-600 invalid:tw-outline-status-negative', showIcon ? 'tw-pl-[44px]' : 'tw-px-2.5', showPasteButton ? 'tw-px-[70px]' : 'tw-pr-2.5', isError && '!tw-outline-status-negative', className), placeholder: placeholder })), showIcon ? (jsx("div", { className: "tw-absolute tw-inset-y-0 tw-left-0 tw-flex tw-h-full tw-w-[44px] tw-items-center tw-justify-center tw-px-squid-xs", children: icon || jsx(SearchIcon, {}) })) : null, showPasteButton ? (jsx("div", { className: "tw-absolute tw-inset-y-0 tw-right-1.5 tw-flex tw-items-center tw-justify-center", children: jsx(PasteButton, { onClick: onPasteButtonClick }) })) : null] }));
2901
+ var { placeholder = 'Search', showIcon = true, className, icon, isError = false, containerClassName, actionButtonProps } = _a, props = __rest(_a, ["placeholder", "showIcon", "className", "icon", "isError", "containerClassName", "actionButtonProps"]);
2902
+ const showActionButton = !!actionButtonProps;
2903
+ return (jsxs("div", { className: cn('tw-relative tw-w-full tw-text-grey-600', containerClassName), children: [jsx("input", Object.assign({}, props, { "aria-invalid": isError, className: cn('tw-relative tw-h-10 tw-w-full tw-rounded-full tw-border tw-border-material-light-thin tw-bg-grey-900 tw-text-body-small tw-font-typography-regular tw-text-grey-300 placeholder:tw-text-grey-600 invalid:tw-outline-status-negative', showIcon ? 'tw-pl-[40px]' : 'tw-px-2.5', showActionButton ? 'tw-pr-[70px]' : 'tw-pr-2.5', isError && '!tw-outline-status-negative', className), placeholder: placeholder })), showIcon ? (jsx("div", { className: "tw-absolute tw-inset-y-0 tw-left-0 tw-flex tw-h-full tw-w-[44px] tw-items-center tw-justify-center tw-px-squid-xs", children: icon || jsx(SearchIcon, {}) })) : null, showActionButton ? (jsx("div", { className: "tw-absolute tw-inset-y-0 tw-right-1.5 tw-flex tw-items-center tw-justify-center", children: jsx(InputActionButton, Object.assign({}, actionButtonProps)) })) : null] }));
2903
2904
  }
2904
- const PasteButton = ({ onClick }) => {
2905
- return (jsx(Button, { size: "md", variant: "tertiary", onClick: onClick, className: "!tw-h-[30px] !tw-w-fit tw-min-w-0 !tw-px-2", children: jsx(CaptionText, { children: "Paste" }) }));
2905
+ const InputActionButton = ({ onClick, variant = 'tertiary', label = 'Paste', }) => {
2906
+ return (jsx(Button, { size: "md", variant: variant, onClick: onClick, className: "!tw-h-[30px] !tw-w-fit !tw-min-w-0", children: jsx(CaptionText, { children: label }) }));
2906
2907
  };
2907
2908
 
2908
2909
  /*
@@ -7134,18 +7135,65 @@ function NumericInput({ priceImpactPercentage, balance = '0', error, criticalPri
7134
7135
  : amountFormatted }), ' ', jsx(CaptionText, { className: "tw-opacity-66", children: token.symbol })] })), priceImpactPercentage && direction === 'to' ? (jsxs("span", { className: cn('tw-flex tw-items-center', priceImpactClass), children: [jsx(ArrowTriangle, {}), jsx(CaptionText, { bold: true, children: priceImpactPercentage.toString().concat('%') })] })) : null] })), jsxs(BalanceChipTag, { onClick: onBalanceButtonClick, className: cn(buttonClassName, isInteractive && interactiveChipClassName), children: [jsx(CaptionText, { className: "tw-opacity-66", children: "Balance" }), jsxs(CaptionText, { children: [balanceFormatted, " ", token.symbol] }), jsx(MaxIcon, {})] })] }))] }));
7135
7136
  }
7136
7137
 
7137
- function SettingsSlider({ value, type, onChange, hasDecimals, max, min, }) {
7138
- return (jsxs("div", { className: "tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-rounded-squid-xs", children: [jsx("input", { min: min !== null && min !== void 0 ? min : 0, max: max !== null && max !== void 0 ? max : 99, step: hasDecimals ? 0.1 : 1, placeholder: "0", type: "number", onChange: (e) => {
7139
- onChange === null || onChange === void 0 ? void 0 : onChange(Number(e.target.value));
7140
- }, className: cn('tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-self-stretch tw-rounded-squid-xs tw-bg-transparent tw-p-squid-xs tw-text-caption !tw-font-medium tw-leading-[10px] tw-text-grey-300 placeholder-shown:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin', type === 'percentage'
7141
- ? 'tw-w-[84px] tw-pr-[52px] tw-text-right'
7142
- : 'tw-w-[80px] tw-pl-[20px] tw-pr-[32px] tw-text-left'), value: value }), type === 'percentage' && jsx(PercentageDecorator, {}), type === 'amount' && jsx(AmountDecorator, {})] }));
7143
- }
7144
- function PercentageDecorator() {
7145
- return (jsxs("div", { className: "tw-absolute tw-right-squid-xs tw-flex tw-items-center tw-justify-center tw-gap-squid-xs !tw-font-medium tw-leading-[10px]", children: [jsx(CaptionText, { className: "tw-translate-y-[0.5px] !tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: "%" }), jsx(Chip, { icon: jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) })] }));
7146
- }
7147
- function AmountDecorator() {
7148
- return (jsxs(Fragment, { children: [jsx(CaptionText, { className: "tw-absolute tw-left-squid-xs tw-translate-y-[0.5px] !tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: "$" }), jsx("div", { className: "tw-absolute tw-right-squid-xs tw-flex tw-items-center tw-justify-center tw-gap-squid-xs !tw-font-medium tw-leading-[10px]", children: jsx(Chip, { icon: jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) }) })] }));
7138
+ function SettingsSlider({ value, type, onChange, decimalsFormat, max, min, }) {
7139
+ const [isInputVisible, setIsInputVisible] = useState(false);
7140
+ const [inputValue, setInputValue] = useState(String(value !== null && value !== void 0 ? value : 0));
7141
+ useEffect(() => {
7142
+ if (!isInputVisible)
7143
+ return;
7144
+ const handleOutsideClick = (event) => {
7145
+ var _a;
7146
+ const clickedElementIsDifferentThanMenu = event.target !== menuRef.current;
7147
+ const clickedElementIsDifferentThanSlider = event.target !== sliderRef.current;
7148
+ const sliderContainsClickedElement = (_a = sliderRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target);
7149
+ const hideInput = clickedElementIsDifferentThanMenu &&
7150
+ (!clickedElementIsDifferentThanSlider || !sliderContainsClickedElement);
7151
+ if (hideInput) {
7152
+ handleCloseInput();
7153
+ }
7154
+ };
7155
+ document.addEventListener('click', handleOutsideClick);
7156
+ return () => {
7157
+ document.removeEventListener('click', handleOutsideClick);
7158
+ };
7159
+ }, [isInputVisible]);
7160
+ const menuRef = useRef(null);
7161
+ const sliderRef = useRef(null);
7162
+ const handleSubmit = useCallback((value) => {
7163
+ handleCloseInput();
7164
+ onChange === null || onChange === void 0 ? void 0 : onChange(value === '' ? undefined : Number(value));
7165
+ }, [onChange]);
7166
+ const handleKeyDown = useCallback((e) => {
7167
+ // block unwanted (but still valid) characters
7168
+ if (['e', 'E', '+', '-'].includes(e.key))
7169
+ return e.preventDefault();
7170
+ // close input when pressing escape
7171
+ if (e.key === 'Escape')
7172
+ return handleCloseInput();
7173
+ }, []);
7174
+ const handleOpenInput = useCallback(() => {
7175
+ setIsInputVisible(true);
7176
+ }, []);
7177
+ const handleCloseInput = useCallback(() => {
7178
+ setIsInputVisible(false);
7179
+ }, []);
7180
+ return (jsxs("div", { ref: sliderRef, className: "tw-relative tw-flex tw-h-full tw-items-center tw-justify-center tw-rounded-squid-xs", children: [jsxs("button", { className: cn('tw-relative tw-flex tw-h-[32px] tw-items-center tw-justify-center tw-self-stretch tw-rounded-squid-xs tw-p-squid-xs tw-pr-[40px] tw-text-left tw-text-caption !tw-font-medium tw-leading-[10px] placeholder-shown:tw-text-grey-600 hover:tw-bg-material-light-thin focus:tw-bg-material-light-thin', value === 0 || value === undefined
7181
+ ? 'tw-text-grey-600'
7182
+ : 'tw-text-grey-300', isInputVisible ? 'tw-bg-material-light-thin' : 'tw-bg-transparent'), children: [value !== null && value !== void 0 ? value : 0, jsx(CaptionText, { className: "!tw-font-medium !tw-leading-[10px] tw-text-grey-300", children: type === 'percentage' ? '%' : '$' })] }), jsx("button", { onClick: handleOpenInput, className: "tw-absolute tw-right-squid-xs tw-flex tw-h-[26px] tw-w-[26px] tw-items-center tw-justify-center tw-gap-squid-xs tw-rounded-squid-xxs !tw-font-medium tw-leading-[10px] hover:tw-bg-material-light-thin", children: jsx(Chip, { icon: jsx(ChevronGrabberVerticalIcon, { className: "tw-text-grey-900" }) }) }), isInputVisible && (jsx(Menu, { menuRef: menuRef, containerClassName: "tw-absolute tw-bottom-full tw-z-10 tw-pb-squid-m tw-w-[160px]", children: jsx("form", { onSubmit: (e) => {
7183
+ e.preventDefault();
7184
+ handleSubmit(inputValue);
7185
+ }, children: jsx(Input, { autoFocus: true, min: min, max: max, onKeyDown: handleKeyDown, step: decimalsFormat, placeholder: "0", type: "number", defaultValue: value, value: inputValue, onChange: (e) => {
7186
+ const isValid = e.target.checkValidity();
7187
+ if (!isValid)
7188
+ return;
7189
+ setInputValue(e.target.value);
7190
+ }, showIcon: false, actionButtonProps: {
7191
+ label: 'Ok',
7192
+ onClick: () => {
7193
+ handleSubmit(inputValue);
7194
+ },
7195
+ variant: 'primary',
7196
+ } }) }) }))] }));
7149
7197
  }
7150
7198
 
7151
7199
  const switchSizeClassMap = {
@@ -1,12 +1,17 @@
1
1
  /// <reference types="react" />
2
+ import { ButtonVariant } from '../../types/components';
2
3
  interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
4
  placeholder?: string;
4
5
  showIcon?: boolean;
5
- showPasteButton?: boolean;
6
6
  icon?: React.ReactNode;
7
7
  isError?: boolean;
8
- onPasteButtonClick?: () => void;
9
8
  containerClassName?: string;
9
+ actionButtonProps?: InputActionButtonProps;
10
10
  }
11
- export declare function Input({ placeholder, showIcon, showPasteButton, className, icon, isError, onPasteButtonClick, containerClassName, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function Input({ placeholder, showIcon, className, icon, isError, containerClassName, actionButtonProps, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
12
+ type InputActionButtonProps = {
13
+ onClick?: () => void;
14
+ variant?: ButtonVariant;
15
+ label?: string;
16
+ };
12
17
  export {};
@@ -1,9 +1,9 @@
1
1
  export interface SettingsSliderProps {
2
2
  value: number;
3
3
  type: 'percentage' | 'amount';
4
- onChange?: (value: number) => void;
5
- hasDecimals?: boolean;
4
+ onChange?: (value: number | undefined) => void;
5
+ decimalsFormat?: number;
6
6
  min?: number;
7
7
  max?: number;
8
8
  }
9
- export declare function SettingsSlider({ value, type, onChange, hasDecimals, max, min, }: SettingsSliderProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function SettingsSlider({ value, type, onChange, decimalsFormat, max, min, }: SettingsSliderProps): import("react/jsx-runtime").JSX.Element;
@@ -5,5 +5,5 @@ export default meta;
5
5
  type Story = StoryObj<typeof meta>;
6
6
  export declare const Default: Story;
7
7
  export declare const WithoutIcon: Story;
8
- export declare const WithPasteButton: Story;
8
+ export declare const WithActionButton: Story;
9
9
  export declare const Error: Story;
@@ -5,3 +5,7 @@ export default meta;
5
5
  type Story = StoryObj<typeof meta>;
6
6
  export declare const Percentage: Story;
7
7
  export declare const Amount: Story;
8
+ export declare const PercentageWith1DecimalPlaceAllowed: Story;
9
+ export declare const AmountWith2DecimalPlacesAllowed: Story;
10
+ export declare const PercentageMax50: Story;
11
+ export declare const AmountMax999: Story;
package/dist/index.css CHANGED
@@ -693,10 +693,6 @@ video {
693
693
  left: 1.875rem;
694
694
  }
695
695
 
696
- .tw-left-squid-xs {
697
- left: 0.625rem;
698
- }
699
-
700
696
  .tw-right-0 {
701
697
  right: 0px;
702
698
  }
@@ -928,10 +924,18 @@ video {
928
924
  height: 240px;
929
925
  }
930
926
 
927
+ .tw-h-\[26px\] {
928
+ height: 26px;
929
+ }
930
+
931
931
  .tw-h-\[30px\] {
932
932
  height: 30px;
933
933
  }
934
934
 
935
+ .tw-h-\[32px\] {
936
+ height: 32px;
937
+ }
938
+
935
939
  .tw-h-\[40px\] {
936
940
  height: 40px;
937
941
  }
@@ -1157,6 +1161,10 @@ video {
1157
1161
  width: 150px;
1158
1162
  }
1159
1163
 
1164
+ .tw-w-\[160px\] {
1165
+ width: 160px;
1166
+ }
1167
+
1160
1168
  .tw-w-\[180px\] {
1161
1169
  width: 180px;
1162
1170
  }
@@ -1169,6 +1177,10 @@ video {
1169
1177
  width: 22px;
1170
1178
  }
1171
1179
 
1180
+ .tw-w-\[26px\] {
1181
+ width: 26px;
1182
+ }
1183
+
1172
1184
  .tw-w-\[299px\] {
1173
1185
  width: 299px;
1174
1186
  }
@@ -1229,14 +1241,6 @@ video {
1229
1241
  width: 72px;
1230
1242
  }
1231
1243
 
1232
- .tw-w-\[80px\] {
1233
- width: 80px;
1234
- }
1235
-
1236
- .tw-w-\[84px\] {
1237
- width: 84px;
1238
- }
1239
-
1240
1244
  .tw-w-\[90px\] {
1241
1245
  width: 90px;
1242
1246
  }
@@ -1287,8 +1291,8 @@ video {
1287
1291
  width: 3.75rem;
1288
1292
  }
1289
1293
 
1290
- .tw-min-w-0 {
1291
- min-width: 0px;
1294
+ .\!tw-min-w-0 {
1295
+ min-width: 0px !important;
1292
1296
  }
1293
1297
 
1294
1298
  .tw-min-w-96 {
@@ -1378,11 +1382,6 @@ video {
1378
1382
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1379
1383
  }
1380
1384
 
1381
- .tw-translate-y-\[0\.5px\] {
1382
- --tw-translate-y: 0.5px;
1383
- transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1384
- }
1385
-
1386
1385
  .tw-rotate-180 {
1387
1386
  --tw-rotate: 180deg;
1388
1387
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -2037,11 +2036,6 @@ video {
2037
2036
  padding: 3.75rem;
2038
2037
  }
2039
2038
 
2040
- .\!tw-px-2 {
2041
- padding-left: 0.5rem !important;
2042
- padding-right: 0.5rem !important;
2043
- }
2044
-
2045
2039
  .\!tw-px-4 {
2046
2040
  padding-left: 1rem !important;
2047
2041
  padding-right: 1rem !important;
@@ -2082,11 +2076,6 @@ video {
2082
2076
  padding-right: 3px;
2083
2077
  }
2084
2078
 
2085
- .tw-px-\[70px\] {
2086
- padding-left: 70px;
2087
- padding-right: 70px;
2088
- }
2089
-
2090
2079
  .tw-px-squid-l {
2091
2080
  padding-left: 1.875rem;
2092
2081
  padding-right: 1.875rem;
@@ -2188,16 +2177,12 @@ video {
2188
2177
  padding-left: 0.25rem;
2189
2178
  }
2190
2179
 
2191
- .tw-pl-\[20px\] {
2192
- padding-left: 20px;
2193
- }
2194
-
2195
2180
  .tw-pl-\[33px\] {
2196
2181
  padding-left: 33px;
2197
2182
  }
2198
2183
 
2199
- .tw-pl-\[44px\] {
2200
- padding-left: 44px;
2184
+ .tw-pl-\[40px\] {
2185
+ padding-left: 40px;
2201
2186
  }
2202
2187
 
2203
2188
  .tw-pl-\[7px\] {
@@ -2228,12 +2213,12 @@ video {
2228
2213
  padding-right: 1rem;
2229
2214
  }
2230
2215
 
2231
- .tw-pr-\[32px\] {
2232
- padding-right: 32px;
2216
+ .tw-pr-\[40px\] {
2217
+ padding-right: 40px;
2233
2218
  }
2234
2219
 
2235
- .tw-pr-\[52px\] {
2236
- padding-right: 52px;
2220
+ .tw-pr-\[70px\] {
2221
+ padding-right: 70px;
2237
2222
  }
2238
2223
 
2239
2224
  .tw-pr-squid-m {
package/dist/index.d.ts CHANGED
@@ -124,13 +124,17 @@ declare function SettingsButton({ label, isSelected, onClick, }: SettingsButtonP
124
124
  interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
125
125
  placeholder?: string;
126
126
  showIcon?: boolean;
127
- showPasteButton?: boolean;
128
127
  icon?: React.ReactNode;
129
128
  isError?: boolean;
130
- onPasteButtonClick?: () => void;
131
129
  containerClassName?: string;
130
+ actionButtonProps?: InputActionButtonProps;
132
131
  }
133
- declare function Input({ placeholder, showIcon, showPasteButton, className, icon, isError, onPasteButtonClick, containerClassName, ...props }: InputProps): react_jsx_runtime.JSX.Element;
132
+ declare function Input({ placeholder, showIcon, className, icon, isError, containerClassName, actionButtonProps, ...props }: InputProps): react_jsx_runtime.JSX.Element;
133
+ type InputActionButtonProps = {
134
+ onClick?: () => void;
135
+ variant?: ButtonVariant;
136
+ label?: string;
137
+ };
134
138
 
135
139
  interface Token$1 {
136
140
  price: number;
@@ -165,12 +169,12 @@ declare function NumericInput({ priceImpactPercentage, balance, error, criticalP
165
169
  interface SettingsSliderProps {
166
170
  value: number;
167
171
  type: 'percentage' | 'amount';
168
- onChange?: (value: number) => void;
169
- hasDecimals?: boolean;
172
+ onChange?: (value: number | undefined) => void;
173
+ decimalsFormat?: number;
170
174
  min?: number;
171
175
  max?: number;
172
176
  }
173
- declare function SettingsSlider({ value, type, onChange, hasDecimals, max, min, }: SettingsSliderProps): react_jsx_runtime.JSX.Element;
177
+ declare function SettingsSlider({ value, type, onChange, decimalsFormat, max, min, }: SettingsSliderProps): react_jsx_runtime.JSX.Element;
174
178
 
175
179
  interface SwitchProps {
176
180
  checked?: boolean;
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.15.6",
8
+ "version": "0.16.0",
9
9
  "author": "",
10
10
  "license": "MIT",
11
11
  "resolutions": {