feat: support smaller field bounds (#1344)

Currently this won't always display super well since
our insertion solution isn't amazing but our current
minimum bounds within the UI are a bit large and can be
smaller.

This change makes it smaller and uses container queries to
support dynamically displaying labels based on the container
size.
This commit is contained in:
Lucas Smith
2024-09-17 00:29:42 +10:00
committed by GitHub
parent fa6453e811
commit 7644c0d855
20 changed files with 75 additions and 49 deletions

View File

@ -267,14 +267,14 @@ export const CheckboxField = ({
)} )}
{field.inserted && ( {field.inserted && (
<div className="flex flex-col gap-y-2"> <div className="flex flex-col gap-y-1">
{values?.map((item: { id: number; value: string; checked: boolean }, index: number) => { {values?.map((item: { id: number; value: string; checked: boolean }, index: number) => {
const itemValue = item.value || `empty-value-${item.id}`; const itemValue = item.value || `empty-value-${item.id}`;
return ( return (
<div key={index} className="flex items-center gap-x-1.5"> <div key={index} className="flex items-center gap-x-1.5">
<Checkbox <Checkbox
className="h-4 w-4" className="h-3 w-3"
checkClassName="text-white" checkClassName="text-white"
id={`checkbox-${index}`} id={`checkbox-${index}`}
checked={field.customText checked={field.customText
@ -283,7 +283,7 @@ export const CheckboxField = ({
disabled={isLoading} disabled={isLoading}
onCheckedChange={() => void handleCheckboxOptionClick(item)} onCheckedChange={() => void handleCheckboxOptionClick(item)}
/> />
<Label htmlFor={`checkbox-${index}`}> <Label htmlFor={`checkbox-${index}`} className="text-xs">
{item.value.includes('empty-value-') ? '' : item.value} {item.value.includes('empty-value-') ? '' : item.value}
</Label> </Label>
</div> </div>

View File

@ -150,7 +150,7 @@ export const DateField = ({
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 text-sm duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{localDateString} {localDateString}
</p> </p>
)} )}

View File

@ -189,7 +189,10 @@ export const DropdownField = ({
}, },
)} )}
> >
<SelectValue placeholder={`${_(msg`Select`)}`} /> <SelectValue
className="text-[clamp(0.625rem,1cqw,0.825rem)]"
placeholder={`${_(msg`Select`)}`}
/>
</SelectTrigger> </SelectTrigger>
<SelectContent className="w-full ring-0 focus:ring-0" position="popper"> <SelectContent className="w-full ring-0 focus:ring-0" position="popper">
{parsedFieldMeta?.values?.map((item, index) => ( {parsedFieldMeta?.values?.map((item, index) => (
@ -203,7 +206,7 @@ export const DropdownField = ({
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 flex items-center justify-center gap-x-1 duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{field.customText} {field.customText}
</p> </p>
)} )}

View File

@ -128,7 +128,7 @@ export const EmailField = ({ field, recipient, onSignField, onUnsignField }: Ema
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 truncate duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{field.customText} {field.customText}
</p> </p>
)} )}

View File

@ -131,7 +131,7 @@ export const InitialsField = ({
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 truncate duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{field.customText} {field.customText}
</p> </p>
)} )}

View File

@ -172,7 +172,7 @@ export const NameField = ({ field, recipient, onSignField, onUnsignField }: Name
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 truncate duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{field.customText} {field.customText}
</p> </p>
)} )}

View File

@ -259,7 +259,7 @@ export const NumberField = ({ field, recipient, onSignField, onUnsignField }: Nu
)} )}
{field.inserted && ( {field.inserted && (
<p className="text-muted-foreground dark:text-background/80 flex items-center justify-center gap-x-1 duration-200"> <p className="text-muted-foreground dark:text-background/80 text-[clamp(0.625rem,1cqw,0.825rem)] duration-200">
{field.customText} {field.customText}
</p> </p>
)} )}
@ -267,7 +267,7 @@ export const NumberField = ({ field, recipient, onSignField, onUnsignField }: Nu
<Dialog open={showRadioModal} onOpenChange={setShowRadioModal}> <Dialog open={showRadioModal} onOpenChange={setShowRadioModal}>
<DialogContent> <DialogContent>
<DialogTitle> <DialogTitle>
{parsedFieldMeta?.label ? parsedFieldMeta?.label : <Trans>Add number</Trans>} {parsedFieldMeta?.label ? parsedFieldMeta?.label : <Trans>Number</Trans>}
</DialogTitle> </DialogTitle>
<div> <div>

View File

@ -173,16 +173,16 @@ export const RadioField = ({ field, recipient, onSignField, onUnsignField }: Rad
)} )}
{field.inserted && ( {field.inserted && (
<RadioGroup> <RadioGroup className="gap-y-1">
{values?.map((item, index) => ( {values?.map((item, index) => (
<div key={index} className="flex items-center gap-x-1.5"> <div key={index} className="flex items-center gap-x-1.5">
<RadioGroupItem <RadioGroupItem
className="" className="h-3 w-3"
value={item.value} value={item.value}
id={`option-${index}`} id={`option-${index}`}
checked={item.value === field.customText} checked={item.value === field.customText}
/> />
<Label htmlFor={`option-${index}`}> <Label htmlFor={`option-${index}`} className="text-xs">
{item.value.includes('empty-value-') ? '' : item.value} {item.value.includes('empty-value-') ? '' : item.value}
</Label> </Label>
</div> </div>

View File

@ -128,7 +128,7 @@ export const SigningFieldContainer = ({
}; };
return ( return (
<div className={cn(type === 'Checkbox' ? 'group' : '')}> <div className={cn('[container-type:size]', type === 'Checkbox' ? 'group' : '')}>
<FieldRootContainer field={field}> <FieldRootContainer field={field}>
{!field.inserted && !loading && !readOnlyField && ( {!field.inserted && !loading && !readOnlyField && (
<button <button

View File

@ -253,7 +253,7 @@ export const TextField = ({ field, recipient, onSignField, onUnsignField }: Text
> >
<span className="flex items-center justify-center gap-x-1"> <span className="flex items-center justify-center gap-x-1">
<Type /> <Type />
{fieldDisplayName || <Trans>Add text</Trans>} {fieldDisplayName || <Trans>Text</Trans>}
</span> </span>
</p> </p>
)} )}
@ -269,7 +269,7 @@ export const TextField = ({ field, recipient, onSignField, onUnsignField }: Text
<Dialog open={showCustomTextModal} onOpenChange={setShowCustomTextModal}> <Dialog open={showCustomTextModal} onOpenChange={setShowCustomTextModal}>
<DialogContent> <DialogContent>
<DialogTitle> <DialogTitle>
{parsedFieldMeta?.label ? parsedFieldMeta?.label : <Trans>Add Text</Trans>} {parsedFieldMeta?.label ? parsedFieldMeta?.label : <Trans>Text</Trans>}
</DialogTitle> </DialogTitle>
<div> <div>

File diff suppressed because one or more lines are too long

View File

@ -251,8 +251,8 @@ msgid "Add more"
msgstr "" msgstr ""
#: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270 #: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270
msgid "Add number" #~ msgid "Add number"
msgstr "" #~ msgstr "Nummer hinzufügen"
#: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:146 #: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:146
#: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:154 #: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:154
@ -276,12 +276,12 @@ msgid "Add team email"
msgstr "" msgstr ""
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256 #: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256
msgid "Add text" #~ msgid "Add text"
msgstr "" #~ msgstr "Text hinzufügen"
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272 #: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272
msgid "Add Text" #~ msgid "Add Text"
msgstr "" #~ msgstr "Text hinzufügen"
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:152 #: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:152
msgid "Add the people who will sign the document." msgid "Add the people who will sign the document."
@ -2078,6 +2078,10 @@ msgstr ""
msgid "Nothing to do" msgid "Nothing to do"
msgstr "" msgstr ""
#: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270
msgid "Number"
msgstr ""
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128 #: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
msgid "On this page, you can create a new webhook." msgid "On this page, you can create a new webhook."
msgstr "" msgstr ""
@ -2598,7 +2602,7 @@ msgstr ""
msgid "Security activity" msgid "Security activity"
msgstr "" msgstr ""
#: apps/web/src/app/(signing)/sign/[token]/dropdown-field.tsx:192 #: apps/web/src/app/(signing)/sign/[token]/dropdown-field.tsx:194
msgid "Select" msgid "Select"
msgstr "" msgstr ""
@ -3114,6 +3118,11 @@ msgstr ""
msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields." msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields."
msgstr "" msgstr ""
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272
msgid "Text"
msgstr ""
#: apps/web/src/app/(dashboard)/admin/site-settings/banner-form.tsx:166 #: apps/web/src/app/(dashboard)/admin/site-settings/banner-form.tsx:166
msgid "Text Color" msgid "Text Color"
msgstr "" msgstr ""

File diff suppressed because one or more lines are too long

View File

@ -246,8 +246,8 @@ msgid "Add more"
msgstr "Add more" msgstr "Add more"
#: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270 #: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270
msgid "Add number" #~ msgid "Add number"
msgstr "Add number" #~ msgstr "Add number"
#: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:146 #: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:146
#: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:154 #: apps/web/src/app/(dashboard)/settings/security/passkeys/create-passkey-dialog.tsx:154
@ -271,12 +271,12 @@ msgid "Add team email"
msgstr "Add team email" msgstr "Add team email"
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256 #: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256
msgid "Add text" #~ msgid "Add text"
msgstr "Add text" #~ msgstr "Add text"
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272 #: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272
msgid "Add Text" #~ msgid "Add Text"
msgstr "Add Text" #~ msgstr "Add Text"
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:152 #: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:152
msgid "Add the people who will sign the document." msgid "Add the people who will sign the document."
@ -2096,6 +2096,10 @@ msgstr "Not supported"
msgid "Nothing to do" msgid "Nothing to do"
msgstr "Nothing to do" msgstr "Nothing to do"
#: apps/web/src/app/(signing)/sign/[token]/number-field.tsx:270
msgid "Number"
msgstr "Number"
#: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128 #: apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx:128
msgid "On this page, you can create a new webhook." msgid "On this page, you can create a new webhook."
msgstr "On this page, you can create a new webhook." msgstr "On this page, you can create a new webhook."
@ -2616,7 +2620,7 @@ msgstr "Security"
msgid "Security activity" msgid "Security activity"
msgstr "Security activity" msgstr "Security activity"
#: apps/web/src/app/(signing)/sign/[token]/dropdown-field.tsx:192 #: apps/web/src/app/(signing)/sign/[token]/dropdown-field.tsx:194
msgid "Select" msgid "Select"
msgstr "Select" msgstr "Select"
@ -3136,6 +3140,11 @@ msgstr "Templates"
msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields." msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields."
msgstr "Templates allow you to quickly generate documents with pre-filled recipients and fields." msgstr "Templates allow you to quickly generate documents with pre-filled recipients and fields."
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:256
#: apps/web/src/app/(signing)/sign/[token]/text-field.tsx:272
msgid "Text"
msgstr "Text"
#: apps/web/src/app/(dashboard)/admin/site-settings/banner-form.tsx:166 #: apps/web/src/app/(dashboard)/admin/site-settings/banner-form.tsx:166
msgid "Text Color" msgid "Text Color"
msgstr "Text Color" msgstr "Text Color"

View File

@ -64,8 +64,8 @@ const fontCaveat = Caveat({
variable: '--font-caveat', variable: '--font-caveat',
}); });
const MIN_HEIGHT_PX = 40; const MIN_HEIGHT_PX = 20;
const MIN_WIDTH_PX = 140; const MIN_WIDTH_PX = 80;
export type FieldFormType = { export type FieldFormType = {
nativeId?: number; nativeId?: number;

View File

@ -26,19 +26,21 @@ export const CheckboxField = ({ field }: CheckboxFieldProps) => {
} }
return ( return (
<div className="flex flex-col gap-y-2"> <div className="flex flex-col gap-y-1">
{!parsedFieldMeta?.values ? ( {!parsedFieldMeta?.values ? (
<FieldIcon fieldMeta={field.fieldMeta} type={field.type} signerEmail={field.signerEmail} /> <FieldIcon fieldMeta={field.fieldMeta} type={field.type} signerEmail={field.signerEmail} />
) : ( ) : (
parsedFieldMeta.values.map((item: { value: string; checked: boolean }, index: number) => ( parsedFieldMeta.values.map((item: { value: string; checked: boolean }, index: number) => (
<div key={index} className="flex items-center gap-x-1.5"> <div key={index} className="flex items-center gap-x-1.5">
<Checkbox <Checkbox
className="h-4 w-4" className="h-3 w-3"
checkClassName="text-white" checkClassName="text-white"
id={`checkbox-${index}`} id={`checkbox-${index}`}
checked={item.checked} checked={item.checked}
/> />
<Label htmlFor={`checkbox-${index}`}>{item.value}</Label> <Label htmlFor={`checkbox-${index}`} className="text-xs">
{item.value}
</Label>
</div> </div>
)) ))
)} )}

View File

@ -30,16 +30,18 @@ export const RadioField = ({ field }: RadioFieldProps) => {
{!parsedFieldMeta?.values ? ( {!parsedFieldMeta?.values ? (
<FieldIcon fieldMeta={field.fieldMeta} type={field.type} signerEmail={field.signerEmail} /> <FieldIcon fieldMeta={field.fieldMeta} type={field.type} signerEmail={field.signerEmail} />
) : ( ) : (
<RadioGroup> <RadioGroup className="gap-y-1">
{parsedFieldMeta.values?.map((item, index) => ( {parsedFieldMeta.values?.map((item, index) => (
<div key={index} className="flex items-center gap-x-1.5"> <div key={index} className="flex items-center gap-x-1.5">
<RadioGroupItem <RadioGroupItem
className="pointer-events-none" className="pointer-events-none h-3 w-3"
value={item.value} value={item.value}
id={`option-${index}`} id={`option-${index}`}
checked={item.checked} checked={item.checked}
/> />
<Label htmlFor={`option-${index}`}>{item.value}</Label> <Label htmlFor={`option-${index}`} className="text-xs">
{item.value}
</Label>
</div> </div>
))} ))}
</RadioGroup> </RadioGroup>

View File

@ -28,8 +28,8 @@ const fieldIcons = {
[FieldType.EMAIL]: { icon: Mail, label: 'Email' }, [FieldType.EMAIL]: { icon: Mail, label: 'Email' },
[FieldType.NAME]: { icon: User, label: 'Name' }, [FieldType.NAME]: { icon: User, label: 'Name' },
[FieldType.DATE]: { icon: CalendarDays, label: 'Date' }, [FieldType.DATE]: { icon: CalendarDays, label: 'Date' },
[FieldType.TEXT]: { icon: Type, label: 'Add text' }, [FieldType.TEXT]: { icon: Type, label: 'Text' },
[FieldType.NUMBER]: { icon: Hash, label: 'Add number' }, [FieldType.NUMBER]: { icon: Hash, label: 'Number' },
[FieldType.RADIO]: { icon: Disc, label: 'Radio' }, [FieldType.RADIO]: { icon: Disc, label: 'Radio' },
[FieldType.CHECKBOX]: { icon: CheckSquare, label: 'Checkbox' }, [FieldType.CHECKBOX]: { icon: CheckSquare, label: 'Checkbox' },
[FieldType.DROPDOWN]: { icon: ChevronDown, label: 'Select' }, [FieldType.DROPDOWN]: { icon: ChevronDown, label: 'Select' },
@ -45,7 +45,7 @@ export const FieldIcon = ({
return ( return (
<div <div
className={cn( className={cn(
'text-field-card-foreground flex items-center justify-center gap-x-1 text-xl', 'text-field-card-foreground flex items-center justify-center gap-x-1 text-[clamp(0.875rem,1.8cqw,1.2rem)]',
fontCaveatClassName, fontCaveatClassName,
)} )}
> >
@ -71,7 +71,7 @@ export const FieldIcon = ({
} }
return ( return (
<div className="text-field-card-foreground flex items-center justify-center gap-x-1.5 text-sm"> <div className="text-field-card-foreground flex items-center justify-center gap-x-1.5 text-[clamp(0.625rem,1cqw,0.825rem)]">
<Icon className="h-4 w-4" /> {label} <Icon className="h-4 w-4" /> {label}
</div> </div>
); );

View File

@ -201,6 +201,7 @@ export const FieldItem = ({
<div <div
className={cn( className={cn(
'relative flex h-full w-full items-center justify-center bg-white', 'relative flex h-full w-full items-center justify-center bg-white',
!fixedSize && '[container-type:size]',
signerStyles.default.base, signerStyles.default.base,
signerStyles.default.fieldItem, signerStyles.default.fieldItem,
)} )}
@ -223,10 +224,10 @@ export const FieldItem = ({
))} ))}
{!hideRecipients && ( {!hideRecipients && (
<div className="absolute -right-6 top-0 z-20 hidden h-full w-6 items-center justify-center group-hover:flex"> <div className="absolute -right-5 top-0 z-20 hidden h-full w-5 items-center justify-center group-hover:flex">
<div <div
className={cn( className={cn(
'flex h-7 w-6 flex-col items-center justify-center rounded-r-lg text-[0.625rem] font-bold text-white', 'flex h-5 w-5 flex-col items-center justify-center rounded-r-md text-[0.5rem] font-bold text-white',
signerStyles.default.fieldItemInitials, signerStyles.default.fieldItemInitials,
{ {
'!opacity-50': disabled || passive, '!opacity-50': disabled || passive,

View File

@ -65,8 +65,8 @@ const fontCaveat = Caveat({
variable: '--font-caveat', variable: '--font-caveat',
}); });
const MIN_HEIGHT_PX = 40; const MIN_HEIGHT_PX = 20;
const MIN_WIDTH_PX = 140; const MIN_WIDTH_PX = 80;
export type AddTemplateFieldsFormProps = { export type AddTemplateFieldsFormProps = {
documentFlow: DocumentFlowStep; documentFlow: DocumentFlowStep;