Commit 31a8d6be authored by tom's avatar tom

styles for sort button

parent 3cfd4d1a
......@@ -28,6 +28,7 @@ const RESTRICTED_MODULES = {
{ name: 'ui/shared/chakra/Skeleton', message: 'Please use Skeleton component from toolkit/chakra instead' },
{ name: 'ui/shared/Tabs/RoutedTabs', message: 'Please use RoutedTabs component from toolkit/components/RoutedTabs instead' },
{ name: 'ui/shared/chakra/Tag', message: 'Please use Tag component from toolkit/chakra instead' },
{ name: 'ui/shared/select/Select', message: 'Please use Select component from toolkit/chakra instead' },
{
name: '@chakra-ui/react',
importNames: [
......
......@@ -16,6 +16,7 @@ export const IconButton = React.forwardRef<HTMLDivElement, IconButtonProps>(
<Skeleton loading={ loading } ref={ ref } asChild>
<Button
display="inline-flex"
justifyContent="center"
px="0"
py="0"
{ ...(size ? { size } : { height: 'auto', minW: 'auto' }) }
......
......@@ -4,25 +4,43 @@ import type { CollectionItem } from '@chakra-ui/react';
import { Select as ChakraSelect, Portal } from '@chakra-ui/react';
import * as React from 'react';
import IconSvg from 'ui/shared/IconSvg';
import { CloseButton } from './close-button';
import { Skeleton } from './skeleton';
interface SelectTriggerProps extends ChakraSelect.ControlProps {
export interface SelectControlProps extends ChakraSelect.ControlProps {
clearable?: boolean;
noIndicator?: boolean;
triggerProps?: ChakraSelect.TriggerProps;
loading?: boolean;
}
export const SelectTrigger = React.forwardRef<
export const SelectControl = React.forwardRef<
HTMLButtonElement,
SelectTriggerProps
>(function SelectTrigger(props, ref) {
const { children, clearable, ...rest } = props;
SelectControlProps
>(function SelectControl(props, ref) {
const { children, clearable, noIndicator, triggerProps, loading, ...rest } = props;
return (
<ChakraSelect.Control { ...rest }>
<ChakraSelect.Trigger ref={ ref }>{ children }</ChakraSelect.Trigger>
<ChakraSelect.IndicatorGroup>
{ clearable && <SelectClearTrigger/> }
<ChakraSelect.Indicator/>
</ChakraSelect.IndicatorGroup>
</ChakraSelect.Control>
<Skeleton loading={ loading } asChild>
<ChakraSelect.Control { ...rest } className="group">
<ChakraSelect.Trigger ref={ ref } { ...triggerProps }>{ children }</ChakraSelect.Trigger>
{ (!noIndicator || clearable) && (
<ChakraSelect.IndicatorGroup>
{ clearable && <SelectClearTrigger/> }
{ !noIndicator && (
<ChakraSelect.Indicator
transform="rotate(-90deg)"
_open={{ transform: 'rotate(90deg)' }}
flexShrink={ 0 }
>
<IconSvg name="arrows/east-mini"/>
</ChakraSelect.Indicator>
) }
</ChakraSelect.IndicatorGroup>
) }
</ChakraSelect.Control>
</Skeleton>
);
});
......@@ -68,8 +86,10 @@ export const SelectItem = React.forwardRef<
const { item, children, ...rest } = props;
return (
<ChakraSelect.Item key={ item.value } item={ item } { ...rest } ref={ ref }>
<ChakraSelect.ItemIndicator asChild>
<IconSvg name="check" boxSize={ 5 } flexShrink={ 0 }/>
</ChakraSelect.ItemIndicator>
{ children }
<ChakraSelect.ItemIndicator/>
</ChakraSelect.Item>
);
});
......@@ -100,6 +120,8 @@ export const SelectValueText = React.forwardRef<
);
});
export interface SelectRootProps extends ChakraSelect.RootProps {}
export const SelectRoot = React.forwardRef<
HTMLDivElement,
ChakraSelect.RootProps
......@@ -108,7 +130,7 @@ export const SelectRoot = React.forwardRef<
<ChakraSelect.Root
{ ...props }
ref={ ref }
positioning={{ sameWidth: true, ...props.positioning }}
positioning={{ sameWidth: false, ...props.positioning }}
>
{ props.asChild ? (
props.children
......
......@@ -238,15 +238,26 @@ const semanticTokens: ThemingConfig['semanticTokens'] = {
},
},
select: {
fg: {
DEFAULT: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
hover: { value: '{colors.blue.400}' },
error: { value: '{colors.red.500}' },
trigger: {
outline: {
fg: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
border: { value: { _light: '{colors.gray.200}', _dark: '{colors.gray.600}' } },
},
filter: {
fg: {
DEFAULT: { value: { _light: '{colors.blackAlpha.800}', _dark: '{colors.whiteAlpha.800}' } },
selected: { value: { _light: '{colors.blue.600}', _dark: '{colors.gray.50}' } },
},
border: {
DEFAULT: { value: { _light: '{colors.gray.200}', _dark: '{colors.gray.600}' } },
selected: { value: { _light: '{colors.blue.50}', _dark: '{colors.gray.600}' } },
},
},
},
border: {
DEFAULT: { value: { _light: '{colors.gray.300}', _dark: '{colors.gray.600}' } },
hover: { value: '{colors.blue.400}' },
error: { value: '{colors.red.500}' },
item: {
bg: {
highlighted: { value: { _light: '{colors.blue.50}', _dark: '{colors.whiteAlpha.100}' } },
},
},
},
spinner: {
......
......@@ -10,6 +10,7 @@ export const recipe = defineRecipe({
width: 'fit-content',
maxWidth: '100%',
whiteSpace: 'nowrap',
fontVariantNumeric: 'normal',
userSelect: 'none',
_loading: {
borderRadius: 'sm',
......
......@@ -13,24 +13,20 @@ export const recipe = defineSlotRecipe({
trigger: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
justifyContent: 'flex-start',
width: 'full',
minH: 'var(--select-trigger-height)',
px: 'var(--select-trigger-padding-x)',
pr: 'var(--select-trigger-padding-right)',
pl: 'var(--select-trigger-padding-left)',
borderRadius: 'base',
userSelect: 'none',
textAlign: 'start',
fontWeight: '500',
fontWeight: 'semibold',
cursor: 'pointer',
focusVisibleRing: 'none',
_placeholderShown: {
color: 'gray.500',
},
_disabled: {
layerStyle: 'disabled',
},
_invalid: {
borderColor: 'select.border.error',
},
},
indicatorGroup: {
display: 'flex',
......@@ -40,7 +36,7 @@ export const recipe = defineSlotRecipe({
right: '0',
top: '0',
bottom: '0',
px: 'var(--select-trigger-padding-x)',
px: '0',
pointerEvents: 'none',
},
indicator: {
......@@ -48,17 +44,27 @@ export const recipe = defineSlotRecipe({
alignItems: 'center',
justifyContent: 'center',
color: 'inherit',
_groupHover: {
color: 'link.primary.hover',
},
_open: {
color: 'link.primary.hover',
},
},
content: {
background: 'popover.bg',
display: 'flex',
flexDirection: 'column',
zIndex: 'dropdown',
borderRadius: 'base',
borderRadius: 'md',
borderWidth: '0',
outline: 0,
boxShadow: 'popover',
boxShadowColor: 'colors.popover.shadow',
maxH: '96',
overflowY: 'auto',
boxShadow: 'md',
width: 'max-content',
minWidth: '150px',
_open: {
animationStyle: 'slide-fade-in',
animationDuration: 'fast',
......@@ -74,14 +80,11 @@ export const recipe = defineSlotRecipe({
display: 'flex',
alignItems: 'center',
gap: '2',
cursor: 'option',
justifyContent: 'space-between',
cursor: 'pointer',
justifyContent: 'flex-start',
flex: '1',
textAlign: 'start',
borderRadius: 'base',
_highlighted: {
bg: 'bg.emphasized/60',
},
borderRadius: 'none',
_disabled: {
pointerEvents: 'none',
opacity: '0.5',
......@@ -90,6 +93,9 @@ export const recipe = defineSlotRecipe({
width: '4',
height: '4',
},
_highlighted: {
bg: 'select.item.bg.highlighted',
},
},
control: {
pos: 'relative',
......@@ -122,76 +128,110 @@ export const recipe = defineSlotRecipe({
variant: {
outline: {
trigger: {
bg: 'transparent',
borderWidth: '2px',
borderColor: 'select.border',
color: 'select.trigger.outline.fg',
bgColor: 'transparent',
borderColor: 'select.trigger.outline.border',
_expanded: {
borderColor: 'select.border.hover',
color: 'link.primary.hover',
borderColor: 'link.primary.hover',
},
_hover: {
borderColor: 'select.border.hover',
color: 'link.primary.hover',
borderColor: 'link.primary.hover',
},
_focusVisible: {
borderColor: 'select.border.hover',
borderColor: 'link.primary.hover',
focusVisibleRing: 'none',
},
_invalid: {
borderColor: 'border.error',
},
},
},
},
size: {
xs: {
root: {
'--select-trigger-height': 'sizes.8',
'--select-trigger-padding-x': 'spacing.2',
},
content: {
p: '1',
gap: '1',
textStyle: 'xs',
},
filter: {
trigger: {
textStyle: 'xs',
gap: '1',
},
item: {
py: '1',
px: '2',
},
itemGroupLabel: {
py: '1',
px: '2',
borderWidth: '2px',
color: 'select.trigger.filter.fg.selected',
bgColor: 'select.trigger.filter.border.selected',
borderColor: 'select.trigger.filter.border.selected',
_expanded: {
color: 'link.primary.hover',
borderColor: 'link.primary.hover',
},
_hover: {
color: 'select.trigger.filter.fg.selected',
borderColor: 'select.trigger.filter.border.selected',
},
_focusVisible: {
borderColor: 'link.primary.hover',
focusVisibleRing: 'none',
},
_placeholderShown: {
color: 'select.trigger.filter.fg',
borderColor: 'select.trigger.filter.border',
bgColor: 'transparent',
_hover: {
color: 'link.primary.hover',
borderColor: 'link.primary.hover',
},
},
},
indicator: {
_icon: {
width: '3.5',
height: '3.5',
},
sort: {
trigger: {
borderWidth: '2px',
borderColor: 'transparent',
bgColor: 'transparent',
_hover: {
color: 'link.primary.hover',
borderColor: 'link.primary.hover',
},
_open: {
bg: 'button.dropdown.border.selected',
color: 'button.dropdown.fg.selected',
borderColor: 'button.dropdown.border.selected',
_hover: {
bg: 'button.dropdown.border.selected',
color: 'button.dropdown.fg.selected',
borderColor: 'button.dropdown.border.selected',
},
},
},
},
},
size: {
sm: {
root: {
'--select-trigger-height': 'sizes.9',
'--select-trigger-padding-x': 'spacing.2.5',
'--select-trigger-height': 'sizes.8',
'--select-trigger-padding-right': 'spacing.8',
'--select-trigger-padding-left': 'spacing.2',
},
content: {
p: '1',
textStyle: 'sm',
px: '0',
py: '2',
textStyle: 'md',
},
trigger: {
textStyle: 'sm',
gap: '1',
},
indicator: {
_icon: {
width: '4',
height: '4',
},
width: '5',
height: '5',
},
indicatorGroup: {
pr: '2',
pl: '1',
},
item: {
py: '1',
px: '1.5',
py: '2',
pr: '4',
pl: '44px',
_selected: {
px: '4',
},
},
itemGroup: {
mt: '1',
......@@ -201,81 +241,11 @@ export const recipe = defineSlotRecipe({
px: '1.5',
},
},
md: {
root: {
'--select-trigger-height': 'sizes.10',
'--select-trigger-padding-x': 'spacing.3',
},
content: {
p: '1',
textStyle: 'sm',
},
itemGroup: {
mt: '1.5',
},
item: {
py: '1.5',
px: '2',
},
itemIndicator: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
itemGroupLabel: {
py: '1.5',
px: '2',
},
trigger: {
textStyle: 'sm',
gap: '2',
},
indicator: {
_icon: {
width: '4',
height: '4',
},
},
},
lg: {
root: {
'--select-trigger-height': 'sizes.12',
'--select-trigger-padding-x': 'spacing.4',
},
content: {
p: '1.5',
textStyle: 'md',
},
itemGroup: {
mt: '2',
},
item: {
py: '2',
px: '3',
},
itemGroupLabel: {
py: '2',
px: '3',
},
trigger: {
textStyle: 'md',
py: '3',
gap: '2',
},
indicator: {
_icon: {
width: '5',
height: '5',
},
},
},
},
},
defaultVariants: {
size: 'md',
size: 'sm',
variant: 'outline',
},
});
......@@ -191,7 +191,7 @@ export interface TransactionsSorting {
export type TransactionsSortingField = TransactionsSorting['sort'];
export type TransactionsSortingValue = `${ TransactionsSortingField }-${ TransactionsSorting['order'] }`;
export type TransactionsSortingValue = `${ TransactionsSortingField }-${ TransactionsSorting['order'] }` | 'default';
export type ScrollTransactionData = {
l1_fee: string;
......
/* eslint-disable max-len */
/* eslint-disable react/jsx-no-bind */
import { createListCollection, HStack, Spinner, VStack } from '@chakra-ui/react';
import { HStack, Spinner, VStack } from '@chakra-ui/react';
import React from 'react';
import { Button } from 'toolkit/chakra/button';
......@@ -12,7 +12,6 @@ import { InputGroup } from 'toolkit/chakra/input-group';
import { NativeSelectField, NativeSelectRoot } from 'toolkit/chakra/native-select';
import { PinInput } from 'toolkit/chakra/pin-input';
import { ProgressCircleRing, ProgressCircleRoot } from 'toolkit/chakra/progress-circle';
import { SelectContent, SelectItem, SelectRoot, SelectTrigger, SelectValueText } from 'toolkit/chakra/select';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Switch } from 'toolkit/chakra/switch';
import { TabsContent, TabsList, TabsRoot, TabsTrigger } from 'toolkit/chakra/tabs';
......@@ -27,6 +26,7 @@ import BadgesShowcase from 'ui/showcases/Badges';
import ButtonShowcase from 'ui/showcases/Button';
import LinksShowcase from 'ui/showcases/Links';
import PaginationShowcase from 'ui/showcases/Pagination';
import SelectsShowcase from 'ui/showcases/Select';
import TabsShowcase from 'ui/showcases/Tabs';
import TagsShowcase from 'ui/showcases/Tags';
import TooltipsShowcase from 'ui/showcases/Tooltip';
......@@ -36,15 +36,6 @@ const TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do ei
const ChakraShowcases = () => {
const colorMode = useColorMode();
const frameworks = createListCollection({
items: [
{ label: 'React.js', value: 'react' },
{ label: 'Vue.js', value: 'vue' },
{ label: 'Angular', value: 'angular' },
{ label: 'Svelte', value: 'svelte' },
],
});
return (
<>
<PageTitle title="Chakra UI Showcase"/>
......@@ -60,6 +51,7 @@ const ChakraShowcases = () => {
<TabsTrigger value="buttons">Buttons</TabsTrigger>
<TabsTrigger value="links">Links</TabsTrigger>
<TabsTrigger value="pagination">Pagination</TabsTrigger>
<TabsTrigger value="selects">Selects</TabsTrigger>
<TabsTrigger value="tabs">Tabs</TabsTrigger>
<TabsTrigger value="tags">Tags</TabsTrigger>
<TabsTrigger value="tooltips">Tooltips</TabsTrigger>
......@@ -72,6 +64,7 @@ const ChakraShowcases = () => {
<LinksShowcase/>
<TabsShowcase/>
<PaginationShowcase/>
<SelectsShowcase/>
<TooltipsShowcase/>
<TagsShowcase/>
......@@ -194,18 +187,6 @@ const ChakraShowcases = () => {
<section>
<Heading textStyle="heading.md" mb={ 2 }>Select</Heading>
<HStack gap={ 4 } whiteSpace="nowrap" flexWrap="wrap">
<SelectRoot collection={ frameworks }>
<SelectTrigger w="350px">
<SelectValueText placeholder="Select framework"/>
</SelectTrigger>
<SelectContent>
{ frameworks.items.map((framework) => (
<SelectItem item={ framework } key={ framework.value }>
{ framework.label }
</SelectItem>
)) }
</SelectContent>
</SelectRoot>
<NativeSelectRoot w="350px">
<NativeSelectField>
<option value="1">Option 1</option>
......
......@@ -13,13 +13,13 @@ interface Props extends Omit<HTMLChakraProps<'div'>, 'direction'> {
const WIDTH = 50;
const Utilization = ({ value, colorScheme = 'green', isLoading, ...rest }: Props) => {
const Utilization = ({ value, colorScheme = 'green', isLoading, ...rest }: Props, ref: React.Ref<HTMLDivElement>) => {
const valueString = (clamp(value * 100 || 0, 0, 100)).toLocaleString(undefined, { maximumFractionDigits: 2 }) + '%';
const colorGrayScheme = { _light: 'gray.500', _dark: 'gray.400' };
const color = colorScheme === 'gray' ? colorGrayScheme : 'green.500';
return (
<Flex alignItems="center" columnGap={ 2 } { ...rest }>
<Flex alignItems="center" columnGap={ 2 } { ...rest } ref={ ref }>
<Skeleton loading={ isLoading } w={ `${ WIDTH }px` } h="4px" borderRadius="full" overflow="hidden">
<Box bg={{ _light: 'blackAlpha.200', _dark: 'whiteAlpha.200' }} h="100%">
<Box bg={ color } w={ valueString } h="100%"/>
......@@ -34,4 +34,4 @@ const Utilization = ({ value, colorScheme = 'green', isLoading, ...rest }: Props
);
};
export default React.memo(Utilization);
export default React.memo(React.forwardRef(Utilization));
......@@ -24,6 +24,7 @@ export interface Props<Value extends string> {
children?: (props: InjectedProps<Value>) => React.ReactNode;
}
// TODO @tom2drum remove this component
const Select = <Value extends string>({ className, isLoading, options, name, defaultValue, onChange, children }: Props<Value>) => {
const { isOpen, onToggle, onClose } = useDisclosure();
......
export interface SelectOption<Value extends string = string> {
value: Value | undefined;
value: Value;
label: string;
}
import {
Box,
useColorModeValue,
Button,
chakra,
} from '@chakra-ui/react';
import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton';
import IconSvg from 'ui/shared/IconSvg';
type ButtonProps = {
isActive: boolean;
onClick: () => void;
isLoading?: boolean;
children: React.ReactNode;
className?: string;
};
const ButtonDesktop = ({ children, isActive, onClick, isLoading, className }: ButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
const primaryColor = useColorModeValue('blackAlpha.800', 'whiteAlpha.800');
const secondaryColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
return (
<Skeleton isLoaded={ !isLoading }>
<Button
className={ className }
ref={ ref }
size="sm"
variant="outline"
onClick={ onClick }
color={ primaryColor }
fontWeight="600"
borderColor="transparent"
px={ 2 }
selected={ isActive }
>
<Box
as={ isActive ? 'div' : 'span' }
color={ isActive ? 'inherit' : secondaryColor }
fontWeight="400"
mr={ 1 }
transition={ isActive ? 'none' : 'inherit' }
>Sort by</Box>
{ children }
<IconSvg
name="arrows/east-mini"
boxSize={ 5 }
ml={ 1 }
transform={ isActive ? 'rotate(90deg)' : 'rotate(-90deg)' }
/>
</Button>
</Skeleton>
);
};
export default chakra(React.forwardRef(ButtonDesktop));
import { IconButton, chakra } from '@chakra-ui/react';
import React from 'react';
import Skeleton from 'ui/shared/chakra/Skeleton';
import IconSvg from 'ui/shared/IconSvg';
type Props = {
onClick: () => void;
isActive: boolean;
className?: string;
isLoading?: boolean;
};
const ButtonMobile = ({ onClick, isActive, className, isLoading }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => {
if (isLoading) {
return <Skeleton className={ className } w="36px" h="32px" borderRadius="base"/>;
}
return (
<IconButton
ref={ ref }
icon={ <IconSvg name="arrows/up-down" boxSize={ 5 }/> }
aria-label="sort"
size="sm"
variant="outline"
colorScheme="gray"
minWidth="36px"
onClick={ onClick }
isActive={ isActive }
display="flex"
className={ className }
/>
);
};
export default chakra(React.forwardRef(ButtonMobile));
import { chakra } from '@chakra-ui/react';
import React from 'react';
import type { SelectOption } from 'ui/shared/select/types';
import useIsMobile from 'lib/hooks/useIsMobile';
import Select, { type Props as SelectProps } from 'ui/shared/select/Select';
import SortButtonDesktop from './ButtonDesktop';
import SortButtonMobile from './ButtonMobile';
import { IconButton } from 'toolkit/chakra/icon-button';
import type { SelectRootProps, SelectControlProps } from 'toolkit/chakra/select';
import { SelectContent, SelectItem, SelectRoot, SelectControl, SelectValueText } from 'toolkit/chakra/select';
import IconSvg from 'ui/shared/IconSvg';
type Props<Value extends string> = Omit<SelectProps<Value>, 'children'>;
export interface Props extends SelectRootProps {
controlProps?: SelectControlProps;
isLoading?: boolean;
}
const Sort = <Sort extends string>({ name, options, isLoading, onChange, defaultValue }: Props<Sort>) => {
const Sort = (props: Props) => {
const { collection, controlProps, isLoading, ...rest } = props;
const isMobile = useIsMobile(false);
const trigger = (() => {
if (isMobile) {
return (
<SelectControl { ...controlProps } triggerProps={{ asChild: true }} noIndicator>
<IconButton
loading={ isLoading }
aria-label="sort"
size="sm"
variant="outline"
colorScheme="gray"
width="36px"
>
<IconSvg name="arrows/up-down" boxSize={ 5 }/>
</IconButton>
</SelectControl>
);
}
return (
<SelectControl
{ ...controlProps }
loading={ isLoading }
>
<chakra.span
flexShrink={ 0 }
fontWeight="normal"
color={{ _light: 'blackAlpha.600', _dark: 'whiteAlpha.600' }}
_groupHover={{ color: 'inherit' }}
>
Sort by
</chakra.span>
<SelectValueText
color={{ _light: 'blackAlpha.800', _dark: 'whiteAlpha.800' }}
_groupHover={{ color: 'inherit' }}
/>
</SelectControl>
);
})();
return (
<Select
options={ options }
name={ name }
defaultValue={ defaultValue }
onChange={ onChange }
>
{ ({ isOpen, onToggle, value }) => {
return (
isMobile ? (
<SortButtonMobile isActive={ isOpen || Boolean(value) } onClick={ onToggle } isLoading={ isLoading }/>
) : (
<SortButtonDesktop isActive={ isOpen } isLoading={ isLoading } onClick={ onToggle }>
{ options.find((option: SelectOption<Sort>) => option.value === value || (!option.value && !value))?.label }
</SortButtonDesktop>
)
);
} }
</Select>
<SelectRoot variant={{ lgDown: 'outline', lg: 'sort' }} collection={ collection } { ...rest }>
{ trigger }
<SelectContent>
{ collection.items.map((item) => (
<SelectItem item={ item } key={ item.value }>
{ item.label }
</SelectItem>
)) }
</SelectContent>
</SelectRoot>
);
};
......
export default function getNextSortValue<SortField extends string, Sort extends string>(
sortSequence: Record<SortField, Array<Sort | undefined>>, field: SortField,
sortSequence: Record<SortField, Array<Sort>>, field: SortField,
) {
return (prevValue: Sort | undefined) => {
return (prevValue: Sort) => {
const sequence = sortSequence[field];
return getNextValueFromSequence(sequence, prevValue);
};
......
import { createListCollection } from '@chakra-ui/react';
import React from 'react';
import { SelectContent, SelectItem, SelectRoot, SelectControl, SelectValueText } from 'toolkit/chakra/select';
import Sort from 'ui/shared/sort/Sort';
import { SORT_OPTIONS } from 'ui/txs/useTxsSort';
import { Section, Container, SectionHeader, SamplesStack, Sample, SectionSubHeader } from './parts';
const frameworks = createListCollection({
items: [
{ label: 'React.js', value: 'react' },
{ label: 'Vue.js', value: 'vue' },
{ label: 'Angular', value: 'angular' },
{ label: 'Svelte', value: 'svelte' },
],
});
const txSortingOptions = createListCollection({
items: SORT_OPTIONS,
});
const SelectsShowcase = () => {
return (
<Container value="selects">
<Section>
<SectionHeader>Variant</SectionHeader>
<SamplesStack>
<Sample label="variant: outline">
<SelectRoot collection={ frameworks } variant="outline" defaultValue={ [ frameworks.items[0].value ] }>
<SelectControl w="200px">
<SelectValueText placeholder="Select framework"/>
</SelectControl>
<SelectContent>
{ frameworks.items.map((framework) => (
<SelectItem item={ framework } key={ framework.value }>
{ framework.label }
</SelectItem>
)) }
</SelectContent>
</SelectRoot>
</Sample>
<Sample label="variant: filter">
<SelectRoot collection={ frameworks } variant="filter" multiple>
<SelectControl w="200px">
<SelectValueText placeholder="Select framework"/>
</SelectControl>
<SelectContent>
{ frameworks.items.map((framework) => (
<SelectItem item={ framework } key={ framework.value }>
{ framework.label }
</SelectItem>
)) }
</SelectContent>
</SelectRoot>
</Sample>
</SamplesStack>
</Section>
<Section>
<SectionHeader>Examples</SectionHeader>
<SectionSubHeader>Sort</SectionSubHeader>
<SamplesStack>
<Sample>
<Sort
name="transactions_sorting"
defaultValue={ [ txSortingOptions.items[0].value ] }
collection={ txSortingOptions }
/>
<Sort
name="transactions_sorting"
defaultValue={ [ txSortingOptions.items[0].value ] }
collection={ txSortingOptions }
isLoading
/>
</Sample>
</SamplesStack>
</Section>
</Container>
);
};
export default React.memo(SelectsShowcase);
......@@ -16,10 +16,10 @@ import TxsHeaderMobile from './TxsHeaderMobile';
import TxsList from './TxsList';
import TxsTable from './TxsTable';
const SORT_SEQUENCE: Record<TransactionsSortingField, Array<TransactionsSortingValue | undefined>> = {
value: [ 'value-desc', 'value-asc', undefined ],
fee: [ 'fee-desc', 'fee-asc', undefined ],
block_number: [ 'block_number-asc', undefined ],
const SORT_SEQUENCE: Record<TransactionsSortingField, Array<TransactionsSortingValue>> = {
value: [ 'value-desc', 'value-asc', 'default' ],
fee: [ 'fee-desc', 'fee-asc', 'default' ],
block_number: [ 'block_number-asc', 'default' ],
};
type Props = {
......@@ -37,8 +37,8 @@ type Props = {
items?: Array<Transaction>;
isPlaceholderData: boolean;
isError: boolean;
setSorting: (value: TransactionsSortingValue | undefined) => void;
sort: TransactionsSortingValue | undefined;
setSorting: (value: TransactionsSortingValue) => void;
sort: TransactionsSortingValue;
};
const TxsContent = ({
......
import { HStack, chakra } from '@chakra-ui/react';
import { HStack, chakra, createListCollection } from '@chakra-ui/react';
import React from 'react';
import type { TransactionsSortingValue } from 'types/api/transaction';
......@@ -15,8 +15,8 @@ import { SORT_OPTIONS } from './useTxsSort';
// import TxsFilters from './TxsFilters';
type Props = {
sorting: TransactionsSortingValue | undefined;
setSorting: (val: TransactionsSortingValue | undefined) => void;
sorting: TransactionsSortingValue;
setSorting: (val: TransactionsSortingValue) => void;
paginationProps: PaginationParams;
className?: string;
showPagination?: boolean;
......@@ -24,19 +24,26 @@ type Props = {
linkSlot?: React.ReactNode;
};
const collection = createListCollection({
items: SORT_OPTIONS,
});
const TxsHeaderMobile = ({ filterComponent, sorting, setSorting, paginationProps, className, showPagination = true, linkSlot }: Props) => {
const handleSortValueChange = React.useCallback(({ value }: { value: Array<string> }) => {
setSorting(value[0] as TransactionsSortingValue);
}, [ setSorting ]);
return (
<ActionBar className={ className }>
<HStack>
{ filterComponent }
{ /* TODO @tom2drum fix sort select */ }
{ /* <Sort
<Sort
name="transactions_sorting"
defaultValue={ sorting }
options={ SORT_OPTIONS }
onChange={ setSorting }
defaultValue={ [ sorting ] }
collection={ collection }
onValueChange={ handleSortValueChange }
isLoading={ paginationProps.isLoading }
/> */ }
/>
{ /* api is not implemented */ }
{ /* <FilterInput
// eslint-disable-next-line react/jsx-no-bind
......
......@@ -10,7 +10,7 @@ import * as cookies from 'lib/cookies';
import sortTxs from './sortTxs';
export const SORT_OPTIONS: Array<SelectOption<TransactionsSortingValue>> = [
{ label: 'Default', value: undefined },
{ label: 'Default', value: 'default' },
{ label: 'Value ascending', value: 'value-asc' },
{ label: 'Value descending', value: 'value-desc' },
{ label: 'Fee ascending', value: 'fee-asc' },
......@@ -18,7 +18,7 @@ export const SORT_OPTIONS: Array<SelectOption<TransactionsSortingValue>> = [
{ label: 'Block number ascending', value: 'block_number-asc' },
];
type SortingValue = TransactionsSortingValue | undefined;
type SortingValue = TransactionsSortingValue;
type HookResult = UseQueryResult<TxsResponse, ResourceError<unknown>> & {
sorting: SortingValue;
......@@ -29,11 +29,11 @@ export default function useTxsSort(
queryResult: UseQueryResult<TxsResponse, ResourceError<unknown>>,
): HookResult {
const [ sorting, setSorting ] = React.useState<SortingValue>(cookies.get(cookies.NAMES.TXS_SORT) as SortingValue);
const [ sorting, setSorting ] = React.useState<SortingValue>((cookies.get(cookies.NAMES.TXS_SORT) as SortingValue | undefined) ?? 'default');
const setSortByValue = React.useCallback((value: SortingValue) => {
setSorting((prevVal: SortingValue) => {
let newVal: SortingValue = undefined;
let newVal: SortingValue = 'default';
if (value !== prevVal) {
newVal = value as SortingValue;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment