From b6367e84628660183f6485e5379f163a28e1d260 Mon Sep 17 00:00:00 2001 From: Lyutskan Lyutskanov Date: Tue, 14 Jul 2026 13:39:22 +0000 Subject: [PATCH 1/5] Implement governance form field styling (Fixes #2656, Fixes #2657, Fixes #2659) Align TextField, DateField, SelectField, and config inputs with Figma: grey (#363636) surfaces, uppercase section labels, and DateField picker pattern (KeyboardArrowDown, read-only display, YY-MM-DD HH:mm). - #2656: ProposalSummaryField / textarea styling - #2657: TextField single-line styling - #2659: ConfigField table entry styling Signed-off-by: Lyutskan Lyutskanov --- .../form-components/ConfigField.tsx | 11 +- .../components/form-components/DateField.tsx | 37 +- .../form-components/EffectiveDateField.tsx | 40 +-- .../form-components/ProposalSummaryField.tsx | 32 +- .../form-components/SelectField.tsx | 17 +- .../components/form-components/TextField.tsx | 20 +- ...UnallocatedUnclaimedActivityRecordForm.tsx | 2 +- .../forms/GrantRevokeFeaturedAppForm.tsx | 2 +- .../src/components/forms/OffboardSvForm.tsx | 2 +- .../forms/SetAmuletConfigRulesForm.tsx | 2 +- .../forms/SetDsoConfigRulesForm.tsx | 2 +- .../forms/UpdateSvRewardWeightForm.tsx | 2 +- apps/sv/frontend/src/themes/fieldStyles.ts | 319 ++++++++++++++++++ 13 files changed, 412 insertions(+), 76 deletions(-) create mode 100644 apps/sv/frontend/src/themes/fieldStyles.ts diff --git a/apps/sv/frontend/src/components/form-components/ConfigField.tsx b/apps/sv/frontend/src/components/form-components/ConfigField.tsx index 61a0216eaa..689d88c619 100644 --- a/apps/sv/frontend/src/components/form-components/ConfigField.tsx +++ b/apps/sv/frontend/src/components/form-components/ConfigField.tsx @@ -8,6 +8,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'; import { useFieldContext } from '../../hooks/formContext'; import type { ConfigChange, PendingConfigFieldInfo } from '../../utils/types'; import { nextScheduledSynchronizerUpgradeFormat } from '@canton-network/splice-common-frontend-utils'; +import { configFieldFieldSx, configFieldInputSx } from '../../themes/fieldStyles'; dayjs.extend(relativeTime); @@ -55,12 +56,16 @@ export const ConfigField: React.FC = props => { const textFieldProps = { variant: 'outlined' as const, - size: 'small' as const, color: field.state.meta.isDefaultValue ? ('primary' as const) : ('secondary' as const), focused: !field.state.meta.isDefaultValue, autoComplete: 'off' as const, + sx: configFieldFieldSx, + slotProps: { + input: { + sx: configFieldInputSx, + }, + }, inputProps: { - sx: { textAlign: 'right' }, 'data-testid': `config-field-${configChange.fieldName}`, }, disabled: isDisabled, @@ -89,7 +94,7 @@ export const ConfigField: React.FC = props => { - + = props => { const dateValue = useMemo(() => dayjs(field.state.value), [field.state.value]); return ( - - {title && ( - - {title} - - )} + + {title && {title}} - {description && ( - - {description} - - )} + {description && {description}} = props => { ampm={false} onChange={newDate => field.handleChange(newDate?.format(dateTimeFormatISO)!)} enableAccessibleFieldDOMStructure={false} + slots={{ + openPickerIcon: KeyboardArrowDown, + }} slotProps={{ textField: { fullWidth: true, variant: 'outlined', id: `${id}-field`, + error: !field.state.meta.isValid, helperText: field.state.meta.errors?.[0], onBlur: field.handleBlur, + sx: datePickerFieldSx, inputProps: { 'data-testid': `${id}-field`, + readOnly: true, + }, + }, + openPickerButton: { + sx: { + color: 'text.light', + marginRight: 0, + padding: 0, + '& .MuiSvgIcon-root': { + fontSize: 16, + }, }, }, }} diff --git a/apps/sv/frontend/src/components/form-components/EffectiveDateField.tsx b/apps/sv/frontend/src/components/form-components/EffectiveDateField.tsx index 26c6b0216c..a61ba99dac 100644 --- a/apps/sv/frontend/src/components/form-components/EffectiveDateField.tsx +++ b/apps/sv/frontend/src/components/form-components/EffectiveDateField.tsx @@ -10,6 +10,7 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { EffectivityType } from '../../utils/types'; import React, { useMemo } from 'react'; import { RadioSelector } from './RadioSelector'; +import { datePickerFieldSx } from '../../themes/fieldStyles'; const effectiveAtDisplayFormat = 'YYYY-MM-DD HH:mm'; @@ -106,46 +107,11 @@ export const EffectiveDateField: React.FC = props => { error: !field.state.meta.isValid, helperText: field.state.meta.errors?.[0], onBlur: field.handleBlur, + sx: datePickerFieldSx, inputProps: { 'data-testid': `${id}-field`, + readOnly: true, }, - sx: theme => ({ - width: '100%', - '& .MuiOutlinedInput-root': { - backgroundColor: '#363636', - borderRadius: '4px', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - alignSelf: 'stretch', - flexWrap: 'nowrap', - padding: '13px 16px', - overflow: 'hidden', - minHeight: 'unset', - '& fieldset': { - border: 'none', - borderRadius: '4px', - }, - }, - '& .MuiOutlinedInput-input': { - ...theme.typography.body2, - flex: 1, - minWidth: 0, - padding: 0, - lineHeight: '22px', - color: theme.palette.text.light, - backgroundColor: 'transparent', - borderRadius: 0, - WebkitBoxShadow: 'none', - }, - '& .MuiInputAdornment-root': { - flexShrink: 0, - marginLeft: theme.spacing(1.25), - }, - '& .MuiFormHelperText-root': { - mx: 0, - }, - }), }, }} /> diff --git a/apps/sv/frontend/src/components/form-components/ProposalSummaryField.tsx b/apps/sv/frontend/src/components/form-components/ProposalSummaryField.tsx index f6a7a83e53..0ff342eb9c 100644 --- a/apps/sv/frontend/src/components/form-components/ProposalSummaryField.tsx +++ b/apps/sv/frontend/src/components/form-components/ProposalSummaryField.tsx @@ -9,6 +9,12 @@ import { PROPOSAL_SUMMARY_SUBTITLE, PROPOSAL_SUMMARY_TITLE, } from '../../utils/constants'; +import { + fieldDescriptionSx, + fieldSectionSx, + fieldSectionTitleSx, + proposalSummaryFieldSx, +} from '../../themes/fieldStyles'; export interface ProposalSummaryFieldProps { id: string; @@ -27,11 +33,17 @@ export const ProposalSummaryField: React.FC = props = const currentLength = field.state.value.length; return ( - - + + {title || PROPOSAL_SUMMARY_TITLE} {optional && ( - + optional )} @@ -39,32 +51,32 @@ export const ProposalSummaryField: React.FC = props = field.handleChange(e.target.value)} error={!field.state.meta.isValid} helperText={field.state.meta.errors?.[0]} inputProps={{ 'data-testid': id, maxLength }} - id={id} /> - + {subtitle || PROPOSAL_SUMMARY_SUBTITLE} diff --git a/apps/sv/frontend/src/components/form-components/SelectField.tsx b/apps/sv/frontend/src/components/form-components/SelectField.tsx index 95bb6d8fb5..024f44a90f 100644 --- a/apps/sv/frontend/src/components/form-components/SelectField.tsx +++ b/apps/sv/frontend/src/components/form-components/SelectField.tsx @@ -1,6 +1,7 @@ // Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +import { KeyboardArrowDown } from '@mui/icons-material'; import { Box, FormControl, @@ -13,6 +14,7 @@ import { import type { FormEvent } from 'react'; import { useFieldContext } from '../../hooks/formContext'; import { scrollableSelectFieldSx } from '../beta/identifierStyles'; +import { fieldSectionSx, fieldSectionTitleSx, selectFieldSx } from '../../themes/fieldStyles'; export type Option = { key: string; value: string }; export interface SelectFieldProps { @@ -38,13 +40,17 @@ export const SelectField: React.FC = props => { const isError = !field.state.meta.isValid && !showPlaceholder; return ( - - - {title} - + + {title} - +