Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions packages/react/src/components/form/form-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@ export interface FormItemProps extends React.HTMLAttributes<HTMLDivElement> {
* />
* ```
*
* @example With custom styling
* ```tsx
* <FormItem className="space-y-2">
* <FormLabel>Password</FormLabel>
* <FormControl>
* <TextInputField type="password" {...field} label="Password" />
* </FormControl>
* <FormMessage />
* </FormItem>
* ```
*/
export const FormItem = React.forwardRef<HTMLDivElement, FormItemProps>(
({ id, className, ...props }, ref) => {
Expand Down
11 changes: 0 additions & 11 deletions packages/react/src/components/form/form-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,6 @@ export interface FormLabelProps extends React.LabelHTMLAttributes<HTMLLabelEleme
* </FormItem>
* ```
*
* @example With custom styling on error
* ```tsx
* <FormItem>
* <FormLabel className={fieldState.error ? 'text-red-500' : ''}>
* Username
* </FormLabel>
* <FormControl>
* <TextInputField {...field} label="Username" />
* </FormControl>
* </FormItem>
* ```
*/
export const FormLabel = React.forwardRef<HTMLLabelElement, FormLabelProps>(
({ required, children, ...props }, ref) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/form/form-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface FormMessageProps extends React.HTMLAttributes<HTMLParagraphElem
* <TextInputField {...field} label="Email" />
* </FormControl>
* {fieldState.error && (
* <FormMessage className="text-red-600" />
* <FormMessage />
* )}
* </FormItem>
* ```
Expand Down
57 changes: 28 additions & 29 deletions packages/react/src/components/molecules/address-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ export interface AddressFieldProps {
* @default "Mailing address"
*/
legend?: string;
/**
* Additional CSS class names
*/
className?: string;
/**
* Street address field configuration
*/
Expand Down Expand Up @@ -278,6 +282,7 @@ export const AddressField = React.forwardRef<HTMLFieldSetElement, AddressFieldPr
(
{
legend = 'Mailing address',
className,
street,
street2,
city,
Expand Down Expand Up @@ -317,8 +322,8 @@ export const AddressField = React.forwardRef<HTMLFieldSetElement, AddressFieldPr
const countryOptions = country?.options ?? DEFAULT_COUNTRIES;

return (
<fieldset ref={ref} className="vads-u-margin-y--2" style={{ border: 'none', padding: 0 }}>
<legend className="vads-u-font-size--lg vads-u-font-weight--bold">{legend}</legend>
<fieldset ref={ref} className={className} data-slot="address-field">
<legend data-slot="address-field-legend">{legend}</legend>

{/* Street address */}
<TextInputField
Expand Down Expand Up @@ -354,34 +359,28 @@ export const AddressField = React.forwardRef<HTMLFieldSetElement, AddressFieldPr
onChange={handleFieldChange('city')}
/>

{/* State and ZIP code row */}
<div style={{ display: 'flex', gap: '1rem' }}>
<div style={{ flex: 1 }}>
<SelectField
label={stateLabel}
{...(state?.hint && { hint: state.hint })}
{...(state?.required && { required: state.required })}
{...(state?.error && { error: state.error })}
{...(values?.state && { value: values.state })}
options={stateOptions}
onChange={handleFieldChange('state')}
/>
</div>
{/* State and ZIP code */}
<SelectField
label={stateLabel}
{...(state?.hint && { hint: state.hint })}
{...(state?.required && { required: state.required })}
{...(state?.error && { error: state.error })}
{...(values?.state && { value: values.state })}
options={stateOptions}
onChange={handleFieldChange('state')}
/>

<div style={{ flex: 1 }}>
<TextInputField
label={zipCodeLabel}
{...(zipCode?.hint && { hint: zipCode.hint })}
{...(zipCode?.required && { required: zipCode.required })}
{...(zipCode?.error && { error: zipCode.error })}
{...(values?.zipCode && { value: values.zipCode })}
autocomplete="postal-code"
inputmode="numeric"
maxlength={10}
onChange={handleFieldChange('zipCode')}
/>
</div>
</div>
<TextInputField
label={zipCodeLabel}
{...(zipCode?.hint && { hint: zipCode.hint })}
{...(zipCode?.required && { required: zipCode.required })}
{...(zipCode?.error && { error: zipCode.error })}
{...(values?.zipCode && { value: values.zipCode })}
autocomplete="postal-code"
inputmode="numeric"
maxlength={10}
onChange={handleFieldChange('zipCode')}
/>

{/* Country (optional) */}
{showCountry && (
Expand Down
9 changes: 7 additions & 2 deletions packages/react/src/components/molecules/full-name-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export interface FullNameFieldProps {
* @default 'Name'
*/
legend?: string;
/**
* Additional CSS class names
*/
className?: string;
/**
* First name field configuration
*/
Expand Down Expand Up @@ -187,6 +191,7 @@ const DEFAULT_SUFFIX_OPTIONS: SelectOption[] = [
*/
export const FullNameField: React.FC<FullNameFieldProps> = ({
legend = 'Name',
className,
firstName,
middleName,
lastName,
Expand All @@ -208,8 +213,8 @@ export const FullNameField: React.FC<FullNameFieldProps> = ({
const showSuffix = suffix?.show === true;

return (
<fieldset className="vads-u-margin-y--2">
<legend className="vads-u-font-size--lg vads-u-font-weight--bold">{legend}</legend>
<fieldset className={className} data-slot="full-name-field">
<legend data-slot="full-name-field-legend">{legend}</legend>

<TextInputField
label={firstName.label || 'First name'}
Expand Down
45 changes: 6 additions & 39 deletions packages/react/src/components/review/review-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,20 @@ export interface ReviewItemProps {
* ```tsx
* <ReviewItem
* label="Status"
* value={<span style={{ color: 'green' }}>Active</span>}
* value={<span>Active</span>}
* />
* ```
*/
export const ReviewItem = React.forwardRef<HTMLDListElement, ReviewItemProps>(
({ label, value, valueList = false, className = '', ...props }, ref) => {
({ label, value, valueList = false, className, ...props }, ref) => {
// Handle null/undefined values
const displayValue = value ?? 'Not provided';

// Render value as list if valueList is true and value is an array
const renderValue = () => {
if (valueList && Array.isArray(value)) {
return (
<ul
style={{
margin: 0,
paddingLeft: '1.5rem',
listStyleType: 'disc',
}}
>
<ul>
{value.map((item, index) => (
<li key={index}>{item ?? 'Not provided'}</li>
))}
Expand All @@ -95,36 +89,9 @@ export const ReviewItem = React.forwardRef<HTMLDListElement, ReviewItemProps>(
};

return (
<dl
ref={ref}
className={`review-item ${className}`.trim()}
style={{
display: 'grid',
gridTemplateColumns: '1fr 2fr',
gap: '1rem',
padding: '0.75rem 0',
borderBottom: '1px solid #d6d7d9',
margin: 0,
}}
{...props}
>
<dt
style={{
fontWeight: 'bold',
color: '#1b1b1b',
margin: 0,
}}
>
{label}
</dt>
<dd
style={{
margin: 0,
color: '#1b1b1b',
}}
>
{renderValue()}
</dd>
<dl ref={ref} className={className} data-slot="review-item" {...props}>
<dt data-slot="review-item-label">{label}</dt>
<dd data-slot="review-item-value">{renderValue()}</dd>
</dl>
);
}
Expand Down
82 changes: 15 additions & 67 deletions packages/react/src/components/review/review-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,77 +73,25 @@ export interface ReviewListProps {
* <ReviewList items={items} listStyle="none" />
* ```
*/
export const ReviewList = React.forwardRef<HTMLDivElement, ReviewListProps>(
({ items, listStyle = 'bullet', className = '', ...props }, ref) => {
const getListStyleType = () => {
switch (listStyle) {
case 'numbered':
return 'decimal';
case 'none':
return 'none';
case 'bullet':
default:
return 'disc';
}
};

const ElementType = listStyle === 'numbered' ? 'ol' : 'ul';
export const ReviewList = React.forwardRef<HTMLElement, ReviewListProps>(
({ items, listStyle = 'bullet', className, ...props }, ref) => {
const ListElement = listStyle === 'numbered' ? 'ol' : 'ul';

return (
<div
ref={ref}
className={`review-list ${className}`.trim()}
style={{
backgroundColor: '#ffffff',
padding: '1rem',
borderRadius: '4px',
border: '1px solid #d6d7d9',
}}
<ListElement
ref={ref as React.Ref<HTMLOListElement>}
className={className}
data-list-style={listStyle}
data-slot="review-list"
{...props}
>
<ElementType
style={{
margin: 0,
paddingLeft: listStyle === 'none' ? 0 : '1.5rem',
listStyleType: getListStyleType(),
}}
>
{items.map((item, index) => (
<li
key={index}
style={{
marginBottom: index < items.length - 1 ? '0.75rem' : 0,
paddingBottom: index < items.length - 1 ? '0.75rem' : 0,
borderBottom: index < items.length - 1 ? '1px solid #e6e6e6' : 'none',
}}
>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.25rem',
}}
>
<strong
style={{
color: '#1b1b1b',
fontWeight: 'bold',
}}
>
{item.label}
</strong>
<span
style={{
color: '#1b1b1b',
}}
>
{item.value ?? 'Not provided'}
</span>
</div>
</li>
))}
</ElementType>
</div>
{items.map((item, index) => (
<li key={index} data-slot="review-list-item">
<strong data-slot="review-list-label">{item.label}</strong>
<span data-slot="review-list-value">{item.value ?? 'Not provided'}</span>
</li>
))}
</ListElement>
);
}
);
Expand Down
60 changes: 13 additions & 47 deletions packages/react/src/components/review/review-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export interface ReviewSectionProps {
* ```
*/
export const ReviewSection = React.forwardRef<HTMLElement, ReviewSectionProps>(
({ title, children, editHref, onEdit, editLabel = 'Edit', className = '', ...props }, ref) => {
({ title, children, editHref, onEdit, editLabel = 'Edit', className, ...props }, ref) => {
const handleEditClick = (e: React.MouseEvent) => {
if (onEdit) {
e.preventDefault();
Expand All @@ -78,53 +78,19 @@ export const ReviewSection = React.forwardRef<HTMLElement, ReviewSectionProps>(
};

return (
<section
ref={ref}
className={`review-section ${className}`.trim()}
style={{
backgroundColor: '#f0f0f0',
padding: '1.5rem',
marginBottom: '1.5rem',
borderRadius: '4px',
border: '1px solid #d6d7d9',
}}
{...props}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '1rem',
}}
>
<h3
style={{
margin: 0,
fontSize: '1.35rem',
fontWeight: 'bold',
color: '#1b1b1b',
}}
<section ref={ref} className={className} data-slot="review-section" {...props}>
<h3 data-slot="review-section-header">{title}</h3>
{(editHref || onEdit) && (
<a
aria-label={`${editLabel} ${title}`}
data-slot="review-section-edit"
href={editHref || '#'}
onClick={onEdit ? handleEditClick : undefined}
>
{title}
</h3>
{(editHref || onEdit) && (
<a
aria-label={`${editLabel} ${title}`}
href={editHref || '#'}
style={{
color: '#005ea2',
textDecoration: 'underline',
fontSize: '1rem',
fontWeight: 'normal',
}}
onClick={onEdit ? handleEditClick : undefined}
>
{editLabel}
</a>
)}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>{children}</div>
{editLabel}
</a>
)}
{children}
</section>
);
}
Expand Down
Loading