diff --git a/src/components/CustomBottomSheet/DatePickerBottomSheet.tsx b/src/components/CustomBottomSheet/DatePickerBottomSheet.tsx index c478c1a..c0a350d 100644 --- a/src/components/CustomBottomSheet/DatePickerBottomSheet.tsx +++ b/src/components/CustomBottomSheet/DatePickerBottomSheet.tsx @@ -47,13 +47,17 @@ export default function DatePickerBottomSheet({ label: (i + 1).toString(), })); - const years = Array.from({ length: 21 }, (_, i) => { - const year = new Date().getFullYear() - 10 + i; - return { - value: year.toString(), - label: year.toString(), - }; - }); + const currentYear = new Date().getFullYear(); + const years = Array.from( + { length: currentYear - 10 - 1900 + 1 }, + (_, i) => { + const year = 1900 + i; + return { + value: year.toString(), + label: year.toString(), + }; + }, + ); return { month: months, @@ -145,10 +149,12 @@ export default function DatePickerBottomSheet({ style={{ position: "relative", display: "flex", - backgroundColor: "#ffffff", + backgroundColor: "var(--secondary-background)", overflow: "hidden", width: "100%", height: 250, + border: "1px solid var(--border)", + borderRadius: "8px", }} aria-selected={false} > @@ -156,8 +162,8 @@ export default function DatePickerBottomSheet({ name="month" style={{ flex: 1, - borderRight: "1px solid #e5e7eb", - backgroundColor: "#ffffff", + borderRight: "1px solid var(--border)", + backgroundColor: "var(--secondary-background)", }} > {pickerOptions.month.map((option) => ( @@ -166,16 +172,22 @@ export default function DatePickerBottomSheet({
{option.label} @@ -188,8 +200,8 @@ export default function DatePickerBottomSheet({ name="day" style={{ flex: 1, - borderRight: "1px solid #e5e7eb", - backgroundColor: "#ffffff", + borderRight: "1px solid var(--border)", + backgroundColor: "var(--secondary-background)", }} > {pickerOptions.day.map((option) => ( @@ -198,16 +210,22 @@ export default function DatePickerBottomSheet({
{option.label} @@ -220,7 +238,7 @@ export default function DatePickerBottomSheet({ name="year" style={{ flex: 1, - backgroundColor: "#ffffff", + backgroundColor: "var(--secondary-background)", }} > {pickerOptions.year.map((option) => ( @@ -229,16 +247,22 @@ export default function DatePickerBottomSheet({
{option.label} diff --git a/src/components/WheelPicker/Picker.module.css b/src/components/WheelPicker/Picker.module.css new file mode 100644 index 0000000..9082195 --- /dev/null +++ b/src/components/WheelPicker/Picker.module.css @@ -0,0 +1,224 @@ +/* + * Picker Component Theme-Aware Styling + * + * This CSS module provides enhanced dark theme support for the Picker component. + * Features include: + * - Automatic theme detection using CSS variables + * - Enhanced visual feedback for selected items + * - Smooth animations and transitions + * - Accessibility improvements (focus states, high contrast) + * - Responsive design for mobile devices + * - Reduced motion support for accessibility + * + * The styling automatically adapts to both light and dark themes using CSS variables + * defined in the application's theme system. + */ + +.pickerContainer { + position: relative; + display: flex; + justify-content: center; + overflow: hidden; + background-color: var(--secondary-background); + border: 1px solid var(--border); + border-radius: 8px; + transition: all 0.2s ease; +} + +.pickerContainer:hover { + border-color: var(--primary); + box-shadow: 0 0 0 1px var(--primary); +} + +.pickerColumn { + flex: 1; + border-right: 1px solid var(--border); + background-color: var(--secondary-background); + transition: all 0.2s ease; +} + +.pickerColumn:last-child { + border-right: none; +} + +.pickerItem { + height: 36px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: all 0.2s ease; + border-radius: 4px; + margin: 2px 4px; +} + +.pickerItem:hover { + background-color: var(--background); + transform: scale(1.02); +} + +.pickerItem.selected { + font-weight: 600; + color: var(--foreground); + opacity: 1; + background-color: var(--background); + border-radius: 4px; + margin: 2px 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.pickerItem.unselected { + font-weight: 400; + color: var(--text-color-gray); + opacity: 0.7; + background-color: transparent; + border-radius: 0; + margin: 0; +} + +.pickerItemText { + font-size: 16px; + padding: 9px 0; + text-align: center; + line-height: 1.2; + width: 100%; + transition: all 0.2s ease; +} + +/* Dark theme specific enhancements */ +[data-theme="dark"] .pickerContainer { + background-color: var(--secondary-background); + border-color: var(--border); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); +} + +[data-theme="dark"] .pickerContainer:hover { + border-color: var(--primary); + box-shadow: 0 0 0 1px var(--primary), 0 4px 12px rgba(0, 0, 0, 0.4); +} + +[data-theme="dark"] .pickerColumn { + background-color: var(--secondary-background); + border-color: var(--border); +} + +[data-theme="dark"] .pickerItem.selected { + background-color: var(--background); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + color: var(--foreground); +} + +[data-theme="dark"] .pickerItem:hover { + background-color: var(--background); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); +} + +[data-theme="dark"] .pickerItem.unselected { + color: var(--text-color-gray); +} + +/* Light theme specific enhancements */ +[data-theme="light"] .pickerContainer { + background-color: var(--secondary-background); + border-color: var(--border); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +[data-theme="light"] .pickerContainer:hover { + border-color: var(--primary); + box-shadow: 0 0 0 1px var(--primary), 0 4px 8px rgba(0, 0, 0, 0.15); +} + +[data-theme="light"] .pickerItem.selected { + background-color: var(--background); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + color: var(--foreground); +} + +[data-theme="light"] .pickerItem:hover { + background-color: var(--background); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); +} + +[data-theme="light"] .pickerItem.unselected { + color: var(--text-color-gray); +} + +/* Accessibility enhancements */ +.pickerItem:focus-visible { + outline: 2px solid var(--primary); + outline-offset: 2px; +} + +.pickerItem:focus-visible.selected { + outline-color: var(--primary); +} + +/* Animation for smooth transitions */ +@keyframes pickerItemSelect { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } + 100% { + transform: scale(1); + } +} + +.pickerItem.selected { + animation: pickerItemSelect 0.2s ease-out; +} + +/* Responsive design */ +@media (max-width: 480px) { + .pickerItemText { + font-size: 14px; + padding: 8px 0; + } + + .pickerItem { + height: 32px; + margin: 1px 2px; + } + + .pickerItem.selected { + margin: 1px 2px; + } +} + +/* High contrast mode support */ +@media (prefers-contrast: high) { + .pickerContainer { + border-width: 2px; + } + + .pickerItem.selected { + border: 2px solid var(--primary); + background-color: var(--primary); + color: var(--secondary-background); + } + + .pickerItem.unselected { + color: var(--foreground); + opacity: 0.8; + } +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + .pickerItem, + .pickerContainer, + .pickerItemText { + transition: none; + } + + .pickerItem.selected { + animation: none; + } + + .pickerItem:hover { + transform: none; + } +} diff --git a/src/components/WheelPicker/components/Picker.tsx b/src/components/WheelPicker/components/Picker.tsx index ca74757..e3c01f2 100644 --- a/src/components/WheelPicker/components/Picker.tsx +++ b/src/components/WheelPicker/components/Picker.tsx @@ -1,13 +1,14 @@ import { - CSSProperties, - HTMLProps, - MutableRefObject, - createContext, - useCallback, - useContext, - useMemo, - useReducer, + CSSProperties, + HTMLProps, + MutableRefObject, + createContext, + useCallback, + useContext, + useMemo, + useReducer, } from "react"; +import styles from "../Picker.module.css"; const DEFAULT_HEIGHT = 216; const DEFAULT_ITEM_HEIGHT = 36; @@ -160,9 +161,9 @@ function PickerRoot(props: PickerRootProps) { justifyContent: "center", overflow: "hidden", maskImage: - "linear-gradient(to top, transparent, transparent 5%, white 20%, white 80%, transparent 95%, transparent)", + "linear-gradient(to top, transparent, transparent 5%, var(--foreground) 20%, var(--foreground) 80%, transparent 95%, transparent)", WebkitMaskImage: - "linear-gradient(to top, transparent, transparent 5%, white 20%, white 80%, transparent 95%, transparent)", + "linear-gradient(to top, transparent, transparent 5%, var(--foreground) 20%, var(--foreground) 80%, transparent 95%, transparent)", }), [height] ); @@ -194,6 +195,7 @@ function PickerRoot(props: PickerRootProps) { return (
{ @@ -255,6 +256,7 @@ function PickerColumn({ return (
{ + return `${styles.pickerItem} ${selected ? styles.selected : styles.unselected}`; + }, []); + const handleClick = useCallback(() => { pickerActions.change(key, value); }, [pickerActions, key, value]); + const isSelected = pickerValue[key] === value; + return (
{isFunction(children) - ? children({ selected: pickerValue[key] === value }) - : children} + ? children({ selected: isSelected }) + : ( +
+ {children} +
+ )}
); }