From 372c928f31d62c56e9d6914a38b3a4e775ce9441 Mon Sep 17 00:00:00 2001 From: elad Date: Tue, 29 Aug 2023 14:00:05 +0300 Subject: [PATCH] grouped display filters --- .../controlledDisplayFiltersGroup/index.tsx | 47 ++++++++++++++ .../elements/displayFilter/index.tsx | 50 ++++++++++++++ src/components/elements/index.ts | 3 +- src/components/forms/index.ts | 1 + src/components/forms/labeledSwitch/index.tsx | 65 +++++++++++++++++++ src/components/icons/index.tsx | 57 +++++++++++----- .../ControlledDisplayFiltersGroup.stories.tsx | 42 ++++++++++++ .../displayFilter/DisplayFilter.stories.tsx | 18 +++++ .../elements/dropdownV2/dropdown.stories.tsx | 2 +- 9 files changed, 266 insertions(+), 19 deletions(-) create mode 100644 src/components/elements/controlledDisplayFiltersGroup/index.tsx create mode 100644 src/components/elements/displayFilter/index.tsx create mode 100644 src/components/forms/labeledSwitch/index.tsx create mode 100644 src/stories/elements/controlledDisplayFiltersGroup/ControlledDisplayFiltersGroup.stories.tsx create mode 100644 src/stories/elements/displayFilter/DisplayFilter.stories.tsx diff --git a/src/components/elements/controlledDisplayFiltersGroup/index.tsx b/src/components/elements/controlledDisplayFiltersGroup/index.tsx new file mode 100644 index 00000000..9e3aebc5 --- /dev/null +++ b/src/components/elements/controlledDisplayFiltersGroup/index.tsx @@ -0,0 +1,47 @@ +import { useState } from 'react'; +import { Box } from '@mui/material'; +import { DisplayFilter, DisplayFilterProps } from '../displayFilter'; +import React from 'react'; +import { LabeledSwitch } from '../../forms'; + +export interface ControlledDisplayFiltersGroupProps { + filters: DisplayFilterProps[]; + label?: string; + toggleShowAll: (show: boolean) => void; + onFilterChange: (name: string, show: boolean) => void; +} + +export function ControlledDisplayFiltersGroup({ + filters, + onFilterChange, + toggleShowAll, + label +}: ControlledDisplayFiltersGroupProps) { + const [showAll, setShowAll] = useState(false); + + const toggleAll = () => { + setShowAll(!showAll); + toggleShowAll(!showAll); + }; + + const updateFilter = (name: string, show: boolean) => { + onFilterChange(name, show); + }; + + return ( + + + + + {filters.map((item) => { + return ( + updateFilter(item.label, show)} + /> + ); + })} + + ); +} diff --git a/src/components/elements/displayFilter/index.tsx b/src/components/elements/displayFilter/index.tsx new file mode 100644 index 00000000..735585e3 --- /dev/null +++ b/src/components/elements/displayFilter/index.tsx @@ -0,0 +1,50 @@ +import { Stack, Typography } from '@mui/material'; +import React, { useEffect, useState } from 'react'; +import { Icon } from '../../icons'; + +export interface DisplayFilterProps { + label: string; + onChange: (show: boolean) => void; + value: boolean; +} +export function DisplayFilter({ label, onChange, value }: DisplayFilterProps) { + const [show, setShow] = useState(false); + + const filterClicked = () => { + setShow(!show); + onChange(!show); + }; + + useEffect(() => { + setShow(value); + }, [value]); + + return ( + + + {label} + + + + + ); +} diff --git a/src/components/elements/index.ts b/src/components/elements/index.ts index 858e8c18..68b017cf 100644 --- a/src/components/elements/index.ts +++ b/src/components/elements/index.ts @@ -5,4 +5,5 @@ export * from './dropdownV2'; export * from './code-block'; export * from './tooltip'; export * from './genericError'; - +export * from './displayFilter'; +export * from './controlledDisplayFiltersGroup'; diff --git a/src/components/forms/index.ts b/src/components/forms/index.ts index dad067cc..178b0c5f 100644 --- a/src/components/forms/index.ts +++ b/src/components/forms/index.ts @@ -3,3 +3,4 @@ export * from './input'; export * from './textarea'; export * from './radio-button/radio-button-item'; export * from './radio-button/radio-button-list'; +export * from './labeledSwitch'; diff --git a/src/components/forms/labeledSwitch/index.tsx b/src/components/forms/labeledSwitch/index.tsx new file mode 100644 index 00000000..38126c64 --- /dev/null +++ b/src/components/forms/labeledSwitch/index.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import FormGroup from '@mui/material/FormGroup'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Switch, { SwitchProps } from '@mui/material/Switch'; + +const StyledSwitch = styled((props: SwitchProps) => ( + +))(({ theme }) => ({ + width: 48, + height: 24, + padding: 0, + '& .MuiSwitch-switchBase': { + padding: 0, + margin: '2px', + transitionDuration: '300ms', + '&.Mui-checked': { + transform: 'translateX(24px)', + color: '#fff', + '& + .MuiSwitch-track': { + backgroundColor: theme.palette.mode === 'dark' ? '#2ECA45' : '#65C466', + opacity: 1, + border: 0 + }, + '&.Mui-disabled + .MuiSwitch-track': { + opacity: 0.5 + } + }, + '&.Mui-focusVisible .MuiSwitch-thumb': { + color: '#33cf4d', + border: '6px solid #fff' + }, + '&.Mui-disabled .MuiSwitch-thumb': { + color: theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[600] + }, + '&.Mui-disabled + .MuiSwitch-track': { + opacity: theme.palette.mode === 'light' ? 0.7 : 0.3 + } + }, + '& .MuiSwitch-thumb': { + boxSizing: 'border-box', + width: 20, + height: 20 + }, + '& .MuiSwitch-track': { + borderRadius: 23 / 2, + backgroundColor: theme.palette.mode === 'light' ? '#E9E9EA' : '#39393D', + opacity: 1, + transition: theme.transitions.create(['background-color'], { + duration: 500 + }) + } +})); + +export function LabeledSwitch({ onChange, label }: { onChange: () => void; label?: string }) { + return ( + + } + label={label} + /> + + ); +} diff --git a/src/components/icons/index.tsx b/src/components/icons/index.tsx index 20d5e865..19bd814e 100644 --- a/src/components/icons/index.tsx +++ b/src/components/icons/index.tsx @@ -1614,7 +1614,7 @@ export const icons = { ), - 'redirect': ({ fill, width, height, onClick = () => {} }: IconProp) => ( + redirect: ({ fill, width, height, onClick = () => {} }: IconProp) => ( ), - 'beaker': ({ fill, width, height, onClick = () => {} }: IconProp) => ( + beaker: ({ fill, width, height, onClick = () => {} }: IconProp) => ( ), - 'annotations': ({ fill, width, height, onClick = () => {} }: IconProp) => ( + annotations: ({ fill, width, height, onClick = () => {} }: IconProp) => ( ), 'code-tags': ({ fill, width, height, onClick = () => {} }: IconProp) => ( - - - - - - + + + + + ), 'sidebar-collapse': ({ fill, width, height, onClick = () => {} }: IconProp) => ( - - - - - - + + + + + - - ), + + + ) }; export type IconType = keyof typeof icons; diff --git a/src/stories/elements/controlledDisplayFiltersGroup/ControlledDisplayFiltersGroup.stories.tsx b/src/stories/elements/controlledDisplayFiltersGroup/ControlledDisplayFiltersGroup.stories.tsx new file mode 100644 index 00000000..28842254 --- /dev/null +++ b/src/stories/elements/controlledDisplayFiltersGroup/ControlledDisplayFiltersGroup.stories.tsx @@ -0,0 +1,42 @@ +import { Meta, StoryFn } from '@storybook/react'; +import React from 'react'; +import { + ControlledDisplayFiltersGroup, + ControlledDisplayFiltersGroupProps +} from '../../../components'; + +const meta: Meta = { + title: 'Elements/Display filter group', + component: ControlledDisplayFiltersGroup +}; + +export default meta; + +const Template: StoryFn = (args) => ( + +); + +export const ControlledDisplayFilterBasic: StoryFn = + Template.bind({}); +ControlledDisplayFilterBasic.args = { + filters: [ + { + label: 'test label1', + onChange: (value) => console.log('changed', value), + value: false + }, + { + label: 'test label2', + onChange: (value) => console.log('changed', value), + value: false + }, + { + label: 'test label3 ', + onChange: (value) => console.log('changed', value), + value: false + } + ], + onFilterChange: (value) => console.log('show all', value), + toggleShowAll: (value) => console.log('toggle show all', value), + label: 'Grouped display filters example', +}; diff --git a/src/stories/elements/displayFilter/DisplayFilter.stories.tsx b/src/stories/elements/displayFilter/DisplayFilter.stories.tsx new file mode 100644 index 00000000..a293dee4 --- /dev/null +++ b/src/stories/elements/displayFilter/DisplayFilter.stories.tsx @@ -0,0 +1,18 @@ +import { DisplayFilter, DisplayFilterProps } from '../../../components'; +import { Meta, StoryFn } from '@storybook/react'; +import React from 'react'; + +const meta: Meta = { + title: 'Elements/Display filter', + component: DisplayFilter +}; + +export default meta; + +const Template: StoryFn = (args) => ; + +export const DisplayFilterBasic: StoryFn = Template.bind({}); +DisplayFilterBasic.args = { + label: 'test label', + onChange: () => console.log('changed') +}; diff --git a/src/stories/elements/dropdownV2/dropdown.stories.tsx b/src/stories/elements/dropdownV2/dropdown.stories.tsx index b3fd6150..767c9aca 100644 --- a/src/stories/elements/dropdownV2/dropdown.stories.tsx +++ b/src/stories/elements/dropdownV2/dropdown.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Meta, StoryFn } from '@storybook/react'; -import {DropdownV2} from '../../../components'; +import { DropdownV2 } from '../../../components'; import { RadioButtonItemProps } from '../../../components'; const meta: Meta = {