From 4c486fc1e94a803fc0aa616b9756c8367ce057f5 Mon Sep 17 00:00:00 2001 From: ephraimduncan Date: Thu, 23 Apr 2026 16:43:48 +0000 Subject: [PATCH] feat: highlight unsigned required fields in red on signing page Add a 'required' key to TRecipientColor with a red ring and translucent hover fill, mirroring the recipient color shape. Both the signing DOM container and the envelope canvas renderer now route unsigned required fields to 'required', falling back to the default green once a field is inserted. On the envelope canvas, orange is now reserved for the single 'next' field the tooltip points at (recipientFieldsRemaining[0]). Other unsigned required fields stay red when the pending-field tooltip is active. --- .../document-signing-field-container.tsx | 5 ++++- .../envelope-signer-page-renderer.tsx | 9 +++++++-- packages/ui/lib/recipient-colors.ts | 15 ++++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/remix/app/components/general/document-signing/document-signing-field-container.tsx b/apps/remix/app/components/general/document-signing/document-signing-field-container.tsx index 339a60d98..b1265ca35 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-field-container.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-field-container.tsx @@ -7,6 +7,7 @@ import { X } from 'lucide-react'; import { type TRecipientActionAuth } from '@documenso/lib/types/document-auth'; import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta'; +import { isFieldUnsignedAndRequired } from '@documenso/lib/utils/advanced-fields-helpers'; import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature'; import { FieldRootContainer } from '@documenso/ui/components/field/field'; import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors'; @@ -131,7 +132,9 @@ export const DocumentSigningFieldContainer = ({ return ( {!field.inserted && !loading && !readOnlyField && ( diff --git a/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx b/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx index 34ff0ee5d..693a554a4 100644 --- a/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx +++ b/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx @@ -138,10 +138,15 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD const fieldToRender = ZFullFieldSchema.parse(unparsedField); + const isNextPendingField = + showPendingFieldTooltip && recipientFieldsRemaining[0]?.id === fieldToRender.id; + const color = fieldToRender.fieldMeta?.readOnly ? 'readOnly' - : showPendingFieldTooltip && isFieldUnsignedAndRequired(fieldToRender) - ? 'orange' + : isFieldUnsignedAndRequired(fieldToRender) + ? isNextPendingField + ? 'orange' + : 'required' : 'green'; const { fieldGroup } = renderField({ diff --git a/packages/ui/lib/recipient-colors.ts b/packages/ui/lib/recipient-colors.ts index 6408d68bf..65cdb64f9 100644 --- a/packages/ui/lib/recipient-colors.ts +++ b/packages/ui/lib/recipient-colors.ts @@ -1,7 +1,7 @@ import { colord } from 'colord'; import { once } from 'remeda'; -export type TRecipientColor = 'readOnly' | (typeof AVAILABLE_RECIPIENT_COLORS)[number]; +export type TRecipientColor = 'readOnly' | 'required' | (typeof AVAILABLE_RECIPIENT_COLORS)[number]; export type RecipientColorStyles = { base: string; @@ -33,6 +33,19 @@ const RECIPIENT_COLOR_STYLES: Record RecipientColorStyles 'ring-2 ring-recipient-green shadow-[0_0_0_5px_hsl(var(--recipient-green)/10%),0_0_0_2px_hsl(var(--recipient-green)/60%),0_0_0_0.5px_hsl(var(--recipient-green))]', comboBoxItem: '', }), + required: (): RecipientColorStyles => ({ + base: 'ring-red-400 hover:bg-red-400/30', + baseRing: 'rgba(248, 113, 113, 1)', + baseRingHover: 'rgba(248, 113, 113, 0.3)', + baseTextHover: 'rgba(248, 113, 113, 1)', + fieldButton: 'border-red-400 hover:border-red-400', + fieldButtonText: '', + fieldItem: 'group/field-item rounded-[2px]', + fieldItemInitials: '', + comboBoxTrigger: + 'ring-2 ring-red-400 shadow-[0_0_0_5px_rgba(248,113,113,0.1),0_0_0_2px_rgba(248,113,113,0.6),0_0_0_0.5px_rgba(248,113,113,1)]', + comboBoxItem: '', + }), green: once(() => generateStyles('green')), blue: once(() => generateStyles('blue')), purple: once(() => generateStyles('purple')),