Skip to content

Commit

Permalink
Merge pull request #55 from kleros/feat/number-field-custom-counter-a…
Browse files Browse the repository at this point in the history
…rrows

feat: custom-counter-arrows-in-number-field
  • Loading branch information
alcercu authored Oct 4, 2024
2 parents 2fb36bb + 8e9612b commit c900809
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 26 deletions.
25 changes: 25 additions & 0 deletions src/assets/svgs/arrows/field-arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions src/assets/svgs/arrows/field-arrow-up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/examples/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Searchbar from "../lib/form/searchbar";
import Textarea from "../lib/form/textarea";
import Slider from "../lib/form/slider";
import Datepicker from "../lib/form/datepicker";
import Telegram from "../assets/svgs/telegram.svg";

const Form = () => {
const [value, setValue] = useState(1);
Expand All @@ -26,6 +27,8 @@ const Form = () => {
variant="success"
message="success msg"
/>
<Field placeholder={"Number"} type="number" Icon={Telegram} />
<Field placeholder={"Number"} type="number" />
<Searchbar />
<Textarea
placeholder={"eg. longer text"}
Expand Down
134 changes: 108 additions & 26 deletions src/lib/form/field.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React, { InputHTMLAttributes } from "react";
import React, { InputHTMLAttributes, useRef } from "react";
import styled, { css } from "styled-components";
import SuccessIcon from "../../assets/svgs/status-icons/success.svg";
import WarningIcon from "../../assets/svgs/status-icons/warning.svg";
import ErrorIcon from "../../assets/svgs/status-icons/error.svg";
import InfoIcon from "../../assets/svgs/status-icons/info.svg";
import UpArrowIcon from "../../assets/svgs/arrows/field-arrow-up.svg";
import DownArrowIcon from "../../assets/svgs/arrows/field-arrow-down.svg";

import { borderBox, small, svg } from "../../styles/common-style";
import { useHover } from "usehooks-ts";

export type VariantProp = {
variant?: "success" | "warning" | "error" | string;
Expand Down Expand Up @@ -80,14 +84,70 @@ const StyledInput = styled.input<{
padding-top: 14px;
padding-bottom: 14px;
padding-left: 16px;
padding-right: ${({ Icon, variant }) => {
if (Icon) return "56px";
if (variant) return "44px";
return "16px";
padding-right: ${({ Icon, variant, type }) => {
if (Icon) return type === "number" ? "64px" : "56px";
if (variant) return type === "number" ? "52px" : "44px";
return type === "number" ? "30px" : "16px";
}};
/* Chrome, Safari, Edge, Opera */
::-webkit-outer-spin-button,
::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
-moz-appearance: textfield;
appearance: textfield;
${baseInputStyle}
`;

const ArrowsContainer = styled.div<{
variant?: string;
Icon?: React.FC<React.SVGAttributes<SVGElement>>;
}>`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
height: 100%;
width: 14px;
gap: 4px;
top: 0;
right: ${({ Icon, variant }) => {
if (Icon) return "48px";
if (variant) return "36px";
return "12px";
}};
`;

const ArrowButton = styled.button`
height: 14px;
width: 14px;
display: flex;
justify-content: center;
align-items: center;
background: transparent;
border: none;
border-radius: 3px;
padding: 0;
cursor: pointer;
:hover {
background: ${(props) => props.theme.klerosUIComponentsStroke};
}
`;

const StyledArrowIcon = styled.svg`
width: 8px;
height: 8px;
path {
fill: ${(props) => props.theme.klerosUIComponentsSecondaryText};
}
`;

const StyledSVG = styled.svg``;

export const StyledMessage = styled.small<VariantProp>`
Expand Down Expand Up @@ -141,27 +201,49 @@ const Field: React.FC<FieldProps> = ({
Icon,
className,
...props
}) => (
<Wrapper {...{ className }}>
<StyledInput {...{ variant, Icon, ...props }} />
{variant === "success" && <StyledSuccessIcon className="field-svg" />}
{variant === "warning" && <StyledWarningIcon className="field-svg" />}
{variant === "error" && <StyledErrorIcon className="field-svg" />}
{Icon && (
<IconContainer>
<StyledIconSVG as={Icon} />
</IconContainer>
)}
{message && (
<StyledMessage {...{ variant }}>
{variant === "info" && (
<InfoIcon className={StyledSVG.styledComponentId} />
)}
<StyledSmall {...{ variant }}>{message}</StyledSmall>
</StyledMessage>
)}
</Wrapper>
);
}) => {
const wrapperRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const hovering = useHover(wrapperRef);

return (
<Wrapper ref={wrapperRef} {...{ className }}>
<StyledInput ref={inputRef} {...{ variant, Icon, ...props }} />
{props.type === "number" && hovering && (
<ArrowsContainer className="field-arrows" {...{ variant, Icon }}>
<ArrowButton
aria-label="increment"
onClick={() => inputRef?.current?.stepUp()}
>
<StyledArrowIcon as={UpArrowIcon} />
</ArrowButton>
<ArrowButton
aria-label="decrement"
onClick={() => inputRef?.current?.stepDown()}
>
<StyledArrowIcon as={DownArrowIcon} />
</ArrowButton>
</ArrowsContainer>
)}
{variant === "success" && <StyledSuccessIcon className="field-svg" />}
{variant === "warning" && <StyledWarningIcon className="field-svg" />}
{variant === "error" && <StyledErrorIcon className="field-svg" />}
{Icon && (
<IconContainer>
<StyledIconSVG as={Icon} />
</IconContainer>
)}
{message && (
<StyledMessage {...{ variant }}>
{variant === "info" && (
<InfoIcon className={StyledSVG.styledComponentId} />
)}
<StyledSmall {...{ variant }}>{message}</StyledSmall>
</StyledMessage>
)}
</Wrapper>
);
};

Field.displayName = "Field";

Expand Down

0 comments on commit c900809

Please sign in to comment.