Skip to content

Commit

Permalink
Added Slider component to library
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
  • Loading branch information
Benjamin Perez committed Jan 16, 2024
1 parent b0b0419 commit 94b2533
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 0 deletions.
109 changes: 109 additions & 0 deletions src/components/Slider/Slider.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// This file is part of MinIO Design System
// Copyright (c) 2024 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import { Meta, Story } from "@storybook/react";

import Slider from "./Slider";
import { SliderProps } from "./Slider.types";

import StoryThemeProvider from "../../utils/StoryThemeProvider";
import GlobalStyles from "../GlobalStyles/GlobalStyles";
import FormLayout from "../FormLayout/FormLayout";
import TestIcon from "../../utils/TestIcon";
import Box from "../Box/Box";
import UsersIcon from "../Icons/UsersIcon";
import PasswordKeyIcon from "../Icons/PasswordKeyIcon";
import {useState} from "react";

export default {
title: "MDS/Forms/Slider",
component: Slider,
argTypes: {},
} as Meta<typeof Slider>;

const Template: Story<SliderProps> = (args) => {
const [value, setValue] = useState<number>(0);
return (
<StoryThemeProvider>
<GlobalStyles />
<FormLayout>
<Slider value={value} onChange={(e) => {setValue(e.target.value)}} {...args} />
</FormLayout>
</StoryThemeProvider>
)};

export const Default = Template.bind({});
Default.args = {
label: "Slide to select a value",
required: true,
};

export const DisabledSlider = Template.bind({});
DisabledSlider.args = {
label: "Slide to select a value",
required: true,
disabled: true,
value: "Demo Text",
};

export const ErrorSlider = Template.bind({});
ErrorSlider.args = {
label: "Slider with Error",
required: true,
error: "This is an error message",
};

export const WithTooltip = Template.bind({});
WithTooltip.args = {
label: "Slide to select a value",
required: true,
tooltip: "Tooltip text",
};

export const DisplayValue = Template.bind({});
DisplayValue.args = {
label: "Slide with visible value",
required: true,
tooltip: "Tooltip text",
displayValue: true,
};

export const CustomDisplayFunction = Template.bind({});
CustomDisplayFunction.args = {
label: "Slide with visible value",
required: true,
tooltip: "Tooltip text",
displayValue: true,
min: 0,
max: 10,
step: 1,
marks: true,
displayValueFunction: (value) => {
return `${value} % Reduction`
}
};

export const WithSteps = Template.bind({});
WithSteps.args = {
label: "Slide with visible value",
required: true,
tooltip: "Tooltip text",
displayValue: true,
min: 0,
max: 10,
step: 1,
marks: true,
};
213 changes: 213 additions & 0 deletions src/components/Slider/Slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// This file is part of MinIO Design System
// Copyright (c) 2024 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import React, {FC} from "react";
import styled, {CSSObject} from "styled-components";
import get from "lodash/get";
import HelpIcon from "../Icons/HelpIcon";
import Tooltip from "../Tooltip/Tooltip";
import InputLabel from "../InputLabel/InputLabel";
import Box from "../Box/Box";
import {SliderContainerProps, SliderProps} from "./Slider.types";
import {lightColors} from "../../global/themes";

const InputBase = styled.input(({theme}) => {
const thumb: CSSObject = {
"-webkit-appearance": "none",
appearance: "none",
backgroundColor: get(theme, "slider.bulletBG", lightColors.bulletColor),
height: 15,
width: 15,
borderRadius: "100%",
};

return {
'&[type="range"]': {
width: "100%",
height: 6,
zIndex: 100,
margin: 0,
"-webkit-appearance": "none",
appearance: "none",
background: "transparent",
cursor: "pointer",
"&:focus": {
outline: "none",
},
"&::-webkit-slider-thumb": {
...thumb,
},
"&::-moz-range-thumb": {
...thumb,
border: "none",
},
},
'&[type="range"]:disabled': {
cursor: "not-allowed",
"&::-webkit-slider-thumb": {
backgroundColor: get(theme, "slider.disabledBullet", lightColors.disabledGrey),
},
"&::-moz-range-thumb": {
backgroundColor: get(theme, "slider.disabledBullet", lightColors.disabledGrey),
},
}
};
});

