Enhance alignment and styling for RJSF components

- Updated LayoutObjectFieldTemplate to ensure consistent alignment of grid items with a minimum height and flex properties.
- Improved TooltipFieldTemplate to center-align switch and checkbox widgets, enhancing overall layout consistency.
- Refined CheckboxWidget and SwitchWidget styles for better alignment and text handling, ensuring labels do not overflow and maintain a single line.
This commit is contained in:
Miguel 2025-08-27 14:45:50 +02:00
parent 76c6743537
commit 42cd1743e8
4 changed files with 13990 additions and 9 deletions

File diff suppressed because it is too large Load Diff

View File

@ -60,13 +60,21 @@ export default function LayoutObjectFieldTemplate(props) {
)
)}
{layout.map((row, rowIdx) => (
<SimpleGrid key={rowIdx} columns={12} spacing={3}>
<SimpleGrid key={rowIdx} columns={12} spacing={3} alignItems="flex-end">
{row.map((cell, cellIdx) => {
const prop = propMap.get(cell.name)
if (!prop) return null
const col = Math.min(Math.max(cell.width || 12, 1), 12)
return (
<Box key={`${rowIdx}-${cellIdx}`} gridColumn={`span ${col}`}>{prop.content}</Box>
<Box
key={`${rowIdx}-${cellIdx}`}
gridColumn={`span ${col}`}
minH="40px" // Minimum height for consistent alignment
display="flex"
alignItems="flex-end"
>
{prop.content}
</Box>
)
})}
</SimpleGrid>

View File

@ -1,10 +1,11 @@
import React from 'react'
import { Box, FormControl, FormErrorMessage, Tooltip as ChakraTooltip, useColorModeValue } from '@chakra-ui/react'
import { Box, FormControl, FormErrorMessage, Tooltip as ChakraTooltip, useColorModeValue, Flex } from '@chakra-ui/react'
/**
* Custom RJSF Field Template with integrated tooltips
* Shows ui:description as tooltip on hover over the field
* Removes the description text that normally appears below the field
* Improves alignment for switches, checkboxes and handles long labels
*/
export default function TooltipFieldTemplate(props) {
const {
@ -36,6 +37,15 @@ export default function TooltipFieldTemplate(props) {
// Only show tooltip if there's actual content (not empty string or whitespace)
const hasTooltipContent = tooltipContent && typeof tooltipContent === 'string' && tooltipContent.trim().length > 0
// Detect if this is a switch or checkbox widget based on the schema type and widget
const widgetType = uiSchema?.['ui:widget']
const isBoolean = schema?.type === 'boolean'
const isSwitchOrCheckbox = isBoolean && (widgetType === 'switch' || widgetType === 'checkbox' || widgetType === 'SwitchWidget' || widgetType === 'CheckboxWidget')
// For switch/checkbox widgets, we need special handling to center-align them with other fields
// These widgets already include their label, so we don't need additional label handling
const shouldCenterAlign = isSwitchOrCheckbox
// If there's tooltip content, wrap just the children (input/widget) in tooltip
const wrappedChildren = hasTooltipContent ? (
<ChakraTooltip
@ -59,9 +69,22 @@ export default function TooltipFieldTemplate(props) {
</ChakraTooltip>
) : children
// Enhanced container for better alignment
const containerProps = shouldCenterAlign ? {
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'flex-start',
minH: '40px', // Standard input height for alignment
w: 'full'
} : {
w: 'full'
}
return (
<FormControl isInvalid={!!errors} isRequired={required}>
{wrappedChildren}
<Box {...containerProps}>
{wrappedChildren}
</Box>
{errors && (
<FormErrorMessage>
{errors}

View File

@ -138,6 +138,23 @@ export const CheckboxWidget = ({ id, label, value, required, disabled, readonly,
isChecked={!!value}
onChange={(e) => onChange(e.target.checked)}
colorScheme="blue"
alignItems="center"
sx={{
'& .chakra-checkbox__control': {
alignSelf: 'flex-start',
mt: '2px' // Small offset to align with text baseline
},
'& .chakra-checkbox__label': {
fontSize: 'sm',
lineHeight: '1.3',
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box',
WebkitLineClamp: 1, // Force single line
WebkitBoxOrient: 'vertical',
wordBreak: 'break-word'
}
}}
>
{label}
</Checkbox>
@ -148,8 +165,30 @@ export const CheckboxWidget = ({ id, label, value, required, disabled, readonly,
)
export const SwitchWidget = ({ id, label, value, required, disabled, readonly, onChange, rawErrors = [] }) => (
<FormControl display="flex" alignItems="center" isRequired={required} isDisabled={disabled} isReadOnly={readonly} isInvalid={rawErrors.length > 0}>
<FormLabel htmlFor={id} mb="0" mr={3}>
<FormControl
display="flex"
alignItems="center"
isRequired={required}
isDisabled={disabled}
isReadOnly={readonly}
isInvalid={rawErrors.length > 0}
minH="40px" // Standard height to match other inputs
position="relative"
>
<FormLabel
htmlFor={id}
mb="0"
mr={3}
fontSize="sm"
lineHeight="1.3"
overflow="hidden"
textOverflow="ellipsis"
whiteSpace="nowrap" // Force single line
wordBreak="break-word"
display="flex"
alignItems="center"
maxW="calc(100% - 60px)" // Reserve space for switch (approx 50px + margin)
>
{label}
</FormLabel>
<Switch
@ -157,9 +196,12 @@ export const SwitchWidget = ({ id, label, value, required, disabled, readonly, o
isChecked={!!value}
onChange={(e) => onChange(e.target.checked)}
colorScheme="blue"
flexShrink={0} // Prevent switch from shrinking
/>
{rawErrors.length > 0 && (
<FormHelperText color="red.500">{rawErrors[0]}</FormHelperText>
<FormHelperText color="red.500" position="absolute" top="100%" left={0} mt={1}>
{rawErrors[0]}
</FormHelperText>
)}
</FormControl>
)