mirror of
https://github.com/documenso/documenso.git
synced 2025-11-15 09:12:02 +10:00
feat: horizontal checkboxes (#1911)
Adds the ability to have checkboxes align horizontally, wrapping when they would go off the PDF
This commit is contained in:
@ -38,13 +38,8 @@ export const FieldContent = ({ field, documentMeta }: FieldIconProps) => {
|
||||
|
||||
const { type, fieldMeta } = field;
|
||||
|
||||
// Only render checkbox if values exist, otherwise render the empty checkbox field content.
|
||||
if (
|
||||
field.type === FieldType.CHECKBOX &&
|
||||
field.fieldMeta?.type === 'checkbox' &&
|
||||
field.fieldMeta.values &&
|
||||
field.fieldMeta.values.length > 0
|
||||
) {
|
||||
// Render checkbox layout for checkbox fields, even if no values exist yet
|
||||
if (field.type === FieldType.CHECKBOX && field.fieldMeta?.type === 'checkbox') {
|
||||
let checkedValues: string[] = [];
|
||||
|
||||
try {
|
||||
@ -55,8 +50,32 @@ export const FieldContent = ({ field, documentMeta }: FieldIconProps) => {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
// If no values exist yet, show a placeholder checkbox
|
||||
if (!field.fieldMeta.values || field.fieldMeta.values.length === 0) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex gap-1 py-0.5',
|
||||
field.fieldMeta.direction === 'horizontal' ? 'flex-row flex-wrap' : 'flex-col gap-y-1',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Checkbox className="h-3 w-3" disabled />
|
||||
<Label className="text-foreground ml-1.5 text-xs font-normal opacity-50">
|
||||
Checkbox option
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-1 py-0.5">
|
||||
<div
|
||||
className={cn(
|
||||
'flex gap-1 py-0.5',
|
||||
field.fieldMeta.direction === 'horizontal' ? 'flex-row flex-wrap' : 'flex-col gap-y-1',
|
||||
)}
|
||||
>
|
||||
{field.fieldMeta.values.map((item, index) => (
|
||||
<div key={index} className="flex items-center">
|
||||
<Checkbox
|
||||
|
||||
@ -129,6 +129,7 @@ const getDefaultState = (fieldType: FieldType): FieldMeta => {
|
||||
validationLength: 0,
|
||||
required: false,
|
||||
readOnly: false,
|
||||
direction: 'vertical',
|
||||
};
|
||||
case FieldType.DROPDOWN:
|
||||
return {
|
||||
|
||||
@ -8,6 +8,7 @@ import { createPortal } from 'react-dom';
|
||||
import { Rnd } from 'react-rnd';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { useElementBounds } from '@documenso/lib/client-only/hooks/use-element-bounds';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import type { TFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
||||
import { ZCheckboxFieldMeta, ZRadioFieldMeta } from '@documenso/lib/types/field-meta';
|
||||
@ -81,7 +82,11 @@ export const FieldItem = ({
|
||||
pageWidth: defaultWidth || 0,
|
||||
});
|
||||
const [settingsActive, setSettingsActive] = useState(false);
|
||||
const $el = useRef(null);
|
||||
const $el = useRef<HTMLDivElement>(null);
|
||||
|
||||
const $pageBounds = useElementBounds(
|
||||
`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${field.pageNumber}"]`,
|
||||
);
|
||||
|
||||
const signerStyles = useRecipientColors(recipientIndex);
|
||||
|
||||
@ -233,9 +238,10 @@ export const FieldItem = ({
|
||||
default={{
|
||||
x: coords.pageX,
|
||||
y: coords.pageY,
|
||||
height: fixedSize ? '' : coords.pageHeight,
|
||||
width: fixedSize ? '' : coords.pageWidth,
|
||||
height: fixedSize ? 'auto' : coords.pageHeight,
|
||||
width: fixedSize ? 'auto' : coords.pageWidth,
|
||||
}}
|
||||
maxWidth={fixedSize && $pageBounds?.width ? $pageBounds.width - coords.pageX : undefined}
|
||||
bounds={`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${field.pageNumber}"]`}
|
||||
onDragStart={() => onFieldActivate?.()}
|
||||
onResizeStart={() => onFieldActivate?.()}
|
||||
|
||||
@ -44,6 +44,9 @@ export const CheckboxFieldAdvancedSettings = ({
|
||||
const [required, setRequired] = useState(fieldState.required ?? false);
|
||||
const [validationLength, setValidationLength] = useState(fieldState.validationLength ?? 0);
|
||||
const [validationRule, setValidationRule] = useState(fieldState.validationRule ?? '');
|
||||
const [direction, setDirection] = useState<'vertical' | 'horizontal'>(
|
||||
fieldState.direction ?? 'vertical',
|
||||
);
|
||||
|
||||
const handleToggleChange = (field: keyof CheckboxFieldMeta, value: string | boolean) => {
|
||||
const readOnly = field === 'readOnly' ? Boolean(value) : Boolean(fieldState.readOnly);
|
||||
@ -52,11 +55,14 @@ export const CheckboxFieldAdvancedSettings = ({
|
||||
field === 'validationRule' ? String(value) : String(fieldState.validationRule);
|
||||
const validationLength =
|
||||
field === 'validationLength' ? Number(value) : Number(fieldState.validationLength);
|
||||
const currentDirection =
|
||||
field === 'direction' && String(value) === 'horizontal' ? 'horizontal' : 'vertical';
|
||||
|
||||
setReadOnly(readOnly);
|
||||
setRequired(required);
|
||||
setValidationRule(validationRule);
|
||||
setValidationLength(validationLength);
|
||||
setDirection(currentDirection);
|
||||
|
||||
const errors = validateCheckboxField(
|
||||
values.map((item) => item.value),
|
||||
@ -65,6 +71,7 @@ export const CheckboxFieldAdvancedSettings = ({
|
||||
required,
|
||||
validationRule,
|
||||
validationLength,
|
||||
direction: currentDirection,
|
||||
type: 'checkbox',
|
||||
},
|
||||
);
|
||||
@ -86,6 +93,7 @@ export const CheckboxFieldAdvancedSettings = ({
|
||||
required,
|
||||
validationRule,
|
||||
validationLength,
|
||||
direction: direction,
|
||||
type: 'checkbox',
|
||||
},
|
||||
);
|
||||
@ -137,6 +145,29 @@ export const CheckboxFieldAdvancedSettings = ({
|
||||
onChange={(e) => handleFieldChange('label', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<Label>
|
||||
<Trans>Direction</Trans>
|
||||
</Label>
|
||||
<Select
|
||||
value={fieldState.direction ?? 'vertical'}
|
||||
onValueChange={(val) => handleToggleChange('direction', val)}
|
||||
>
|
||||
<SelectTrigger className="text-muted-foreground bg-background mt-2 w-full">
|
||||
<SelectValue placeholder={_(msg`Select direction`)} />
|
||||
</SelectTrigger>
|
||||
<SelectContent position="popper">
|
||||
<SelectItem value="vertical">
|
||||
<Trans>Vertical</Trans>
|
||||
</SelectItem>
|
||||
<SelectItem value="horizontal">
|
||||
<Trans>Horizontal</Trans>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center gap-x-4">
|
||||
<div className="flex w-2/3 flex-col">
|
||||
<Label>
|
||||
|
||||
Reference in New Issue
Block a user