const SliderContainer = styled.div<SliderContainerProps>(
({theme, error, sx}) => ({
display: "flex",
alignItems: "center",
flexGrow: 1,
width: "100%",
"& .errorText": {
fontSize: 12,
color: get(theme, "inputBox.error", "#C51B3F"),
marginTop: 3,
},
"& .textBoxContainer": {
width: "100%",
flexGrow: 1,
position: "relative",
minWidth: 160,
},
"& .tooltipContainer": {
marginLeft: 5,
display: "flex",
alignItems: "center",
"& .min-icon": {
width: 13,
},
},
"& .inputLabel": {
marginBottom: error ? 18 : 0,
},
"& .displayValue": {
fontSize: 12,
fontWeight: "bold",
},
...sx,
}),
);

const BackBar = styled.div(({theme}) => ({
position: "absolute",
width: "100%",
height: 6,
top: "50%",
transform: "translateY(-50%)",
backgroundColor: get(theme, "slider.railBG", lightColors.borderColor),
borderRadius: 15,
display: "flex",
alignItems: "center",
zIndex: 90,
"&.disabled": {
backgroundColor: get(theme, "slider.disabledRail", lightColors.disabledBGGrey),
}
}));

const Slider: FC<SliderProps & React.InputHTMLAttributes<HTMLInputElement>> = ({
id,
tooltip = "",
noLabelMinWidth,
label = "",
required,
className,
error,
sx,
helpTip,
helpTipPlacement,
min = 0,
max = 100,
type,
value,
displayValue,
displayValueFunction,
step = 1,
disabled=false,
...props
}) => {

return (
<SliderContainer
error={!!error && error !== ""}
sx={sx}
className={`slider ${className}`}
>
{label !== "" && (
<InputLabel
htmlFor={id}
noMinWidth={noLabelMinWidth}
className={"inputLabel"}
helpTip={helpTip}
helpTipPlacement={helpTipPlacement}
>
{label}
{required ? "*" : ""}
{tooltip !== "" && (
<Box className={"tooltipContainer"}>
<Tooltip tooltip={tooltip} placement="top">
<Box className={tooltip}>
<HelpIcon/>
</Box>
</Tooltip>
</Box>
)}
</InputLabel>
)}

<Box className={"textBoxContainer"}>
<Box sx={{
display: "flex",
alignItems: "center",
gap: 8,
}}>
<Box sx={{
flexGrow: 1,
position: "relative",
height: 6,
display: "flex",
alignItems: "flex-start"
}}>
<InputBase
id={id}
type={"range"}
className={"rangeSelector"}
min={min}
max={max}
step={step}
disabled={disabled}
{...props}
/>
<BackBar className={`${disabled ? "disabled" : ""}`}/>
</Box>
{!!displayValue ? (
<span className={"displayValue"}>
{displayValueFunction ? (
displayValueFunction(value || 0)
) : (
value
)}
</span>
) : null}
</Box>
{error !== "" && <Box className={"errorText"}>{error}</Box>}
</Box>
</SliderContainer>
);
};

export default Slider;
39 changes: 39 additions & 0 deletions src/components/Slider/Slider.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This file is part of MinIO Design System
// Copyright (c) 2024 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from "react";
import {CSSObject} from "styled-components";
import {CommonHelpTipPlacement} from "../HelpTip/HelpTip.types";

export interface SliderProps {
id: string;
label?: string;
noLabelMinWidth?: boolean;
error?: string;
tooltip?: string;
sx?: CSSObject;
helpTip?: React.ReactNode;
helpTipPlacement?: CommonHelpTipPlacement;
displayValue?: boolean;
displayValueFunction?: (value:any) => React.ReactNode
}

export interface SliderContainerProps {
children?: React.ReactNode;
sx?: CSSObject;
error?: boolean;
className?: string;
}
8 changes: 8 additions & 0 deletions src/global/global.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ export interface WizardColorProps {
modal: WizardStepColorProps;
}

export interface SliderProps {
railBG: string;
bulletBG: string;
disabledRail: string;
disabledBullet: string;
}

export interface ThemeDefinitionProps {
bgColor: string;
fontColor: string;
Expand Down Expand Up @@ -369,6 +376,7 @@ export interface ThemeDefinitionProps {
informativeMessage?: InformativeMessageProps;
badge?: BadgeStyleProps;
wizard?: WizardColorProps;
slider?: SliderProps;
}

export interface SelectorType {
Expand Down
Loading

0 comments on commit 94b2533

Please sign in to comment.