diff --git a/.Jules/palette.md b/.Jules/palette.md index 5a5b459..7d3d798 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -5,3 +5,7 @@ ## 2024-05-24 - Accessible Loading Buttons **Learning:** Replacing button text with a spinner destroys the accessible name. **Action:** Use `aria-busy="true"`, keep children in DOM (visually hidden via opacity/class), and overlay spinner absolutely. Ensure wrapper element replicates flex layout (gap/alignment) to prevent layout shifts. + +## 2024-05-24 - Enhancing Inputs Safely +**Learning:** Adding features like character counters to generic input components must handle both controlled and uncontrolled states. Assuming a component is controlled (using `props.value`) can break uncontrolled usage by showing stale data (e.g., sticking at 0/100). +**Action:** When enhancing generic components, detect uncontrolled state (e.g., `props.value === undefined`) and either implement internal state tracking or gracefully degrade (hide the feature) to avoid misleading UX. diff --git a/src/components/ui/Input.module.css b/src/components/ui/Input.module.css index 3acc481..75f9d0a 100644 --- a/src/components/ui/Input.module.css +++ b/src/components/ui/Input.module.css @@ -61,3 +61,10 @@ font-size: 0.8125rem; color: var(--md-sys-color-error); } + +.charCount { + font-size: 0.75rem; + color: var(--md-sys-color-outline); + text-align: right; + font-variant-numeric: tabular-nums; +} diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx index 185bfbe..185889e 100644 --- a/src/components/ui/Input.tsx +++ b/src/components/ui/Input.tsx @@ -30,6 +30,11 @@ export const Input = forwardRef( {...props} /> {error && {error}} + {props.maxLength !== undefined && props.value !== undefined && ( + + )} ); } @@ -66,6 +71,11 @@ export const Textarea = forwardRef( {...props} /> {error && {error}} + {props.maxLength !== undefined && props.value !== undefined && ( + + )} ); }