diff --git a/app/components/NumberInput.tsx b/app/components/NumberInput.tsx
index 0dfb0fd..e0c34de 100644
--- a/app/components/NumberInput.tsx
+++ b/app/components/NumberInput.tsx
@@ -1,16 +1,232 @@
"use client";
+import { ChangeEvent, KeyboardEvent, useState } from "react";
import styled from "styled-components";
-// TODO: Add props for NumberInput
type NumberInputProps = {
- propName: string; // replace string with actual prop type
+ defaultValue?: number;
+ disabled?: boolean;
+ label?: string;
};
-// TODO: implement NumberInput component
-export default function NumberInput({}: NumberInputProps) {
- return ;
+export default function NumberInput({
+ defaultValue = 0,
+ disabled = false,
+ label,
+}: NumberInputProps) {
+ const [val, setVal] = useState(defaultValue);
+
+ // can change these for future purposes
+ const step = 1;
+ const min = 0;
+ const max = 9;
+
+ const handleIncrement = () => {
+ setVal(Math.min(max, val + step));
+ };
+
+ const handleDecrement = () => {
+ setVal(Math.max(min, val - step));
+ };
+
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === "Enter") {
+ event.currentTarget.blur();
+ return;
+ }
+ };
+
+ const handleChange = (event: ChangeEvent) => {
+ const input = event.target as HTMLInputElement;
+ // if the field is empty
+ if (Number.isNaN(input.valueAsNumber)) {
+ setVal(min);
+ return;
+ }
+ const update = Math.max(min, Math.min(max, input.valueAsNumber));
+ setVal(update);
+ input.value = String(update);
+ };
+
+ return (
+
+
+
+
+
+
+ arrow_drop_up
+
+
+ arrow_drop_down
+
+
+
+
+ );
}
+const NumberInputWrapper = styled.div`
+ --s: 1;
+
+ @media (max-width: 768px) {
+ --s: 0.75;
+ }
+
+ @media (max-width: 600px) {
+ --s: 0.5;
+ }
+
+ @media (max-width: 360px) {
+ --s: 0.3;
+ }
+
+ display: inline-block;
+ transform: scale(var(--s));
+ transform-origin: top left;
+
+ width: calc(52px / var(--s));
+ height: calc(36px / var(--s));
+`;
+
const StyledNumberInput = styled.div`
- /* TODO: Add styles for NumberInput */
+ --border: #525252;
+ --bg: #ffffff;
+ --bg-hover: #f2f2f2;
+ --bg-focus: #e9e9e9;
+ --chevron: #525252;
+
+ position: relative;
+ width: 52px;
+ height: 36px;
+
+ display: grid;
+ grid-template-columns: 1fr 20px;
+ column-gap: 8px;
+
+ border: 2px solid var(--border);
+ border-radius: 4px;
+ background: var(--bg);
+ box-sizing: border-box;
+
+ padding-left: 8px;
+ padding-right: 2px;
+ overflow: hidden;
+ transition:
+ background 120ms ease,
+ border-color 120ms ease;
+
+ &:focus-within {
+ background: var(--bg-focus);
+ }
+
+ &[data-disabled="true"] {
+ --border: #cfcfcf;
+ --bg: #efefef;
+ --chevron: #cfcfcf;
+ }
+`;
+
+const StyledInput = styled.input`
+ grid-column: 1 / 2;
+ grid-row: 1 / 2;
+
+ width: 100%;
+ border: none;
+ outline: none;
+ background: transparent;
+ text-align: left;
+
+ font-family: "Inter", sans-serif;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 20px;
+ color: var(--Black, #000);
+
+ &::-webkit-outer-spin-button,
+ &::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+ }
+ -moz-appearance: textfield;
+
+ &:disabled {
+ color: #9e9e9e;
+ }
+`;
+
+const MaterialIcon = styled.span`
+ font-family: "Material Symbols Rounded";
+ font-weight: normal;
+ font-style: normal;
+ font-size: 16px;
+ line-height: 1;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--chevron);
+ user-select: none;
+`;
+
+const StyledNumberArrows = styled.div`
+ grid-column: 2 / 3;
+ grid-row: 1 / 2;
+ width: 20px;
+ height: 20px;
+ align-self: center;
+ position: relative;
+`;
+
+const ArrowButton = styled.button<{ $dir: "up" | "down" }>`
+ position: absolute;
+ left: 0;
+ width: 100%;
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ padding: 0;
+ transition: opacity 100ms ease;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ ${({ $dir }) =>
+ $dir === "up"
+ ? `
+ top: 0;
+ height: calc(50% - 2px);
+ `
+ : `
+ bottom: 0;
+ height: calc(50% - 2px);
+ `}
+
+ &:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
`;