fix: rework fields (#1697)

Rework:
- Field styling to improve visibility
- Field insertions, better alignment, centering and overflows

## Changes

General changes:

- Set default text alignment to left if no meta found
- Reduce borders and rings around fields to allow smaller fields
- Removed lots of redundant duplicated code surrounding field rendering
- Make fields more consistent across viewing, editing and signing
- Add more transparency to fields to allow users to see under fields
- No more optional/required/etc colors when signing, required fields
will be highlighted as orange when form is "validating"

Highlighted internal changes:

- Utilize native PDF fields to insert text, instead of drawing text 
- Change font auto scaling to only apply to when the height overflows
AND no custom font is set

⚠️ Multiline changes:

Multi line is enabled for a field under these conditions

1. Field content exceeds field width
2. Field includes a new line
3. Field type is TEXT

## [BEFORE] Field UI Signing 


![image](https://github.com/user-attachments/assets/ea002743-faeb-477c-a239-3ed240b54f55)

## [AFTER] Field UI Signing 


![image](https://github.com/user-attachments/assets/0f8eb252-4cf3-4d96-8d4f-cd085881b78c)

## [BEFORE] Signing a checkbox


![image](https://github.com/user-attachments/assets/4567d745-e1da-4202-a758-5d3c178c930e)

![image](https://github.com/user-attachments/assets/c25068e7-fe80-40f5-b63a-e8a0d4b38b6c)

## [AFTER] Signing a checkbox


![image](https://github.com/user-attachments/assets/effa5e3d-385a-4c35-bc8a-405386dd27d6)

![image](https://github.com/user-attachments/assets/64be34a9-0b32-424d-9264-15361c03eca5)

## [BEFORE] What a 2nd recipient sees once someone else signed a
document


![image](https://github.com/user-attachments/assets/21c21ae2-fc62-4ccc-880a-46aab012aa70)

## [AFTER] What a 2nd recipient sees once someone else signed a document


![image](https://github.com/user-attachments/assets/ae51677b-f1d5-4008-a7fd-756533166542)

## **[BEFORE]** Inserting fields


![image](https://github.com/user-attachments/assets/1a8bb8da-9a15-4deb-bc28-eb349414465c)

## **[AFTER]** Inserting fields


![image](https://github.com/user-attachments/assets/c52c5238-9836-45aa-b8a4-bc24a3462f40)

## Overflows, multilines and field alignments testing

Debugging borders:
- Red border = The original field placement without any modifications
- Blue border = The available space to overflow

### Single line overflows and field alignments 

This is left aligned fields, overflow will always go to the end of the
page and will not wrap


![image](https://github.com/user-attachments/assets/47003658-783e-4f9c-adbf-c4686804d98f)

This is center aligned fields, the max width is the closest edge to the
page * 2


![image](https://github.com/user-attachments/assets/05a38093-75d6-4600-bae2-21ecff63e115)

This is right aligned text, the width will extend all the way to the
left hand side of the page


![image](https://github.com/user-attachments/assets/6a9d84a8-4166-4626-9fb3-1577fac2571e)

### Multiline line overflows and field alignments 

These are text fields that can be overflowed


![image](https://github.com/user-attachments/assets/f7b5456e-2c49-48b2-8d4c-ab1dc3401644)

Another example of left aligned text overflows with more text


![image](https://github.com/user-attachments/assets/3db6b35e-4c8d-4ffe-8036-0da760d9c167)
This commit is contained in:
David Nguyen
2025-04-23 21:40:42 +10:00
committed by GitHub
parent b94645a451
commit 193325717d
62 changed files with 1819 additions and 1070 deletions

View File

@ -53,7 +53,7 @@ import { FRIENDLY_FIELD_TYPE } from '@documenso/ui/primitives/document-flow/type
import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { getSignerColorStyles, useSignerColors } from '../../lib/signer-colors';
import { getRecipientColorStyles, useRecipientColors } from '../../lib/recipient-colors';
import type { FieldFormType } from '../document-flow/add-fields';
import { FieldAdvancedSettings } from '../document-flow/field-item-advanced-settings';
import { Form } from '../form/form';
@ -68,7 +68,6 @@ const DEFAULT_WIDTH_PX = MIN_WIDTH_PX * 2.5;
export type AddTemplateFieldsFormProps = {
documentFlow: DocumentFlowStep;
hideRecipients?: boolean;
recipients: Recipient[];
fields: Field[];
onSubmit: (_data: TAddTemplateFieldsFormSchema) => void;
@ -77,7 +76,6 @@ export type AddTemplateFieldsFormProps = {
export const AddTemplateFieldsFormPartial = ({
documentFlow,
hideRecipients = false,
recipients,
fields,
onSubmit,
@ -136,7 +134,7 @@ export const AddTemplateFieldsFormPartial = ({
const [showRecipientsSelector, setShowRecipientsSelector] = useState(false);
const selectedSignerIndex = recipients.findIndex((r) => r.id === selectedSigner?.id);
const selectedSignerStyles = useSignerColors(
const selectedSignerStyles = useRecipientColors(
selectedSignerIndex === -1 ? 0 : selectedSignerIndex,
);
@ -505,8 +503,8 @@ export const AddTemplateFieldsFormPartial = ({
{selectedField && (
<div
className={cn(
'text-muted-foreground dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center bg-white transition duration-200 [container-type:size]',
selectedSignerStyles.default.base,
'text-muted-foreground dark:text-muted-background pointer-events-none fixed z-50 flex cursor-pointer flex-col items-center justify-center rounded-[2px] bg-white ring-2 transition duration-200 [container-type:size]',
selectedSignerStyles?.base,
{
'-rotate-6 scale-90 opacity-50 dark:bg-black/20': !isFieldWithinBounds,
'dark:text-black/60': isFieldWithinBounds,
@ -549,7 +547,6 @@ export const AddTemplateFieldsFormPartial = ({
setCurrentField(field);
handleAdvancedSettings();
}}
hideRecipients={hideRecipients}
active={activeFieldId === field.formId}
onFieldActivate={() => setActiveFieldId(field.formId)}
onFieldDeactivate={() => setActiveFieldId(null)}
@ -557,99 +554,98 @@ export const AddTemplateFieldsFormPartial = ({
);
})}
{!hideRecipients && (
<Popover open={showRecipientsSelector} onOpenChange={setShowRecipientsSelector}>
<PopoverTrigger asChild>
<Button
type="button"
variant="outline"
role="combobox"
className={cn(
'bg-background text-muted-foreground hover:text-foreground mb-12 mt-2 justify-between font-normal',
selectedSignerStyles.default.base,
)}
>
{selectedSigner?.email && (
<span className="flex-1 truncate text-left">
{selectedSigner?.name} ({selectedSigner?.email})
</span>
)}
<Popover open={showRecipientsSelector} onOpenChange={setShowRecipientsSelector}>
<PopoverTrigger asChild>
<Button
type="button"
variant="outline"
role="combobox"
className={cn(
'bg-background text-muted-foreground hover:text-foreground mb-12 mt-2 justify-between font-normal',
selectedSignerStyles?.comboxBoxTrigger,
)}
>
{selectedSigner?.email && (
<span className="flex-1 truncate text-left">
{selectedSigner?.name} ({selectedSigner?.email})
</span>
)}
{!selectedSigner?.email && (
<span className="gradie flex-1 truncate text-left">
{selectedSigner?.email}
</span>
)}
{!selectedSigner?.email && (
<span className="gradie flex-1 truncate text-left">
{selectedSigner?.email}
</span>
)}
<ChevronsUpDown className="ml-2 h-4 w-4" />
</Button>
</PopoverTrigger>
<ChevronsUpDown className="ml-2 h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<Command value={selectedSigner?.email}>
<CommandInput />
<PopoverContent className="p-0" align="start">
<Command value={selectedSigner?.email}>
<CommandInput />
<CommandEmpty>
<span className="text-muted-foreground inline-block px-4">
<Trans>No recipient matching this description was found.</Trans>
</span>
</CommandEmpty>
<CommandEmpty>
<span className="text-muted-foreground inline-block px-4">
<Trans>No recipient matching this description was found.</Trans>
</span>
</CommandEmpty>
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
<CommandGroup key={roleIndex}>
<div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium">
{_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
{/* Note: This is duplicated in `add-fields.tsx` */}
{recipientsByRoleToDisplay.map(([role, roleRecipients], roleIndex) => (
<CommandGroup key={roleIndex}>
<div className="text-muted-foreground mb-1 ml-2 mt-2 text-xs font-medium">
{_(RECIPIENT_ROLES_DESCRIPTION[role].roleNamePlural)}
</div>
{roleRecipients.length === 0 && (
<div
key={`${role}-empty`}
className="text-muted-foreground/80 px-4 pb-4 pt-2.5 text-center text-xs"
>
<Trans>No recipients with this role</Trans>
</div>
)}
{roleRecipients.length === 0 && (
<div
key={`${role}-empty`}
className="text-muted-foreground/80 px-4 pb-4 pt-2.5 text-center text-xs"
{roleRecipients.map((recipient) => (
<CommandItem
key={recipient.id}
className={cn(
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
getRecipientColorStyles(
Math.max(
recipients.findIndex((r) => r.id === recipient.id),
0,
),
)?.comboxBoxItem,
)}
onSelect={() => {
setSelectedSigner(recipient);
setShowRecipientsSelector(false);
}}
>
<span
className={cn('text-foreground/70 truncate', {
'text-foreground/80': recipient === selectedSigner,
})}
>
<Trans>No recipients with this role</Trans>
</div>
)}
{roleRecipients.map((recipient) => (
<CommandItem
key={recipient.id}
className={cn(
'px-2 last:mb-1 [&:not(:first-child)]:mt-1',
getSignerColorStyles(
Math.max(
recipients.findIndex((r) => r.id === recipient.id),
0,
),
).default.comboxBoxItem,
{recipient.name && (
<span title={`${recipient.name} (${recipient.email})`}>
{recipient.name} ({recipient.email})
</span>
)}
onSelect={() => {
setSelectedSigner(recipient);
setShowRecipientsSelector(false);
}}
>
<span
className={cn('text-foreground/70 truncate', {
'text-foreground/80': recipient === selectedSigner,
})}
>
{recipient.name && (
<span title={`${recipient.name} (${recipient.email})`}>
{recipient.name} ({recipient.email})
</span>
)}
{!recipient.name && (
<span title={recipient.email}>{recipient.email}</span>
)}
</span>
</CommandItem>
))}
</CommandGroup>
))}
</Command>
</PopoverContent>
</Popover>
)}
{!recipient.name && (
<span title={recipient.email}>{recipient.email}</span>
)}
</span>
</CommandItem>
))}
</CommandGroup>
))}
</Command>
</PopoverContent>
</Popover>
<Form {...form}>
<div className="-mx-2 flex-1 overflow-y-auto px-2">