diff --git a/packages/components/src/Dialog/Dialog.style.tsx b/packages/components/src/Dialog/Dialog.style.tsx index fa065881b..94b701a69 100644 --- a/packages/components/src/Dialog/Dialog.style.tsx +++ b/packages/components/src/Dialog/Dialog.style.tsx @@ -15,6 +15,7 @@ const StyledDialog = styled.section` position: relative; outline: none; + width: 100%; ${({ theme, $size }) => css` ${theme.dialog.base} ${theme.dialog.size[$size]} diff --git a/packages/components/src/Field/Field.style.tsx b/packages/components/src/Field/Field.style.tsx index c3e537909..b56da511c 100644 --- a/packages/components/src/Field/Field.style.tsx +++ b/packages/components/src/Field/Field.style.tsx @@ -9,6 +9,7 @@ const StyledField = styled.div` position: relative; box-sizing: border-box; display: inline-flex; + height: 100%; max-width: ${({ $maxWidth, theme }) => $maxWidth && theme.spacing($maxWidth)}; `; diff --git a/packages/components/src/Flex/Flex.style.tsx b/packages/components/src/Flex/Flex.style.tsx index e709a906f..2e79582e8 100644 --- a/packages/components/src/Flex/Flex.style.tsx +++ b/packages/components/src/Flex/Flex.style.tsx @@ -6,7 +6,7 @@ import { StyledMarginProps } from '@interlay/hooks'; import { marginCSS } from '../utils/margin'; type StyledFlexProps = { - $gap: Spacing; + $gap?: Spacing; $justifyContent?: JustifyContent; $alignItems?: AlignItems; $direction?: Direction; @@ -20,7 +20,7 @@ const StyledFlex = styled.div` flex-direction: ${(props) => props.$direction}; justify-content: ${(props) => props.$justifyContent}; align-items: ${(props) => props.$alignItems}; - gap: ${({ theme, $gap }) => theme.spacing($gap)}; + gap: ${({ theme, $gap }) => $gap && theme.spacing($gap)}; flex: ${(props) => props.$flex}; flex-wrap: ${(props) => (typeof props.$wrap === 'boolean' ? 'wrap' : props.$wrap)}; align-self: ${(props) => props.$alignSelf}; diff --git a/packages/components/src/Input/BaseInput.tsx b/packages/components/src/Input/BaseInput.tsx index e3617f366..b57347883 100644 --- a/packages/components/src/Input/BaseInput.tsx +++ b/packages/components/src/Input/BaseInput.tsx @@ -41,6 +41,7 @@ type InheritAttrs = Omit< Pick, keyof Props >; + type BaseInputProps = Props & InheritAttrs; const BaseInput = forwardRef( @@ -60,7 +61,7 @@ const BaseInput = forwardRef( ref={ref as any} $adornments={{ left: !!startAdornment, right: !!endAdornment }} $hasError={error} - $isDisabled={!!inputProps.disabled} + $isDisabled={!!inputProps?.disabled} $minHeight={minHeight} $size={size} as={elementType} diff --git a/packages/components/src/List/List.stories.tsx b/packages/components/src/List/List.stories.tsx index 127893a25..f71effb3f 100644 --- a/packages/components/src/List/List.stories.tsx +++ b/packages/components/src/List/List.stories.tsx @@ -28,18 +28,6 @@ export default { export const Default: StoryObj = {}; -export const Secondary: StoryObj = { - args: { - variant: 'secondary' - } -}; - -export const Card: StoryObj = { - args: { - variant: 'card' - } -}; - export const Horizontal: StoryObj = { args: { direction: 'row' diff --git a/packages/components/src/List/List.style.tsx b/packages/components/src/List/List.style.tsx index 49e6892a5..8a2e2c324 100644 --- a/packages/components/src/List/List.style.tsx +++ b/packages/components/src/List/List.style.tsx @@ -1,22 +1,11 @@ import styled, { css } from 'styled-components'; import { theme } from '@interlay/theme'; -import { ListVariants } from '@interlay/theme'; import { Flex } from '../Flex'; -type StyledListProps = { - $variant: ListVariants; -}; - -const StyledList = styled(Flex)` - background-color: ${({ $variant }) => theme.list?.[$variant]?.bg}; - border-radius: ${({ $variant }) => theme.list[$variant].rounded}; - border: ${({ $variant }) => theme.list[$variant].border}; - overflow: hidden; -`; +const StyledList = styled(Flex)``; type StyledListItemProps = { - $variant: ListVariants; $isDisabled: boolean; $isHovered: boolean; $isInteractable: boolean; @@ -27,30 +16,19 @@ const StyledListItem = styled.div` flex: 1; align-self: stretch; padding: ${theme.spacing.spacing3}; - border-radius: ${({ $variant }) => theme.list.item[$variant].rounded}; - background-color: ${({ $variant, $isHovered, $isFocusVisible }) => - $isHovered || $isFocusVisible ? theme.list.item[$variant].hover.bg : theme.list.item[$variant].bg}; - border: ${({ $variant }) => $variant !== 'card' && theme.list.item[$variant].border}; color: ${theme.colors.textPrimary}; cursor: ${({ $isInteractable }) => $isInteractable && 'pointer'}; outline: ${({ $isFocusVisible }) => !$isFocusVisible && 'none'}; opacity: ${({ $isDisabled }) => $isDisabled && 0.5}; white-space: nowrap; - ${({ $variant }) => { - if ($variant === 'card') { - return css` - &:not(:first-of-type) { - border-top: ${theme.list.item.card.border}; - } - `; - } - + ${({ theme, $isHovered }) => { return css` + ${theme.list.item.base} + ${$isHovered && theme.list.item.hover} + &[aria-selected='true'] { - background-color: ${theme.list.item[$variant].selected.bg}; - color: ${theme.list.text}; - border-color: ${theme.list.item[$variant].selected.bg}; + ${theme.list.item.selected}; } `; }} diff --git a/packages/components/src/List/List.tsx b/packages/components/src/List/List.tsx index d9dd409ae..91b69476c 100644 --- a/packages/components/src/List/List.tsx +++ b/packages/components/src/List/List.tsx @@ -27,7 +27,19 @@ type ListProps = Props & NativeAttrs & InheritAttrs; // FIXME: use keyboardDelegate for horizontal list (see TagGroup from spectrum) const List = forwardRef( ( - { variant = 'primary', direction = 'column', onSelectionChange, selectionMode, selectedKeys, ...props }, + { + variant = 'primary', + direction = 'column', + onSelectionChange, + selectionMode, + selectedKeys, + disabledBehavior, + disabledKeys, + disallowEmptySelection, + defaultSelectedKeys, + selectionBehavior, + ...props + }, ref ): JSX.Element => { const listRef = useDOMRef(ref); @@ -36,9 +48,13 @@ const List = forwardRef( onSelectionChange, selectionMode, selectedKeys, + disabledBehavior, + defaultSelectedKeys, + disabledKeys, + disallowEmptySelection, ...props }; - const state = useListState(ariaProps); + const state = useListState({ selectionBehavior, ...ariaProps }); const { gridProps } = useGridList(ariaProps, state, listRef); @@ -46,12 +62,11 @@ const List = forwardRef( {[...state.collection].map((item) => ( - + ))} ); diff --git a/packages/components/src/List/ListItem.tsx b/packages/components/src/List/ListItem.tsx index 46cd298d7..d7931ade3 100644 --- a/packages/components/src/List/ListItem.tsx +++ b/packages/components/src/List/ListItem.tsx @@ -6,15 +6,12 @@ import { mergeProps } from '@react-aria/utils'; import { ListState } from '@react-stately/list'; import { Node } from '@react-types/shared'; import { useMemo, useRef } from 'react'; -import { ListVariants } from '@interlay/theme'; import { Flex, FlexProps } from '../Flex'; import { StyledListItem } from './List.style'; -type Props = { - variant?: ListVariants; -}; +type Props = {}; type InheritAttrs = Omit; @@ -22,7 +19,7 @@ type ListItemProps = Props & InheritAttrs; type InternalProps = ListItemProps & { item: Node; state: ListState }; -const ListItem = ({ item, state, variant = 'primary' }: InternalProps): JSX.Element => { +const ListItem = ({ item, state }: InternalProps): JSX.Element => { const ref = useRef(null); const { rowProps, gridCellProps, isDisabled } = useGridListItem({ node: item }, state, ref); @@ -44,7 +41,6 @@ const ListItem = ({ item, state, variant = 'primary' }: Intern $isFocusVisible={isFocusVisible} $isHovered={isHovered} $isInteractable={isInteractable} - $variant={variant} > {item.rendered} diff --git a/packages/components/src/Modal/Modal.style.tsx b/packages/components/src/Modal/Modal.style.tsx index b48e025ed..837df6536 100644 --- a/packages/components/src/Modal/Modal.style.tsx +++ b/packages/components/src/Modal/Modal.style.tsx @@ -1,22 +1,28 @@ -import styled from 'styled-components'; +import styled, { CSSProperties } from 'styled-components'; +import { DialogSize } from '@interlay/themev2'; import { overlayCSS } from '../utils/overlay'; import { Dialog, DialogBody } from '../Dialog'; +type StyledWrapperProps = { + $placement: 'top' | 'center'; +}; + type StyledModalProps = { $isOpen?: boolean; - $placement: 'top' | 'center'; + $size: DialogSize; }; type StyledDialogProps = { $isOpen?: boolean; + $maxHeight?: CSSProperties['maxHeight']; }; type StyledModalBodyProps = { $noPadding?: boolean; }; -const StyledWrapper = styled.div` +const StyledWrapper = styled.div` position: fixed; top: 0; left: 0; @@ -46,11 +52,13 @@ const StyledModal = styled.div` outline: none; margin: ${({ theme }) => `${theme.spacing('7xl')} ${theme.spacing('xl')}`}; + max-width: ${({ theme, $size }) => theme.dialog.size[$size].maxWidth}; + width: 100%; `; const StyledDialog = styled(Dialog)` pointer-events: ${({ $isOpen }) => !$isOpen && 'none'}; - max-height: ${({ theme }) => `calc(100dvh - ${theme.spacing('10xl')})`}; + max-height: ${({ theme, $maxHeight }) => $maxHeight || `calc(100dvh - ${theme.spacing('10xl')})`}; `; const StyledDialogBody = styled(DialogBody)` diff --git a/packages/components/src/Modal/Modal.tsx b/packages/components/src/Modal/Modal.tsx index a36099d95..d4ce048ea 100644 --- a/packages/components/src/Modal/Modal.tsx +++ b/packages/components/src/Modal/Modal.tsx @@ -1,6 +1,7 @@ import { forwardRef, useRef } from 'react'; import { useDOMRef } from '@interlay/hooks'; import { DialogSize } from '@interlay/themev2'; +import { CSSProperties } from 'styled-components'; import { DialogProps } from '../Dialog'; import { Overlay } from '../Overlay'; @@ -22,6 +23,7 @@ type Props = { container?: Element; placement?: 'top' | 'center'; size?: ModalSizes; + maxHeight?: CSSProperties['maxHeight']; }; type InheritAttrs = Omit; @@ -39,7 +41,8 @@ const Modal = forwardRef( shouldCloseOnInteractOutside, container, isOpen, - size, + size = 'md', + maxHeight, ...props }, ref @@ -64,10 +67,11 @@ const Modal = forwardRef( placement={placement} shouldCloseOnBlur={shouldCloseOnBlur} shouldCloseOnInteractOutside={handleShouldCloseOnInteractOutside} + size={size} wrapperRef={wrapperRef} onClose={onClose} > - + {children} diff --git a/packages/components/src/Modal/ModalWrapper.tsx b/packages/components/src/Modal/ModalWrapper.tsx index 87f4f5900..5331ed2fe 100644 --- a/packages/components/src/Modal/ModalWrapper.tsx +++ b/packages/components/src/Modal/ModalWrapper.tsx @@ -2,6 +2,7 @@ import { AriaModalOverlayProps, AriaOverlayProps, useModalOverlay } from '@react import { mergeProps } from '@react-aria/utils'; import { OverlayTriggerState } from '@react-stately/overlays'; import { forwardRef, ReactNode, RefObject } from 'react'; +import { DialogSize } from '@interlay/themev2'; import { Underlay } from '../Overlay/Underlay'; @@ -13,6 +14,7 @@ type Props = { isOpen?: boolean; onClose: () => void; wrapperRef: RefObject; + size: DialogSize; }; type InheritAttrs = Omit; @@ -31,6 +33,7 @@ const ModalWrapper = forwardRef( shouldCloseOnInteractOutside, shouldCloseOnBlur, wrapperRef, + size, ...props }, ref @@ -53,8 +56,8 @@ const ModalWrapper = forwardRef( return (
- - + + {children} diff --git a/packages/components/src/Select/Select.stories.tsx b/packages/components/src/Select/Select.stories.tsx index 44e72b008..d09ce524b 100644 --- a/packages/components/src/Select/Select.stories.tsx +++ b/packages/components/src/Select/Select.stories.tsx @@ -24,6 +24,51 @@ const Render = (args: SelectProps) => ( USDT + + + USDC + + + + + TBTC + + + + + WBTC + + + + + WETH + + + + + DAI + + + + + BBTC + + + + + DBTC + + + + + PBTC + + + + + WWBTC + + ); diff --git a/packages/components/src/Select/Select.style.tsx b/packages/components/src/Select/Select.style.tsx index 433cc9c8a..877fb81e9 100644 --- a/packages/components/src/Select/Select.style.tsx +++ b/packages/components/src/Select/Select.style.tsx @@ -1,16 +1,16 @@ -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { ChevronDown } from '@interlay/icons'; -import { theme } from '@interlay/theme'; -import { Sizes } from '@interlay/theme'; +import { InputSizes } from '@interlay/themev2'; import { List } from '../List'; import { Span } from '../Text'; type StyledTriggerProps = { $isOpen?: boolean; - $size: Sizes; + $size: InputSizes; $isDisabled: boolean; $hasError: boolean; + $hasValue: boolean; }; type StyledTriggerValueProps = { @@ -24,10 +24,6 @@ const StyledTrigger = styled.button` letter-spacing: inherit; background: none; - font-size: ${({ $size }) => theme.select.size[$size].text}; - line-height: ${theme.lineHeight.base}; - color: ${({ $isDisabled }) => ($isDisabled ? theme.input.disabled.color : theme.input.color)}; - background-color: ${({ $isDisabled }) => ($isDisabled ? theme.input.disabled.bg : theme.input.background)}; overflow: hidden; display: inline-flex; @@ -36,45 +32,60 @@ const StyledTrigger = styled.button` width: 100%; text-align: left; - padding: ${({ $size }) => theme.select.size[$size].padding}; cursor: ${({ $isDisabled }) => !$isDisabled && 'pointer'}; - max-height: ${({ $size }) => `calc(${theme.input[$size].maxHeight} - 1px)`}; - - border: ${({ $isDisabled, $hasError }) => - $isDisabled ? theme.input.disabled.border : $hasError ? theme.input.error.border : theme.border.default}; - border-radius: ${theme.rounded.md}; - transition: - border-color ${theme.transition.duration.duration150}ms ease-in-out, - box-shadow ${theme.transition.duration.duration150}ms ease-in-out; - - &:hover:not(:disabled):not(:focus) { - border: ${({ $isDisabled, $hasError }) => !$isDisabled && !$hasError && theme.input.hover.border}; - } - - &:focus { - border: ${({ $isDisabled }) => !$isDisabled && theme.input.focus.border}; - box-shadow: ${({ $isDisabled }) => !$isDisabled && theme.input.focus.boxShadow}; - } + + ${({ theme, $size, $hasError, $hasValue }) => { + const { paddingRight, paddingTop, paddingBottom, paddingLeft, ...sizeCss } = theme.input.size[$size]; + const { color, ...baseCss } = theme.input.base; + + return css` + padding-top: ${paddingTop}; + padding-bottom: ${paddingBottom}; + padding-left: ${paddingLeft}; + padding-right: ${paddingRight}; + + color: ${$hasValue ? color : theme.input.placeholder.color}; + + ${sizeCss} + ${baseCss} + ${$hasError && theme.input.error.base} + + + &:hover:not(:disabled):not(:focus) { + ${$hasError ? theme.input.error.hover : theme.input.hover} + } + + &:focus:not(:disabled) { + ${$hasError ? theme.input.error.focus : theme.input.focus} + } + + &:disabled { + ${theme.input.disabled} + } + `; + }} `; const StyledTriggerValue = styled(Span)` flex: 1; display: inline-flex; align-items: center; - color: ${({ $isDisabled, $isSelected }) => - $isDisabled ? theme.input.disabled.color : $isSelected ? theme.select.color : theme.select.placeholder}; + color: inherit; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + font-size: inherit; + line-height: inherit; + font-weight: inherit; `; const StyledList = styled(List)` overflow: auto; - padding: 0 ${theme.dialog.medium.body.paddingX} ${theme.dialog.medium.body.paddingX}; + padding: 0 12px 12px; `; const StyledChevronDown = styled(ChevronDown)` - margin-left: ${theme.spacing.spacing2}; + margin-left: ${({ theme }) => theme.spacing('md')}; `; export { StyledChevronDown, StyledList, StyledTrigger, StyledTriggerValue }; diff --git a/packages/components/src/Select/Select.tsx b/packages/components/src/Select/Select.tsx index d9d1da6aa..21d5ef6f5 100644 --- a/packages/components/src/Select/Select.tsx +++ b/packages/components/src/Select/Select.tsx @@ -1,12 +1,11 @@ +import { useDOMRef } from '@interlay/hooks'; +import { InputSizes } from '@interlay/themev2'; import { useSelect } from '@react-aria/select'; import { mergeProps, useId } from '@react-aria/utils'; import { VisuallyHidden } from '@react-aria/visually-hidden'; import { SelectProps as AriaSelectProps, useSelectState } from '@react-stately/select'; -import { CollectionBase, Node } from '@react-types/shared'; -import { ForwardedRef, forwardRef, ReactNode, useRef } from 'react'; -import { Sizes } from '@interlay/theme'; -import { useDOMRef } from '@interlay/hooks'; -import { Key } from '@react-types/shared'; +import { CollectionBase, Key, Node } from '@react-types/shared'; +import { ForwardedRef, ReactNode, forwardRef, useRef } from 'react'; import { Field, FieldProps, useFieldProps } from '../Field'; import { hasError } from '../utils/input'; @@ -19,7 +18,7 @@ type SelectObject = Record; type Props = { open?: boolean; loading?: boolean; - size?: Sizes; + size?: InputSizes; // MEMO: Allows a custom select trigger (TokenInput select) asSelectTrigger?: any; renderValue?: (item: Node) => ReactNode; @@ -62,7 +61,7 @@ const Select = ( required, label, errorMessage, - size = 'medium', + size = 'md', placeholder = 'Select an option', asSelectTrigger, isInvalid, @@ -165,6 +164,7 @@ const Select = ( selectedKeys: state.selectedItem?.key ? [state.selectedItem?.key] : [], disabledKeys })} + maxHeight='650px' state={state} /> )} @@ -179,4 +179,4 @@ const _Select = forwardRef(Select) as ( Select.displayName = 'Select'; export { _Select as Select }; -export type { SelectProps, ListboxSelectProps, ModalSelectProps }; +export type { ListboxSelectProps, ModalSelectProps, SelectProps }; diff --git a/packages/components/src/Select/SelectTrigger.tsx b/packages/components/src/Select/SelectTrigger.tsx index 7a5d91361..cf2e84365 100644 --- a/packages/components/src/Select/SelectTrigger.tsx +++ b/packages/components/src/Select/SelectTrigger.tsx @@ -51,6 +51,7 @@ const SelectTrigger = forwardRef( {...buttonProps} ref={buttonRef} $hasError={hasError} + $hasValue={!!children} $isDisabled={!!disabled} $isOpen={isOpen} $size={size} @@ -59,7 +60,7 @@ const SelectTrigger = forwardRef( {children || placeholder} - + ); } diff --git a/packages/components/src/TokenInput/BaseTokenInput.style.tsx b/packages/components/src/TokenInput/BaseTokenInput.style.tsx new file mode 100644 index 000000000..09baed4b4 --- /dev/null +++ b/packages/components/src/TokenInput/BaseTokenInput.style.tsx @@ -0,0 +1,100 @@ +import { InputSizes, TokenInputSize } from '@interlay/themev2'; +import styled, { css } from 'styled-components'; + +import { Flex } from '../Flex'; + +type StyledUSDAdornmentProps = { + $isDisabled?: boolean; + $size: TokenInputSize; +}; + +type StyledBaseInputProps = { + $adornmentBottom: boolean; + $hasError: boolean; + $size: InputSizes; +}; + +const StyledBaseInput = styled.input` + display: block; + width: 100%; + height: 100%; + + outline: none; + font: inherit; + letter-spacing: inherit; + background: none; + + text-overflow: ellipsis; + + ${({ theme, $size, $adornmentBottom, $hasError }) => { + const { paddingRight, paddingTop, paddingBottom, paddingLeft, ...sizeCss } = theme.input.size[$size]; + + // MEMO: adding `spacing6` is a hacky solution because + // the `endAdornmentWidth` does not update width correctly + // after fonts are loaded. Instead of falling back to a more + // complex solution, an extra offset does the job of not allowing + // the input overlap the adornment. + return css` + padding-top: ${paddingTop}; + padding-bottom: ${$adornmentBottom ? theme.spacing('3xl') : paddingBottom}; + padding-left: ${paddingLeft}; + padding-right: ${paddingRight}; + + ${sizeCss} + ${theme.input.base} + ${$hasError && theme.input.error.base} + + border-top-right-radius: 0; + border-bottom-right-radius: 0; + + &:hover:not(:disabled):not(:focus) { + ${$hasError ? theme.input.error.hover : theme.input.hover} + } + + &:focus:not(:disabled) { + z-index: 1; + ${$hasError ? theme.input.error.focus : theme.input.focus} + } + + &::placeholder { + ${theme.input.placeholder} + } + + &:disabled { + ${theme.input.disabled} + } + `; + }} +`; + +const StyledUSDAdornment = styled.span` + display: block; + white-space: nowrap; + align-self: flex-start; + overflow: hidden; + max-width: -webkit-fill-available; + text-overflow: ellipsis; + ${({ theme, $size }) => theme.tokenInput.size[$size].addornment.bottom} +`; + +type StyledAdornmentProps = { + $size: InputSizes; +}; + +const StyledAdornment = styled.div` + display: inline-flex; + align-items: center; + position: absolute; + // to not allow adornment to take more than 50% of the input. We might want to reduce this in the future. + left: ${({ theme, $size }) => theme.input.size[$size].paddingLeft}; + bottom: ${({ theme }) => theme.spacing('s')}; + overflow: hidden; + max-width: ${({ theme, $size }) => `calc(100% - (2 *${theme.input.size[$size].paddingLeft}))`}; + z-index: 2; +`; + +const StyledInputWrapper = styled(Flex)` + position: relative; +`; + +export { StyledBaseInput, StyledAdornment, StyledUSDAdornment, StyledInputWrapper }; diff --git a/packages/components/src/TokenInput/BaseTokenInput.tsx b/packages/components/src/TokenInput/BaseTokenInput.tsx index a1227b80a..11996077c 100644 --- a/packages/components/src/TokenInput/BaseTokenInput.tsx +++ b/packages/components/src/TokenInput/BaseTokenInput.tsx @@ -1,73 +1,146 @@ -import { useLabel } from '@react-aria/label'; +import { useCurrencyFormatter, useDOMRef } from '@interlay/hooks'; +import { Spacing, TokenInputSize } from '@interlay/themev2'; +import { AriaTextFieldOptions, useTextField } from '@react-aria/textfield'; import { mergeProps } from '@react-aria/utils'; -import { forwardRef, ReactNode } from 'react'; -import { useCurrencyFormatter } from '@interlay/hooks'; +import { ChangeEventHandler, FocusEvent, forwardRef, ReactNode, useCallback, useEffect, useState } from 'react'; +import { HelperTextProps } from 'src/HelperText'; +import { LabelProps } from 'src/Label'; +import { Field, FieldProps, useFieldProps } from '../Field'; import { Flex } from '../Flex'; -import { NumberInput, NumberInputProps } from '../NumberInput'; +import { hasError } from '../utils/input'; +import { StyledAdornment, StyledBaseInput, StyledInputWrapper, StyledUSDAdornment } from './BaseTokenInput.style'; import { TokenInputLabel } from './TokenInputLabel'; -import { StyledUSDAdornment } from './TokenInput.style'; + +const escapeRegExp = (string: string): string => { + // $& means the whole matched string + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +}; type Props = { valueUSD?: number; balance?: ReactNode; + label?: ReactNode; + labelProps?: LabelProps; + endAdornment: ReactNode; + size?: TokenInputSize; + isInvalid?: boolean; + minHeight?: Spacing; + value?: string | number; + defaultValue?: string | number; + onValueChange?: (value: string | number) => void; + onChange?: (e: React.ChangeEvent) => void; + onFocus?: (e: FocusEvent) => void; + onBlur?: (e: FocusEvent) => void; }; -type InheritAttrs = Omit; +type InheritAttrs = Omit< + HelperTextProps & + Pick, + keyof Props +>; -type BaseTokenInputProps = Props & InheritAttrs; +type AriaAttrs = Omit, (keyof Props & InheritAttrs) | 'onChange'>; + +type BaseTokenInputProps = Props & AriaAttrs & InheritAttrs; const BaseTokenInput = forwardRef( ( { label, - style, - hidden, - className, - placeholder = '0', - errorMessage, - description, + placeholder = '0.00', balance, children, valueUSD, isDisabled, + isInvalid, + size = 'md', + defaultValue, + inputMode, + value: valueProp, + endAdornment, + onChange, + onValueChange, ...props }, ref ): JSX.Element => { + const [value, setValue] = useState(defaultValue?.toString()); + const inputRef = useDOMRef(ref); + const format = useCurrencyFormatter(); - const { labelProps, fieldProps } = useLabel({ label, ...props }); + + const handleChange: ChangeEventHandler = useCallback( + (e) => { + const value = e.target.value; + + const isValid = value === '' || RegExp(`^\\d*(?:\\\\[.])?\\d*$`).test(escapeRegExp(value)); + + if (isValid) { + onChange?.(e); + onValueChange?.(value); + setValue(value); + } + }, + [onChange, onValueChange] + ); + + const { inputProps, descriptionProps, errorMessageProps, labelProps } = useTextField( + { + ...props, + label, + inputMode, + isInvalid: isInvalid || !!props.errorMessage, + value: value, + placeholder, + autoComplete: 'off' + }, + inputRef + ); + + useEffect(() => { + if (valueProp === undefined) return; + + setValue(valueProp.toString()); + }, [valueProp]); const hasLabel = !!label || !!balance; + // FIXME: move this into Field + const { fieldProps: styleFieldProps } = useFieldProps({ ...props, descriptionProps, errorMessageProps }); + + const error = hasError({ isInvalid, errorMessage: props.errorMessage }); + const bottomAdornment = valueUSD !== undefined && ( - {format(valueUSD)} + + {format(valueUSD)} + ); return ( - + + + {hasLabel && ( + + {label} + + )} + + + {bottomAdornment} + {endAdornment} + + {children} + + ); } ); diff --git a/packages/components/src/TokenInput/FixedTokenInput.tsx b/packages/components/src/TokenInput/FixedTokenInput.tsx index 97c7860bd..1ad51d2aa 100644 --- a/packages/components/src/TokenInput/FixedTokenInput.tsx +++ b/packages/components/src/TokenInput/FixedTokenInput.tsx @@ -13,7 +13,7 @@ type Props = { logoUrl: string; }; -type InheritAttrs = Omit; +type InheritAttrs = Omit; type FixedTokenInputProps = Props & InheritAttrs; @@ -28,6 +28,7 @@ const FixedTokenInput = forwardRef( logoUrl, isDisabled, id, + size = 'md', ...props }, ref @@ -45,12 +46,13 @@ const FixedTokenInput = forwardRef( return ( } + endAdornment={} id={id} isDisabled={isDisabled} - {...props} + size={size} /> ); } diff --git a/packages/components/src/TokenInput/SelectableTokenInput.tsx b/packages/components/src/TokenInput/SelectableTokenInput.tsx index 782990ea2..303f8853b 100644 --- a/packages/components/src/TokenInput/SelectableTokenInput.tsx +++ b/packages/components/src/TokenInput/SelectableTokenInput.tsx @@ -15,7 +15,7 @@ type Props = { selectProps: Omit; }; -type InheritAttrs = Omit; +type InheritAttrs = Omit; type SelectableTokenInputProps = Props & InheritAttrs; diff --git a/packages/components/src/TokenInput/TokenAdornment.tsx b/packages/components/src/TokenInput/TokenAdornment.tsx index f6746bd07..ab3b04a08 100644 --- a/packages/components/src/TokenInput/TokenAdornment.tsx +++ b/packages/components/src/TokenInput/TokenAdornment.tsx @@ -1,3 +1,5 @@ +import { TokenInputSize } from '@interlay/themev2'; + import { FlexProps } from '../Flex'; import { StyledTicker, StyledTokenAdornment, StyledTokenImg } from './TokenInput.style'; @@ -5,15 +7,16 @@ import { StyledTicker, StyledTokenAdornment, StyledTokenImg } from './TokenInput type Props = { ticker: string; logoUrl: string; + size: TokenInputSize; }; type NativeAttrs = Omit; type TokenAdornmentProps = Props & NativeAttrs; -const TokenAdornment = ({ ticker, logoUrl, ...props }: TokenAdornmentProps): JSX.Element => ( - - +const TokenAdornment = ({ ticker, logoUrl, size, ...props }: TokenAdornmentProps): JSX.Element => ( + + {ticker} ); diff --git a/packages/components/src/TokenInput/TokenInput.style.tsx b/packages/components/src/TokenInput/TokenInput.style.tsx index 3f34b5d67..e5001ee72 100644 --- a/packages/components/src/TokenInput/TokenInput.style.tsx +++ b/packages/components/src/TokenInput/TokenInput.style.tsx @@ -1,79 +1,50 @@ import styled from 'styled-components'; import { ChevronDown } from '@interlay/icons'; import { theme } from '@interlay/theme'; +import { TokenInputSize } from '@interlay/themev2'; +import { UnstyledButton } from '../UnstyledButton'; import { Flex } from '../Flex'; import { List } from '../List'; import { StyledTrigger } from '../Select/Select.style'; -import { Dl, Dt, Span } from '../Text'; - -type StyledUSDAdornmentProps = { - $isDisabled?: boolean; -}; +import { Span } from '../Text'; type StyledListItemSelectedLabelProps = { $isSelected: boolean; }; +type StyledTokenAdornmentProps = { + $size: TokenInputSize; +}; + const StyledTicker = styled.span` - font-size: ${theme.text.s}; - color: ${theme.colors.textPrimary}; + color: inherit; overflow: hidden; text-overflow: ellipsis; `; -const StyledUSDAdornment = styled.span` - display: block; - font-size: ${theme.text.xs}; - line-height: ${theme.lineHeight.s}; - color: ${({ $isDisabled }) => ($isDisabled ? theme.input.disabled.color : theme.colors.textTertiary)}; - white-space: nowrap; - align-self: flex-start; +const StyledTokenAdornment = styled(Flex)` + ${({ theme, $size }) => theme.tokenInput.size[$size].addornment.token.base} `; -const StyledTokenAdornment = styled(Flex)` - border: ${theme.border.default}; - background-color: ${theme.tokenInput.endAdornment.bg}; - border-radius: ${theme.rounded.md}; - font-size: ${theme.text.s}; - padding: ${theme.spacing.spacing3}; - height: 3rem; - width: auto; - overflow: hidden; -`; - -const StyledTokenImg = styled.img` - height: ${theme.spacing.spacing6}; - width: ${theme.spacing.spacing6}; +const StyledTokenImg = styled.img` + ${({ theme, $size }) => theme.tokenInput.size[$size].addornment.token.img} border-radius: ${theme.rounded.full}; `; const StyledTokenSelect = styled(StyledTrigger)` - background-color: ${theme.tokenInput.endAdornment.bg}; - opacity: ${({ $isDisabled }) => $isDisabled && 0.5}; - border-radius: ${theme.rounded.md}; - font-size: ${theme.text.s}; - padding: ${theme.spacing.spacing3}; - height: 3rem; - max-height: 3rem; - width: auto; + border-top-left-radius: 0; + border-bottom-left-radius: 0; overflow: hidden; + margin-left: -1px; + max-width: 150px; + width: 100%; `; const StyledChevronDown = styled(ChevronDown)` margin-left: ${theme.spacing.spacing1}; `; -const StyledBalance = styled(Dl)` - padding: ${theme.spacing.spacing1} 0; -`; - -const StyledBalanceLabel = styled(Dt)` - &:after { - content: ':'; - } -`; - const StyledListItemLabel = styled(Span)` color: ${({ $isSelected }) => $isSelected ? theme.tokenInput.list.item.selected.text : theme.tokenInput.list.item.default.text}; @@ -94,17 +65,26 @@ const StyledListTokenWrapper = styled(Flex)` overflow: hidden; `; +const StyledBalanceButton = styled(UnstyledButton)` + ${({ theme }) => theme.tokenInput.balance} +`; + +const StyledBalanceLabel = styled(Span)` + font-size: inherit; + font-weight: inherit; + line-height: inherit; +`; + export { + StyledBalanceLabel, StyledChevronDown, StyledList, StyledListHeader, StyledListItemLabel, StyledListTokenWrapper, StyledTicker, + StyledBalanceButton, StyledTokenAdornment, - StyledBalance, - StyledBalanceLabel, StyledTokenSelect, - StyledUSDAdornment, StyledTokenImg }; diff --git a/packages/components/src/TokenInput/TokenInputBalance.tsx b/packages/components/src/TokenInput/TokenInputBalance.tsx index 7b331e09f..0111729d2 100644 --- a/packages/components/src/TokenInput/TokenInputBalance.tsx +++ b/packages/components/src/TokenInput/TokenInputBalance.tsx @@ -1,8 +1,6 @@ import { ReactNode } from 'react'; -import { Dd, Flex, UnstyledButton } from '..'; - -import { StyledBalance, StyledBalanceLabel } from './TokenInput.style'; +import { StyledBalanceButton, StyledBalanceLabel } from './TokenInput.style'; type TokenInputBalanceProps = { inputId?: string; @@ -30,25 +28,14 @@ const TokenInputBalance = ({ const handleClickBalance = () => onClickBalance?.(balanceProp); return ( - - - - {label} - -
- {balance} -
-
- {/* - MAX - */} -
+ + {label}: {balance} + ); }; diff --git a/packages/components/src/TokenInput/TokenSelect.tsx b/packages/components/src/TokenInput/TokenSelect.tsx index 78702acaa..1db0f50bf 100644 --- a/packages/components/src/TokenInput/TokenSelect.tsx +++ b/packages/components/src/TokenInput/TokenSelect.tsx @@ -1,7 +1,7 @@ import { mergeProps } from '@react-aria/utils'; import { Flex } from '../Flex'; -import { Item, Select, ModalSelectProps } from '../Select'; +import { Item, ModalSelectProps, Select } from '../Select'; import { Span } from '../Text'; import { StyledTicker, StyledTokenImg, StyledTokenSelect } from './TokenInput.style'; @@ -9,7 +9,7 @@ import { TokenListItem } from './TokenListItem'; const Value = ({ data }: { data: TokenData }) => ( - + {data.ticker} ); diff --git a/packages/components/src/TokenInput/stories/FixedTokenInput.stories.tsx b/packages/components/src/TokenInput/stories/FixedTokenInput.stories.tsx index c44c2cf5f..72de68aa1 100644 --- a/packages/components/src/TokenInput/stories/FixedTokenInput.stories.tsx +++ b/packages/components/src/TokenInput/stories/FixedTokenInput.stories.tsx @@ -43,7 +43,9 @@ export const Controlled: StoryObj = { export const WithValueUSD: StoryObj = { args: { - valueUSD: 0 + valueUSD: 0, + balance: '10.901231231', + humanBalance: '11' }, render: ControlledComponent }; diff --git a/packages/components/src/TokenInput/stories/SelectableTokenInput.stories.tsx b/packages/components/src/TokenInput/stories/SelectableTokenInput.stories.tsx index 9df5f49ad..0e31db7e2 100644 --- a/packages/components/src/TokenInput/stories/SelectableTokenInput.stories.tsx +++ b/packages/components/src/TokenInput/stories/SelectableTokenInput.stories.tsx @@ -63,7 +63,8 @@ export const SelectableControlledValue: StoryObj = { export const SelectableWithBalance: StoryObj = { args: { - balance: '10' + balance: '10', + valueUSD: '0' } }; diff --git a/packages/components/src/Tooltip/Tooltip.stories.tsx b/packages/components/src/Tooltip/Tooltip.stories.tsx index 3f11fca3c..cc78cf00e 100644 --- a/packages/components/src/Tooltip/Tooltip.stories.tsx +++ b/packages/components/src/Tooltip/Tooltip.stories.tsx @@ -11,7 +11,7 @@ export default { layout: 'centered' }, render: (args) => ( - + Hover Me ), diff --git a/packages/components/src/Tooltip/Tooltip.style.tsx b/packages/components/src/Tooltip/Tooltip.style.tsx index 87ce27aaa..b39de494b 100644 --- a/packages/components/src/Tooltip/Tooltip.style.tsx +++ b/packages/components/src/Tooltip/Tooltip.style.tsx @@ -1,5 +1,4 @@ import styled, { css } from 'styled-components'; -import { theme } from '@interlay/theme'; import { Placement } from '@interlay/theme'; import { getOverlayPlacementCSS, overlayCSS } from '../utils/overlay'; @@ -20,15 +19,6 @@ const StyledTooltip = styled.div` align-items: center; box-sizing: border-box; vertical-align: top; - background-color: ${theme.tooltip.bg}; - padding: ${theme.spacing.spacing3}; - border-radius: ${theme.rounded.rg}; - // TODO: add box-shadow to theme - box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.21); - font-weight: ${theme.fontWeight.book}; - font-size: ${theme.text.s}; - line-height: ${theme.lineHeight.s}; - color: ${theme.colors.textPrimary}; word-break: break-word; -webkit-font-smoothing: antialiased; cursor: default; @@ -41,22 +31,23 @@ const StyledTooltip = styled.div` case 'top': default: return css` - margin-bottom: ${theme.tooltip.offset}; + margin-bottom: 3px; `; case 'bottom': return css` - margin-top: ${theme.tooltip.offset}; + margin-top: 3px; `; case 'right': return css` - margin-left: ${theme.tooltip.offset}; + margin-left: 3px; `; case 'left': return css` - margin-right: ${theme.tooltip.offset}; + margin-right: 3px; `; } }} + ${({ theme }) => theme.tooltip} `; const StyledTooltipTip = styled.span` @@ -64,8 +55,8 @@ const StyledTooltipTip = styled.span` height: 0; width: 0; border-style: solid; - border-width: ${theme.tooltip.tip.width}; - border-top-color: ${theme.tooltip.tip.bg}; + border-width: 3px; + border-top-color: ${({ theme }) => theme.tooltip.backgroundColor}; border-left-color: transparent; border-right-color: transparent; border-bottom-color: transparent; @@ -77,27 +68,27 @@ const StyledTooltipTip = styled.span` return css` top: 100%; left: 50%; - margin-left: calc(${theme.tooltip.tip.width} * -1); + margin-left: calc(5px * -1); `; case 'bottom': return css` bottom: 100%; left: 50%; - margin-left: calc(${theme.tooltip.tip.width} * -1); + margin-left: calc(5px * -1); transform: rotate(-180deg); `; case 'right': return css` right: 100%; top: 50%; - margin-top: calc(${theme.tooltip.tip.width} * -1); + margin-top: calc(5px * -1); transform: rotate(90deg); `; case 'left': return css` left: 100%; top: 50%; - margin-top: calc(${theme.tooltip.tip.width} * -1); + margin-top: calc(5px * -1); transform: rotate(-90deg); `; } diff --git a/packages/components/src/utils/overlay.ts b/packages/components/src/utils/overlay.ts index c0ecdb364..ed0a3e9e1 100644 --- a/packages/components/src/utils/overlay.ts +++ b/packages/components/src/utils/overlay.ts @@ -1,10 +1,8 @@ -import type { DefaultTheme, RuleSet } from 'styled-components'; - import { css } from 'styled-components'; import { Placement, theme } from '../../../core/theme/src'; -const getOverlayPlacementCSS = (placement: Placement): RuleSet => { +const getOverlayPlacementCSS = (placement: Placement) => { switch (placement) { case 'bottom': return css` diff --git a/packages/core/themeV2/src/components/index.ts b/packages/core/themeV2/src/components/index.ts index 7c2171b66..3824890de 100644 --- a/packages/core/themeV2/src/components/index.ts +++ b/packages/core/themeV2/src/components/index.ts @@ -11,3 +11,5 @@ export * from './radio'; export * from './switch'; export * from './spinner'; export * from './progress-bar'; +export * from './tooltip'; +export * from './token-input'; diff --git a/packages/core/themeV2/src/components/list.ts b/packages/core/themeV2/src/components/list.ts index 638137138..479b7dd44 100644 --- a/packages/core/themeV2/src/components/list.ts +++ b/packages/core/themeV2/src/components/list.ts @@ -1,17 +1,5 @@ -import { Rounded } from '../core'; +import { StyledObject } from 'styled-components'; -type ListTheme = { - bg: string; - item: { - rounded: Rounded; - border: string; - hover: { - bg: string; - }; - selected: { - bg: string; - }; - }; -}; +type ListTheme = { item: { base: StyledObject; hover: StyledObject; selected: StyledObject } }; export type { ListTheme }; diff --git a/packages/core/themeV2/src/components/radio.ts b/packages/core/themeV2/src/components/radio.ts index e035d040b..6851e137a 100644 --- a/packages/core/themeV2/src/components/radio.ts +++ b/packages/core/themeV2/src/components/radio.ts @@ -1,8 +1,5 @@ -type RadioTheme = { - color: string; - selected: { - color: string; - }; -}; +import { StyledObject } from 'styled-components'; + +type RadioTheme = StyledObject; export type { RadioTheme }; diff --git a/packages/core/themeV2/src/components/switch.ts b/packages/core/themeV2/src/components/switch.ts index 54747a1d6..ba4638ce1 100644 --- a/packages/core/themeV2/src/components/switch.ts +++ b/packages/core/themeV2/src/components/switch.ts @@ -1,15 +1,5 @@ -import { Spacing } from '../core'; +import { StyledObject } from 'styled-components'; -type SwitchTheme = { - width: Spacing; - height: Spacing; - bg: string; - selected: { - bg: string; - }; - indicator: { - bg: string; - }; -}; +type SwitchTheme = StyledObject; export type { SwitchTheme }; diff --git a/packages/core/themeV2/src/components/token-input.ts b/packages/core/themeV2/src/components/token-input.ts new file mode 100644 index 000000000..e876071cb --- /dev/null +++ b/packages/core/themeV2/src/components/token-input.ts @@ -0,0 +1,21 @@ +import { StyledObject } from 'styled-components'; + +import { InputSizes } from './input'; + +type TokenInputSize = InputSizes; + +type TokenInputTheme = { + balance: StyledObject; + addorment: { token: { base: StyledObject; img?: StyledObject } }; + size: Record< + TokenInputSize, + { + addornment: { + bottom: StyledObject; + token: { base: StyledObject; img: StyledObject }; + }; + } + >; +}; + +export type { TokenInputTheme, TokenInputSize }; diff --git a/packages/core/themeV2/src/components/tooltip.ts b/packages/core/themeV2/src/components/tooltip.ts new file mode 100644 index 000000000..1420c5439 --- /dev/null +++ b/packages/core/themeV2/src/components/tooltip.ts @@ -0,0 +1,5 @@ +import { StyledObject } from 'styled-components'; + +type TooltipTheme = StyledObject; + +export type { TooltipTheme }; diff --git a/packages/core/themeV2/src/define.ts b/packages/core/themeV2/src/define.ts index a0c1d5543..e84c8de2e 100644 --- a/packages/core/themeV2/src/define.ts +++ b/packages/core/themeV2/src/define.ts @@ -26,7 +26,9 @@ import { RadioTheme, SwitchTheme, SpinnerTheme, - ProgressBarTheme + ProgressBarTheme, + TooltipTheme, + TokenInputTheme } from './components'; const baseTheme = { @@ -56,6 +58,8 @@ type ThemeParams = { switch: SwitchTheme; spinner: SpinnerTheme; progressBar: ProgressBarTheme; + tooltip: TooltipTheme; + tokenInput: TokenInputTheme; }; const defineTheme = ({ colors, ...theme }: ThemeParams) => ({ diff --git a/packages/core/themeV2/src/index.ts b/packages/core/themeV2/src/index.ts index 5215232e4..968de09d3 100644 --- a/packages/core/themeV2/src/index.ts +++ b/packages/core/themeV2/src/index.ts @@ -9,7 +9,8 @@ export type { DialogSize, AccordionVariants, ProgressBarSize, - AlertStatus + AlertStatus, + TokenInputSize } from './components'; export type { IconsSizes, diff --git a/packages/core/themeV2/src/themes/bob/drawer.ts b/packages/core/themeV2/src/themes/bob/drawer.ts index ca30ee943..2feec748f 100644 --- a/packages/core/themeV2/src/themes/bob/drawer.ts +++ b/packages/core/themeV2/src/themes/bob/drawer.ts @@ -3,8 +3,8 @@ import { DrawerTheme } from '../../components'; import { color } from './colors'; const drawer: DrawerTheme = { - background: color('grey-300'), - borderRight: `1px solid ${color('grey-200')}` + background: color('grey-500'), + borderRight: `1px solid ${color('grey-400')}` }; export { drawer }; diff --git a/packages/core/themeV2/src/themes/bob/index.ts b/packages/core/themeV2/src/themes/bob/index.ts index 976872313..4f2e09eae 100644 --- a/packages/core/themeV2/src/themes/bob/index.ts +++ b/packages/core/themeV2/src/themes/bob/index.ts @@ -14,6 +14,8 @@ import { colors } from './colors'; import { spinner } from './spinner'; import { _switch } from './switch'; import { progressBar } from './progress-bar'; +import { tooltip } from './tooltip'; +import { tokenInput } from './token-input'; const bobTheme = defineTheme({ colors, @@ -29,7 +31,9 @@ const bobTheme = defineTheme({ radio, spinner, switch: _switch, - progressBar + progressBar, + tooltip, + tokenInput }); export { bobTheme }; diff --git a/packages/core/themeV2/src/themes/bob/input.ts b/packages/core/themeV2/src/themes/bob/input.ts index 8266281eb..63e3f8807 100644 --- a/packages/core/themeV2/src/themes/bob/input.ts +++ b/packages/core/themeV2/src/themes/bob/input.ts @@ -6,7 +6,7 @@ import { color } from './colors'; const input: InputTheme = { base: { color: color('light'), - backgroundColor: color('grey-500'), + backgroundColor: color('grey-600'), border: `1px solid ${color('grey-400')}`, borderRadius: rounded('md'), ...transition('common', 'normal') diff --git a/packages/core/themeV2/src/themes/bob/list.ts b/packages/core/themeV2/src/themes/bob/list.ts index 8089c4cf8..3aa96a313 100644 --- a/packages/core/themeV2/src/themes/bob/list.ts +++ b/packages/core/themeV2/src/themes/bob/list.ts @@ -1,8 +1,23 @@ +import { rounded, typography, spacing } from '../../core'; import { ListTheme } from '../../components'; +import { color } from './colors'; + const list: ListTheme = { - size: { - xs: {} + item: { + base: { + borderRadius: rounded('md'), + color: color('light'), + padding: spacing('lg'), + ...typography('md') + }, + hover: { + backgroundColor: color('grey-600') + }, + selected: { + backgroundColor: color('light'), + color: color('dark') + } } }; diff --git a/packages/core/themeV2/src/themes/bob/token-input.ts b/packages/core/themeV2/src/themes/bob/token-input.ts new file mode 100644 index 000000000..8aefeb6b7 --- /dev/null +++ b/packages/core/themeV2/src/themes/bob/token-input.ts @@ -0,0 +1,86 @@ +import { fontWeight, rounded, spacing, typography } from '../../core'; +import { TokenInputTheme } from '../../components'; + +import { color } from './colors'; + +const tokenInput: TokenInputTheme = { + balance: { + padding: `${spacing('xxs')} 0`, + color: color('primary-500'), + fontWeight: fontWeight('medium'), + ...typography('xs') + }, + addorment: { + token: { + base: { + backgroundColor: color('grey-500'), + border: `1px solid ${color('grey-400')}`, + borderLeft: 'none', + borderTopRightRadius: rounded('md'), + borderBottomRightRadius: rounded('md'), + color: color('light') + } + } + }, + size: { + s: { + addornment: { + bottom: { + ...typography('xs'), + color: color('grey-200') + }, + token: { + base: { + paddingLeft: spacing('md'), + paddingRight: spacing('md'), + ...typography('md') + }, + img: { + height: spacing('2xl'), + width: spacing('2xl') + } + } + } + }, + md: { + addornment: { + bottom: { + ...typography('xs'), + color: color('grey-200') + }, + token: { + base: { + paddingLeft: spacing('md'), + paddingRight: spacing('md'), + ...typography('md') + }, + img: { + height: spacing('2xl'), + width: spacing('2xl') + } + } + } + }, + lg: { + addornment: { + bottom: { + ...typography('xs'), + color: color('grey-200') + }, + token: { + base: { + paddingLeft: spacing('md'), + paddingRight: spacing('md'), + ...typography('md') + }, + img: { + height: spacing('2xl'), + width: spacing('2xl') + } + } + } + } + } +}; + +export { tokenInput }; diff --git a/packages/core/themeV2/src/themes/bob/tooltip.ts b/packages/core/themeV2/src/themes/bob/tooltip.ts new file mode 100644 index 000000000..f488a1bb5 --- /dev/null +++ b/packages/core/themeV2/src/themes/bob/tooltip.ts @@ -0,0 +1,14 @@ +import { rounded, spacing, typography } from '../../core'; +import { TooltipTheme } from '../../components'; + +import { color } from './colors'; + +const tooltip: TooltipTheme = { + backgroundColor: color('grey-400'), + padding: `${spacing('s')} ${spacing('md')}`, + boxShadow: '0px 0px 10px rgba(0, 0, 0, 0.21)', + borderRadius: rounded('md'), + ...typography('s') +}; + +export { tooltip };