From b9a37b795cd68c3ee08c8ad40a9f646ee396c4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Mon, 6 Jan 2025 06:48:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=B8=AA=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=8B=A3=E9=80=89=E6=95=B0=E5=80=BC=E7=9A=84=E6=BB=91?= =?UTF-8?q?=E6=9D=86=E7=BB=84=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LabeledPicker.module.css | 23 ++++++++++ src/components/LabeledPicker.tsx | 58 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/components/LabeledPicker.module.css create mode 100644 src/components/LabeledPicker.tsx diff --git a/src/components/LabeledPicker.module.css b/src/components/LabeledPicker.module.css new file mode 100644 index 0000000..88ac788 --- /dev/null +++ b/src/components/LabeledPicker.module.css @@ -0,0 +1,23 @@ +@layer components { + .labeled_picker { + width: 100%; + display: flex; + flex-direction: column; + align-items: stretch; + gap: var(--spacing-xs); + .title_row { + width: 100%; + display: flex; + flex-direction: row; + align-items: baseline; + label { + flex: 1; + font-size: var(--font-size-xs); + } + & > span { + text-align: right; + font-size: var(--font-size-xs); + } + } + } +} diff --git a/src/components/LabeledPicker.tsx b/src/components/LabeledPicker.tsx new file mode 100644 index 0000000..1c77e85 --- /dev/null +++ b/src/components/LabeledPicker.tsx @@ -0,0 +1,58 @@ +import cx from 'clsx'; +import { isEqual, isNil } from 'lodash-es'; +import { useEffect, useState } from 'react'; +import styles from './LabeledPicker.module.css'; + +type LabeledPickerProps = { + title?: string; + value?: number; + unit?: string; + onChange: (value: number) => void; + min?: number; + max?: number; + step?: number; +}; + +export function LabeledPicker({ + title, + value, + unit, + onChange, + min = 0, + max = 100, + step = 1, +}: LabeledPickerProps) { + const [pickerValue, setPickerValue] = useState(value ?? min); + const handlePickerChange = (event: React.ChangeEvent) => { + const value = event.target.value as number; + setPickerValue(value); + onChange?.(value); + }; + + useEffect(() => { + if (!isEqual(value, pickerValue)) { + setPickerValue(value); + } + }, [value]); + + return ( +
+
+ {!isNil(title) && } +
+ + {pickerValue} {unit} + +
+ +
+ ); +}