feat(dashboard-v2): implement TextInputIcon component

This commit is contained in:
Michał Leszczyk 2022-03-07 10:55:43 +01:00
parent a93e4e93f8
commit aa6db3d115
No known key found for this signature in database
GPG Key ID: FA123CA8BAA2FBF4
6 changed files with 64 additions and 24 deletions

View File

@ -0,0 +1,10 @@
import { withIconProps } from "../withIconProps";
export const SearchIcon = withIconProps(({ size, ...props }) => (
<svg width={size} height={size} viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
fill="currentColor"
d="M9,0a9,9,0,0,1,7,14.62l3.68,3.67a1,1,0,0,1-1.32,1.5l-.1-.08L14.62,16A9,9,0,1,1,9,0ZM9,2a7,7,0,1,0,4.87,12l.07-.09.09-.07A7,7,0,0,0,9,2Z"
/>
</svg>
));

View File

@ -9,3 +9,4 @@ export * from "./icons/CircledErrorIcon";
export * from "./icons/CircledProgressIcon"; export * from "./icons/CircledProgressIcon";
export * from "./icons/CircledArrowUpIcon"; export * from "./icons/CircledArrowUpIcon";
export * from "./icons/PlusIcon"; export * from "./icons/PlusIcon";
export * from "./icons/SearchIcon";

View File

@ -4,7 +4,7 @@ const propTypes = {
/** /**
* Size of the icon's bounding box. * Size of the icon's bounding box.
*/ */
size: PropTypes.number, size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
}; };
const defaultProps = { const defaultProps = {

View File

@ -1,20 +1,45 @@
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import cn from "classnames";
import { useEffect, useRef, useState } from "react";
import { PlusIcon } from "../Icons";
export const TextInputIcon = ({ className, icon, placeholder, onChange }) => {
const inputRef = useRef();
const [focused, setFocused] = useState(false);
const [value, setValue] = useState("");
useEffect(() => {
onChange(value);
}, [value, onChange]);
/**
* Primary UI component for user interaction
*/
export const TextInputIcon = ({ icon, position, placeholder }) => {
return ( return (
<div className={"flex flex-row items-center px-textInputIcon h-textInput rounded-full bg-palette-100"}> <div
{position === "left" ? <div className={"w-buttonIconLg h-buttonIconLg"}>{icon}</div> : null} className={cn(
<input "grid-flow-col inline-grid grid-cols-[2rem_1fr_1.5rem] items-center rounded-full bg-palette-100 px-4 py-2",
placeholder={placeholder} className,
className={ {
"w-full focus:outline-none mx-textInputHorizontal rounded-full bg-transparent " + "outline outline-1 outline-primary": focused,
"placeholder-palette-400 text-content tracking-inputPlaceholder text-textInput"
} }
)}
>
<div>{icon}</div>
<input
ref={inputRef}
value={value}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
onChange={(event) => setValue(event.target.value)}
placeholder={placeholder}
className="focus:outline-none bg-transparent placeholder:text-palette-400"
/> />
{position === "right" ? <div className={"w-buttonIconLg h-buttonIconLg"}>{icon}</div> : null} {value && (
<PlusIcon
size={14}
role="button"
className="justify-self-end text-palette-400 rotate-45"
onClick={() => setValue("")}
/>
)}
</div> </div>
); );
}; };
@ -23,13 +48,13 @@ TextInputIcon.propTypes = {
/** /**
* Icon to place in text input * Icon to place in text input
*/ */
icon: PropTypes.element, icon: PropTypes.element.isRequired,
/**
* Side to place icon
*/
position: PropTypes.oneOf(["left", "right"]),
/** /**
* Input placeholder * Input placeholder
*/ */
placeholder: PropTypes.string, placeholder: PropTypes.string,
/**
* Function to be called whenever value changes
*/
onChange: PropTypes.func.isRequired,
}; };

View File

@ -1,5 +1,6 @@
import { TextInputIcon } from "./TextInputIcon"; import { TextInputIcon } from "./TextInputIcon";
import { CogIcon } from "../Icons"; import { SearchIcon } from "../Icons";
import { Panel } from "../Panel";
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default { export default {
@ -9,19 +10,21 @@ export default {
}; };
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <TextInputIcon {...args} />; const Template = (args) => (
<Panel>
<TextInputIcon {...args} />
</Panel>
);
export const IconLeft = Template.bind({}); export const IconLeft = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args // More on args: https://storybook.js.org/docs/react/writing-stories/args
IconLeft.args = { IconLeft.args = {
icon: <CogIcon />, icon: <SearchIcon size={20} />,
position: "left",
placeholder: "Search", placeholder: "Search",
}; };
export const IconRight = Template.bind({}); export const IconRight = Template.bind({});
IconRight.args = { IconRight.args = {
icon: <CogIcon />, icon: <SearchIcon size={20} />,
position: "right",
placeholder: "Search", placeholder: "Search",
}; };

View File

@ -28,6 +28,7 @@ module.exports = {
borderColor: (theme) => ({ ...theme("colors"), ...colors }), borderColor: (theme) => ({ ...theme("colors"), ...colors }),
textColor: (theme) => ({ ...theme("colors"), ...colors }), textColor: (theme) => ({ ...theme("colors"), ...colors }),
placeholderColor: (theme) => ({ ...theme("colors"), ...colors }), placeholderColor: (theme) => ({ ...theme("colors"), ...colors }),
outlineColor: (theme) => ({ ...theme("colors"), ...colors }),
extend: { extend: {
fontFamily: { fontFamily: {
sans: ["Sora", ...defaultTheme.fontFamily.sans], sans: ["Sora", ...defaultTheme.fontFamily.sans],