diff --git a/packages/storybook/src/stories/Filters/atoms/ToggleButton.stories.tsx b/packages/storybook/src/stories/Filters/atoms/ToggleButton.stories.tsx new file mode 100644 index 000000000..1673b42fd --- /dev/null +++ b/packages/storybook/src/stories/Filters/atoms/ToggleButton.stories.tsx @@ -0,0 +1,125 @@ +import React, { useCallback, useState } from "react"; +import { ToggleButton } from "scorer-ui-kit"; +import { boolean, object, select, text } from "@storybook/addon-knobs"; +import { action } from "@storybook/addon-actions"; +import styled from "styled-components"; + +export default { + title: 'Filters/atoms', + component: ToggleButton, + decorators: [] +}; + +const layoutOptions = [ + { text: 'Grid', value: 'grid', icon: 'LayoutGrid' }, + { text: 'List', value: 'list', icon: 'LayoutList' } +] + +const CameraData = styled.div``; +const Camera = styled.li``; + +const Container = styled.div``; +const DataGroup = styled.ol<{ layout: string }>` + margin-top: 20px; + display: grid; + ${({ layout }) => layout === 'grid' && + ` + list-style-type: none; + grid-template-columns: repeat(3, 300px); + gap: 16px; + ${Camera} { + padding: 100px 20px; + border: 1px solid var(--grey-9); + text-align: center; + } + ` + }; +`; + +const StatusSpan = styled.span<{ isOnline?: boolean }>` + ${({ isOnline }) => isOnline ? + ` + color: var(--success); + ` + : + ` + color: var(--warning); + `} + `; + +export const _ToggleButton = () => { + const [selectedLayout, setSelectedLayout] = useState(0) + + const disabled = boolean('Disabled', false); + const design = select('Design type', { Default: 'default', Basic: 'basic' }, 'basic'); + const categoryLabel = text('Category Label', 'Layout:'); + const options = object('Options', layoutOptions); + const showToggleValue = action('Button Value: '); + + const onToggle = useCallback((index: number, value: string | number) => { + setSelectedLayout(index); + showToggleValue(value); + }, [showToggleValue]) + + return ( + + + + + + + Camera01 - Online + + + + + Camera02 - Online + + + + + Camera03 - OffLine + + + + + Camera04 - OffLine + + + + + Camera05 - OffLine + + + + + Camera06 - OffLine + + + + + Camera07 - Online + + + + + Camera08 - Online + + + + + Camera09 - Online + + + + + ) +} \ No newline at end of file diff --git a/packages/ui-lib/src/Filters/FilterTypes.ts b/packages/ui-lib/src/Filters/FilterTypes.ts index cb9c48c17..373c11466 100644 --- a/packages/ui-lib/src/Filters/FilterTypes.ts +++ b/packages/ui-lib/src/Filters/FilterTypes.ts @@ -7,6 +7,7 @@ import { IFilterDropdown } from './molecules/FilterDropdown'; type IFilterItem = { text: string; value: string | number; } type IFilterValue = IFilterItem | IFilterItem[] | null; type IFilterType = 'search' | 'dropdown' | 'datepicker'; +type IToggleOption = { text: string; value: string | number; icon: string } // Type checking for IFilterItem // https://stackoverflow.com/questions/14425568/interface-type-check-with-typescript @@ -78,5 +79,6 @@ export type { ISearchFilter, IFilterDropdownExt, IFilterDatePicker, - IFilterDropdownConfig + IFilterDropdownConfig, + IToggleOption, }; \ No newline at end of file diff --git a/packages/ui-lib/src/Filters/atoms/FilterButton.tsx b/packages/ui-lib/src/Filters/atoms/FilterButton.tsx index 36c888a0d..23381482d 100644 --- a/packages/ui-lib/src/Filters/atoms/FilterButton.tsx +++ b/packages/ui-lib/src/Filters/atoms/FilterButton.tsx @@ -5,10 +5,11 @@ import Icon, { IconWrapper } from '../../Icons/Icon'; import { animation } from '../../theme/common'; import { FilterButtonDesign } from '..'; -const FlipWrapper = styled.div<{ isSortAscending: boolean }>` +const LeftIconWrapper = styled.div<{ isSortAscending: boolean }>` ${({ isSortAscending }) => isSortAscending && css` transform: scaleY(-1); `}; + padding: 0 6px; `; const fadeInAnimation = keyframes` @@ -20,17 +21,29 @@ const fadeInAnimation = keyframes` } `; -const FlipArrowContainer = styled.div``; +const FlipArrowContainer = styled.div<{ design?: FilterButtonDesign }>` + ${({ design }) => design === 'default' ? + `padding: 0px 12px 0px 8px;` + : + `padding: 0px 8px;` + }; +`; const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, design?: FilterButtonDesign }>` ${resetButtonStyles}; border-radius: 3px; height: var(--common-height); + display: inline-flex; + align-items: center; + gap: 4px; + flex-shrink: 0; + padding: 4px 10px 4px 4px; - ${({design}) => design === 'basic'? + ${({ design }) => design === 'basic' ? ` background-color: transparent; border: 1px solid transparent; + padding: 4px; ` : ` @@ -40,6 +53,8 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d ` }; + ${({ hasFlipArrow }) => hasFlipArrow && `padding: 4px 0px 4px 4px;`}; + text-align: left; font-size: 12px; font-weight: 500; @@ -56,7 +71,6 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d animation: ${fadeInAnimation} ${animation.speed.slower} ${animation.easing.primary.out}; ${IconWrapper} { - padding: 0 9px; display: flex; align-items: center; [stroke]{ @@ -66,18 +80,18 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d &:hover:enabled, &:active:enabled { color: var(--grey-12); - + ${({design}) => design === 'basic'? '' : css` box-shadow: 0px 4px 9px 0px var(--primary-a2); border-color: var(--primary-7); `}; - + ${IconWrapper} { [stroke]{ stroke: var(--primary-9); } } - + ${({isOpen}) => !isOpen && css` ${FlipArrowContainer} ${IconWrapper} { [stroke]{ @@ -85,7 +99,7 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d } }; `}; - + } &:disabled { @@ -106,7 +120,7 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d } } } - + ${FlipArrowContainer} ${IconWrapper} { [stroke]{ stroke: var(--white-1); @@ -119,13 +133,12 @@ const StyledButton = styled.button<{ isOpen?: boolean, hasFlipArrow?: boolean, d const InnerContainer = styled.div` - display: flex; - align-items: center; + display: flex; + align-items: center; + gap: 4px; `; -const ButtonText = styled.div<{ hasFlipArrow: boolean }>` - padding-right: ${({ hasFlipArrow }) => hasFlipArrow ? '3px' : '20px'}; -`; +const ButtonText = styled.div<{ hasFlipArrow: boolean }>``; interface OwnProps { icon: string @@ -150,18 +163,18 @@ const FilterButton: React.FC = ({ return ( - + - + {children} - - {hasFlipArrow && } - + + {hasFlipArrow && } + ); diff --git a/packages/ui-lib/src/Filters/atoms/ToggleButton.tsx b/packages/ui-lib/src/Filters/atoms/ToggleButton.tsx new file mode 100644 index 000000000..d3eeac0e1 --- /dev/null +++ b/packages/ui-lib/src/Filters/atoms/ToggleButton.tsx @@ -0,0 +1,31 @@ +import React, { useCallback } from 'react'; +import { IToggleOption } from '../FilterTypes'; +import FilterButton from './FilterButton'; +import { FilterButtonDesign } from '..'; + +type IToggleButton = { + options: IToggleOption[] + categoryLabel: String + selectedIndex: number + design?: FilterButtonDesign + onToggle: (index: number, value: string | number) => void +} + +const ToggleButton: React.FC = ({ options, categoryLabel, selectedIndex, design = 'basic', onToggle, ...props }) => { + + const onToggleCallback = useCallback((currentIndex: number) => { + const selected = currentIndex === 1 ? 0 : 1; + onToggle(selected, options[selected].value); + + }, [onToggle, options]); + + if (selectedIndex !== 0 && selectedIndex !== 1) return null; + + return ( + onToggleCallback(selectedIndex)} {...{design}} {...props}> + {`${categoryLabel} : ${options[selectedIndex].text}`} + + ); +}; + +export default ToggleButton; \ No newline at end of file diff --git a/packages/ui-lib/src/Filters/index.ts b/packages/ui-lib/src/Filters/index.ts index 7de7333ce..e99343341 100644 --- a/packages/ui-lib/src/Filters/index.ts +++ b/packages/ui-lib/src/Filters/index.ts @@ -7,6 +7,8 @@ import FilterLayout from './molecules/FilterLayout'; import FilterInputs, { IFilterInputs } from './molecules/FilterInputs'; import FiltersResults, { IFilterLabel } from './molecules/FiltersResults'; import FilterBar from './organisms/FilterBar'; +import ToggleButton from './atoms/ToggleButton'; + import { IFilterType, IFilterItem, @@ -17,6 +19,7 @@ import { IFilterDropdownConfig, IFilterDatePicker, isFilterItem, + IToggleOption, } from './FilterTypes'; export { @@ -31,6 +34,7 @@ export { FilterBar, isFilterItem, isDateInterval, + ToggleButton }; type FilterButtonDesign = 'default' | 'basic' @@ -48,5 +52,6 @@ export type { DateInterval, IFilterDatePicker, FilterButtonDesign, + IToggleOption, DateRange }; diff --git a/packages/ui-lib/src/index.tsx b/packages/ui-lib/src/index.tsx index ec5c8fe72..582ff4a3e 100644 --- a/packages/ui-lib/src/index.tsx +++ b/packages/ui-lib/src/index.tsx @@ -76,7 +76,9 @@ import { IFilterValue, IFilterResult, isFilterItem, - FilterButtonDesign + FilterButtonDesign, + ToggleButton, + IToggleOption } from './Filters'; import Icon, { IconSVGs } from './Icons/Icon'; @@ -279,6 +281,7 @@ export { FilterInputs, FiltersResults, FilterBar, + ToggleButton, isFilterItem, isDateInterval, @@ -419,5 +422,6 @@ export type { AlertType, ITooltipType, FilterButtonDesign, + IToggleOption, DateRange };