Compare commits

...
22 changed files with 1532 additions and 2395 deletions
-1
View File
@@ -10,7 +10,6 @@
"postinstall": "fumadocs-mdx" "postinstall": "fumadocs-mdx"
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-tabs": "^1.1.13",
"fumadocs-core": "16.5.0", "fumadocs-core": "16.5.0",
"fumadocs-mdx": "14.2.6", "fumadocs-mdx": "14.2.6",
"fumadocs-ui": "16.5.0", "fumadocs-ui": "16.5.0",
+1 -1
View File
@@ -16,7 +16,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",
"@types/react": "18.3.27", "@types/react": "^19.2.17",
"typescript": "5.6.2" "typescript": "5.6.2"
} }
} }
@@ -18,7 +18,7 @@ import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro'; import { Trans } from '@lingui/react/macro';
import { keepPreviousData } from '@tanstack/react-query'; import { keepPreviousData } from '@tanstack/react-query';
import { commandScore } from 'cmdk/dist/command-score'; import { defaultFilter as commandScore } from 'cmdk';
import { import {
ArrowLeftIcon, ArrowLeftIcon,
CheckIcon, CheckIcon,
@@ -146,14 +146,17 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }:
{isLoading && <DocumentSigningFieldsLoader />} {isLoading && <DocumentSigningFieldsLoader />}
{!field.inserted && ( {!field.inserted && (
<RadioGroup onValueChange={(value) => handleSelectItem(value)} className="z-10 my-0.5 gap-y-1"> <RadioGroup
value={selectedOption}
onValueChange={(value) => handleSelectItem(value)}
className="z-10 my-0.5 gap-y-1"
>
{values?.map((item, index) => ( {values?.map((item, index) => (
<div key={index} className="flex items-center"> <div key={index} className="flex items-center">
<RadioGroupItem <RadioGroupItem
className="h-3 w-3 shrink-0" className="h-3 w-3 shrink-0"
value={item.value} value={item.value}
id={`option-${field.id}-${item.id}`} id={`option-${field.id}-${item.id}`}
checked={item.checked}
disabled={isReadOnly} disabled={isReadOnly}
/> />
{!item.value.includes('empty-value-') && item.value && ( {!item.value.includes('empty-value-') && item.value && (
@@ -167,14 +170,13 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }:
)} )}
{field.inserted && ( {field.inserted && (
<RadioGroup className="my-0.5 gap-y-1"> <RadioGroup value={field.customText ?? ''} className="my-0.5 gap-y-1">
{values?.map((item, index) => ( {values?.map((item, index) => (
<div key={index} className="flex items-center"> <div key={index} className="flex items-center">
<RadioGroupItem <RadioGroupItem
className="h-3 w-3" className="h-3 w-3"
value={item.value} value={item.value}
id={`option-${field.id}-${item.id}`} id={`option-${field.id}-${item.id}`}
checked={item.value === field.customText}
disabled={isReadOnly} disabled={isReadOnly}
/> />
{!item.value.includes('empty-value-') && item.value && ( {!item.value.includes('empty-value-') && item.value && (
@@ -215,7 +215,7 @@ export default function PDFViewer({
type VirtualizedPageListProps = { type VirtualizedPageListProps = {
scrollParentRef: ScrollTarget; scrollParentRef: ScrollTarget;
constraintRef: React.RefObject<HTMLDivElement>; constraintRef: React.RefObject<HTMLDivElement | null>;
pages: PageMeta[]; pages: PageMeta[];
numPages: number; numPages: number;
pdf: pdfjsLib.PDFDocumentProxy; pdf: pdfjsLib.PDFDocumentProxy;
+21
View File
@@ -31,6 +31,26 @@ function initPosthog() {
} }
} }
/**
* Surfaces hydration recoveries (React 19 discards the server HTML and
* re-renders on the client instead of dying) so we can track how often
* extensions/early clicks interfere with hydration in the wild.
*/
function onRecoverableError(error: unknown, errorInfo: { componentStack?: string }) {
console.error('[hydration] recovered from error', error, errorInfo.componentStack);
if (extractPostHogConfig()) {
void import('posthog-js').then(({ default: posthog }) => {
if (posthog.__loaded) {
posthog.capture('$hydration_recoverable_error', {
message: error instanceof Error ? error.message : String(error),
componentStack: errorInfo.componentStack,
});
}
});
}
}
async function main() { async function main() {
const locale = detect(fromHtmlTag('lang')) || 'en'; const locale = detect(fromHtmlTag('lang')) || 'en';
@@ -44,6 +64,7 @@ async function main() {
<HydratedRouter /> <HydratedRouter />
</I18nProvider> </I18nProvider>
</StrictMode>, </StrictMode>,
{ onRecoverableError },
); );
}); });
+4 -4
View File
@@ -57,9 +57,9 @@
"papaparse": "^5.5.3", "papaparse": "^5.5.3",
"posthog-js": "^1.297.2", "posthog-js": "^1.297.2",
"posthog-node": "4.18.0", "posthog-node": "4.18.0",
"react": "^18", "react": "^19.2.7",
"react-call": "^1.8.1", "react-call": "^1.8.1",
"react-dom": "^18", "react-dom": "^19.2.7",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
"react-hook-form": "^7.66.1", "react-hook-form": "^7.66.1",
"react-hotkeys-hook": "^4.6.2", "react-hotkeys-hook": "^4.6.2",
@@ -93,8 +93,8 @@
"@types/luxon": "^3.7.1", "@types/luxon": "^3.7.1",
"@types/node": "^20", "@types/node": "^20",
"@types/papaparse": "^5.5.0", "@types/papaparse": "^5.5.0",
"@types/react": "18.3.27", "@types/react": "^19.2.17",
"@types/react-dom": "^18", "@types/react-dom": "^19.2.3",
"@types/ua-parser-js": "^0.7.39", "@types/ua-parser-js": "^0.7.39",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"esbuild": "^0.27.0", "esbuild": "^0.27.0",
+1366 -2266
View File
File diff suppressed because it is too large Load Diff
+38 -4
View File
@@ -48,14 +48,16 @@
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.4.8", "@biomejs/biome": "2.4.8",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@commitlint/cli": "^20.1.0", "@commitlint/cli": "^20.1.0",
"@commitlint/config-conventional": "^20.0.0", "@commitlint/config-conventional": "^20.0.0",
"@datadog/pprof": "^5.13.5", "@datadog/pprof": "^5.13.5",
"@lingui/cli": "^5.6.0", "@lingui/cli": "^5.6.0",
"@prisma/client": "^6.19.0", "@prisma/client": "^6.19.0",
"@trpc/client": "11.8.1", "@trpc/client": "11.17.0",
"@trpc/react-query": "11.8.1", "@trpc/react-query": "11.17.0",
"@trpc/server": "11.8.1", "@trpc/server": "11.17.0",
"@ts-rest/core": "^3.52.1", "@ts-rest/core": "^3.52.1",
"@ts-rest/open-api": "^3.52.1", "@ts-rest/open-api": "^3.52.1",
"@ts-rest/serverless": "^3.52.1", "@ts-rest/serverless": "^3.52.1",
@@ -92,12 +94,40 @@
"@lingui/conf": "^5.6.0", "@lingui/conf": "^5.6.0",
"@lingui/core": "^5.6.0", "@lingui/core": "^5.6.0",
"@prisma/extension-read-replicas": "^0.4.1", "@prisma/extension-read-replicas": "^0.4.1",
"@radix-ui/react-accordion": "^1.2.16",
"@radix-ui/react-alert-dialog": "^1.1.19",
"@radix-ui/react-aspect-ratio": "^1.1.11",
"@radix-ui/react-avatar": "^1.2.2",
"@radix-ui/react-checkbox": "^1.3.7",
"@radix-ui/react-collapsible": "^1.1.16",
"@radix-ui/react-context-menu": "^2.3.3",
"@radix-ui/react-dialog": "^1.1.19",
"@radix-ui/react-dropdown-menu": "^2.1.20",
"@radix-ui/react-hover-card": "^1.1.19",
"@radix-ui/react-label": "^2.1.11",
"@radix-ui/react-menubar": "^1.1.20",
"@radix-ui/react-navigation-menu": "^1.2.18",
"@radix-ui/react-popover": "^1.1.19",
"@radix-ui/react-progress": "^1.1.12",
"@radix-ui/react-radio-group": "^1.4.3",
"@radix-ui/react-scroll-area": "^1.2.14",
"@radix-ui/react-select": "^2.3.3",
"@radix-ui/react-separator": "^1.1.11",
"@radix-ui/react-slider": "^1.4.3",
"@radix-ui/react-slot": "^1.3.0",
"@radix-ui/react-switch": "^1.3.3",
"@radix-ui/react-tabs": "^1.1.17",
"@radix-ui/react-toast": "^1.2.19",
"@radix-ui/react-toggle": "^1.1.14",
"@radix-ui/react-toggle-group": "^1.1.15",
"@radix-ui/react-tooltip": "^1.2.12",
"ai": "^5.0.104", "ai": "^5.0.104",
"cron-parser": "^5.5.0", "cron-parser": "^5.5.0",
"luxon": "^3.7.2", "luxon": "^3.7.2",
"patch-package": "^8.0.1", "patch-package": "^8.0.1",
"posthog-node": "4.18.0", "posthog-node": "4.18.0",
"react": "^18", "react": "^19.2.7",
"react-dom": "^19.2.7",
"typescript": "5.6.2", "typescript": "5.6.2",
"@marsidev/react-turnstile": "^1.5.0", "@marsidev/react-turnstile": "^1.5.0",
"zod": "^3.25.76" "zod": "^3.25.76"
@@ -106,6 +136,10 @@
"lodash": "4.18.1", "lodash": "4.18.1",
"pdfjs-dist": "5.4.296", "pdfjs-dist": "5.4.296",
"postcss": "^8.5.19", "postcss": "^8.5.19",
"react": "$react",
"react-dom": "$react-dom",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"typescript": "5.6.2", "typescript": "5.6.2",
"zod": "$zod", "zod": "$zod",
"fumadocs-mdx": { "fumadocs-mdx": {
+1 -1
View File
@@ -19,7 +19,7 @@
"arctic": "^3.7.0", "arctic": "^3.7.0",
"hono": "^4.12.14", "hono": "^4.12.14",
"luxon": "^3.7.2", "luxon": "^3.7.2",
"react": "^18", "react": "^19.2.7",
"ts-pattern": "^5.9.0", "ts-pattern": "^5.9.0",
"zod": "^3.25.76" "zod": "^3.25.76"
} }
+19 -17
View File
@@ -1,17 +1,19 @@
export { Body } from '@react-email/body'; export {
export { Button } from '@react-email/button'; Body,
export { Column } from '@react-email/column'; Button,
export { Container } from '@react-email/container'; Column,
export { Font } from '@react-email/font'; Container,
export { Head } from '@react-email/head'; Font,
export { Heading } from '@react-email/heading'; Head,
export { Hr } from '@react-email/hr'; Heading,
export { Html } from '@react-email/html'; Hr,
export { Img } from '@react-email/img'; Html,
export { Link } from '@react-email/link'; Img,
export { Preview } from '@react-email/preview'; Link,
export { render } from '@react-email/render'; Preview,
export { Row } from '@react-email/row'; Row,
export { Section } from '@react-email/section'; render,
export { Tailwind } from '@react-email/tailwind'; Section,
export { Text } from '@react-email/text'; Tailwind,
Text,
} from 'react-email';
+2 -20
View File
@@ -19,27 +19,9 @@
"dependencies": { "dependencies": {
"@documenso/nodemailer-resend": "5.0.0", "@documenso/nodemailer-resend": "5.0.0",
"@documenso/tailwind-config": "*", "@documenso/tailwind-config": "*",
"@react-email/body": "0.2.0", "@react-email/render": "2.1.0",
"@react-email/button": "0.2.0",
"@react-email/code-block": "0.2.0",
"@react-email/code-inline": "0.0.5",
"@react-email/column": "0.0.13",
"@react-email/container": "0.0.15",
"@react-email/font": "0.0.9",
"@react-email/head": "0.0.12",
"@react-email/heading": "0.0.15",
"@react-email/hr": "0.0.11",
"@react-email/html": "0.0.11",
"@react-email/img": "0.0.11",
"@react-email/link": "0.0.12",
"@react-email/preview": "0.0.13",
"@react-email/render": "2.0.0",
"@react-email/row": "0.0.12",
"@react-email/section": "0.0.16",
"@react-email/tailwind": "^2.0.1",
"@react-email/text": "0.1.5",
"nodemailer": "^9.0.0", "nodemailer": "^9.0.0",
"react-email": "^5.0.6", "react-email": "^6.9.0",
"resend": "^6.5.2" "resend": "^6.5.2"
}, },
"devDependencies": { "devDependencies": {
@@ -8,7 +8,7 @@ type SaveRequest<T, R> = {
export const useAutoSave = <T, R = void>(onSave: (data: T) => Promise<R>, options: { delay?: number } = {}) => { export const useAutoSave = <T, R = void>(onSave: (data: T) => Promise<R>, options: { delay?: number } = {}) => {
const { delay = 2000 } = options; const { delay = 2000 } = options;
const saveTimeoutRef = useRef<NodeJS.Timeout>(); const saveTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
const saveQueueRef = useRef<SaveRequest<T, R>[]>([]); const saveQueueRef = useRef<SaveRequest<T, R>[]>([]);
const isProcessingRef = useRef(false); const isProcessingRef = useRef(false);
@@ -15,7 +15,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
import { useLingui } from '@lingui/react/macro'; import { useLingui } from '@lingui/react/macro';
import { EnvelopeType, Prisma, ReadStatus, SendStatus, SigningStatus } from '@prisma/client'; import { EnvelopeType, Prisma, ReadStatus, SendStatus, SigningStatus } from '@prisma/client';
import type React from 'react'; import type React from 'react';
import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react'; import { createContext, useCallback, useContext, useMemo, useRef, useState, useSyncExternalStore } from 'react';
import { useSearchParams } from 'react-router'; import { useSearchParams } from 'react-router';
import type { TDocumentEmailSettings } from '../../types/document-email'; import type { TDocumentEmailSettings } from '../../types/document-email';
@@ -107,7 +107,39 @@ export const EnvelopeEditorProvider = ({
const [_searchParams, setSearchParams] = useSearchParams(); const [_searchParams, setSearchParams] = useSearchParams();
const [envelope, _setEnvelope] = useState(initialEnvelope); /**
* The envelope is kept in a ref-backed external store instead of useState so
* that async consumers (debounced autosave callbacks, flushAutosave, resetForms)
* can synchronously read the latest value via `getEnvelope`.
*
* React subscribes to the store through useSyncExternalStore, keeping renders in
* sync without maintaining a separate copy of the state.
*/
const envelopeStoreRef = useRef(initialEnvelope);
const envelopeStoreSubscribersRef = useRef(new Set<() => void>());
const subscribeToEnvelopeStore = useCallback((onStoreChange: () => void) => {
envelopeStoreSubscribersRef.current.add(onStoreChange);
return () => {
envelopeStoreSubscribersRef.current.delete(onStoreChange);
};
}, []);
const getEnvelope = useCallback(() => envelopeStoreRef.current, []);
const setEnvelope = useCallback((action: React.SetStateAction<TEditorEnvelope>) => {
const next = typeof action === 'function' ? action(envelopeStoreRef.current) : action;
envelopeStoreRef.current = next;
for (const onStoreChange of envelopeStoreSubscribersRef.current) {
onStoreChange();
}
}, []);
const envelope = useSyncExternalStore(subscribeToEnvelopeStore, getEnvelope, getEnvelope);
const [autosaveError, setAutosaveError] = useState<boolean>(false); const [autosaveError, setAutosaveError] = useState<boolean>(false);
const isCscMode = IS_INSTANCE_CSC_MODE(); const isCscMode = IS_INSTANCE_CSC_MODE();
@@ -135,8 +167,6 @@ export const EnvelopeEditorProvider = ({
}; };
}, [isCscMode, providedEditorConfig]); }, [isCscMode, providedEditorConfig]);
const envelopeRef = useRef(initialEnvelope);
const externalFlushCallbacksRef = useRef<Map<string, () => Promise<void>>>(new Map()); const externalFlushCallbacksRef = useRef<Map<string, () => Promise<void>>>(new Map());
const pendingMutationsRef = useRef<Set<Promise<unknown>>>(new Set()); const pendingMutationsRef = useRef<Set<Promise<unknown>>>(new Set());
@@ -156,14 +186,6 @@ export const EnvelopeEditorProvider = ({
}); });
}, []); }, []);
const setEnvelope: typeof _setEnvelope = (action) => {
_setEnvelope((prev) => {
const next = typeof action === 'function' ? action(prev) : action;
envelopeRef.current = next;
return next;
});
};
const isEmbedded = editorConfig.embedded !== undefined; const isEmbedded = editorConfig.embedded !== undefined;
const editorFields = useEditorFields({ const editorFields = useEditorFields({
@@ -192,16 +214,18 @@ export const EnvelopeEditorProvider = ({
try { try {
let recipients: TEditorEnvelope['recipients'] = []; let recipients: TEditorEnvelope['recipients'] = [];
const currentEnvelope = getEnvelope();
if (!isEmbedded) { if (!isEmbedded) {
const response = await setRecipientsMutation.mutateAsync({ const response = await setRecipientsMutation.mutateAsync({
envelopeId: envelope.id, envelopeId: currentEnvelope.id,
envelopeType: envelope.type, envelopeType: currentEnvelope.type,
recipients: localRecipients, recipients: localRecipients,
}); });
recipients = response.data; recipients = response.data;
} else { } else {
recipients = mapLocalRecipientsToRecipients({ envelope, localRecipients }); recipients = mapLocalRecipientsToRecipients({ envelope: currentEnvelope, localRecipients });
} }
setEnvelope((prev) => ({ setEnvelope((prev) => ({
@@ -211,9 +235,7 @@ export const EnvelopeEditorProvider = ({
})); }));
// Reset the local fields to ensure deleted recipient fields are removed. // Reset the local fields to ensure deleted recipient fields are removed.
editorFields.resetForm( editorFields.resetForm(getEnvelope().fields);
envelope.fields.filter((field) => recipients.some((recipient) => recipient.id === field.recipientId)),
);
setAutosaveError(false); setAutosaveError(false);
} catch (err) { } catch (err) {
@@ -248,16 +270,18 @@ export const EnvelopeEditorProvider = ({
try { try {
let fields: TSetEnvelopeFieldsResponse['data'] = []; let fields: TSetEnvelopeFieldsResponse['data'] = [];
const currentEnvelope = getEnvelope();
if (!isEmbedded) { if (!isEmbedded) {
const response = await setFieldsMutation.mutateAsync({ const response = await setFieldsMutation.mutateAsync({
envelopeId: envelope.id, envelopeId: currentEnvelope.id,
envelopeType: envelope.type, envelopeType: currentEnvelope.type,
fields: localFields, fields: localFields,
}); });
fields = response.data; fields = response.data;
} else { } else {
fields = mapLocalFieldsToFields({ envelope, localFields }); fields = mapLocalFieldsToFields({ envelope: currentEnvelope, localFields });
} }
setEnvelope((prev) => ({ setEnvelope((prev) => ({
@@ -309,7 +333,7 @@ export const EnvelopeEditorProvider = ({
try { try {
const response = !isEmbedded const response = !isEmbedded
? await updateEnvelopeMutation.mutateAsync({ ? await updateEnvelopeMutation.mutateAsync({
envelopeId: envelope.id, envelopeId: getEnvelope().id,
data, data,
meta, meta,
}) })
@@ -467,12 +491,14 @@ export const EnvelopeEditorProvider = ({
}; };
const resetForms = () => { const resetForms = () => {
const currentEnvelope = getEnvelope();
editorRecipients.resetForm({ editorRecipients.resetForm({
recipients: envelopeRef.current.recipients, recipients: currentEnvelope.recipients,
documentMeta: envelopeRef.current.documentMeta, documentMeta: currentEnvelope.documentMeta,
}); });
editorFields.resetForm(envelopeRef.current.fields); editorFields.resetForm(currentEnvelope.fields);
}; };
const flushAutosave = async (): Promise<TEditorEnvelope> => { const flushAutosave = async (): Promise<TEditorEnvelope> => {
@@ -488,7 +514,7 @@ export const EnvelopeEditorProvider = ({
await Promise.allSettled(Array.from(pendingMutationsRef.current)); await Promise.allSettled(Array.from(pendingMutationsRef.current));
} }
return envelopeRef.current; return getEnvelope();
}; };
return ( return (
+1 -1
View File
@@ -64,7 +64,7 @@
"postcss-selector-parser": "^7.1.4", "postcss-selector-parser": "^7.1.4",
"posthog-js": "^1.297.2", "posthog-js": "^1.297.2",
"posthog-node": "4.18.0", "posthog-node": "4.18.0",
"react": "^18", "react": "^19.2.7",
"remeda": "^2.32.0", "remeda": "^2.32.0",
"sharp": "0.34.5", "sharp": "0.34.5",
"skia-canvas": "^3.0.8", "skia-canvas": "^3.0.8",
+3 -3
View File
@@ -12,9 +12,9 @@
"@documenso/prisma": "*", "@documenso/prisma": "*",
"@simplewebauthn/server": "^13.2.2", "@simplewebauthn/server": "^13.2.2",
"@tanstack/react-query": "5.90.10", "@tanstack/react-query": "5.90.10",
"@trpc/client": "11.8.1", "@trpc/client": "11.17.0",
"@trpc/react-query": "11.8.1", "@trpc/react-query": "11.17.0",
"@trpc/server": "11.8.1", "@trpc/server": "11.17.0",
"@ts-rest/core": "^3.52.1", "@ts-rest/core": "^3.52.1",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"luxon": "^3.7.2", "luxon": "^3.7.2",
+1 -1
View File
@@ -35,7 +35,7 @@ export const SigningCard3D = ({ className, name, signature, signingCelebrationIm
const [trackMouse, setTrackMouse] = useState(false); const [trackMouse, setTrackMouse] = useState(false);
const timeoutRef = useRef<number | undefined>(); const timeoutRef = useRef<number | undefined>(undefined);
const cardX = useMotionValue(0); const cardX = useMotionValue(0);
const cardY = useMotionValue(0); const cardY = useMotionValue(0);
+7 -34
View File
@@ -18,59 +18,32 @@
"@documenso/tailwind-config": "*", "@documenso/tailwind-config": "*",
"@documenso/tsconfig": "*", "@documenso/tsconfig": "*",
"@types/luxon": "^3.7.1", "@types/luxon": "^3.7.1",
"@types/react": "18.3.27", "@types/react": "^19.2.17",
"@types/react-dom": "^18", "@types/react-dom": "^19.2.3",
"react": "^18", "react": "^19.2.7",
"typescript": "5.6.2" "typescript": "5.6.2"
}, },
"dependencies": { "dependencies": {
"@documenso/lib": "*", "@documenso/lib": "*",
"@hello-pangea/dnd": "^16.6.0", "@hello-pangea/dnd": "^18.0.1",
"@hookform/resolvers": "^3", "@hookform/resolvers": "^3",
"@lingui/macro": "^5.6.0", "@lingui/macro": "^5.6.0",
"@lingui/react": "^5.6.0", "@lingui/react": "^5.6.0",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.8",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@scure/base": "^1.2.6", "@scure/base": "^1.2.6",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"cmdk": "^0.2.1", "cmdk": "^1.1.1",
"colord": "^2.9.3", "colord": "^2.9.3",
"framer-motion": "^12.23.24", "framer-motion": "^12.23.24",
"lucide-react": "^0.554.0", "lucide-react": "^0.554.0",
"luxon": "^3.7.2", "luxon": "^3.7.2",
"pdfjs-dist": "5.4.296", "pdfjs-dist": "5.4.296",
"perfect-freehand": "^1.2.2", "perfect-freehand": "^1.2.2",
"react": "^18", "react": "^19.2.7",
"react-colorful": "^5.6.1", "react-colorful": "^5.6.1",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18", "react-dom": "^19.2.7",
"react-hook-form": "^7.66.1", "react-hook-form": "^7.66.1",
"react-rnd": "^10.5.2", "react-rnd": "^10.5.2",
"remeda": "^2.32.0", "remeda": "^2.32.0",
+3 -1
View File
@@ -145,7 +145,9 @@ const CommandItem = React.forwardRef<
<CommandPrimitive.Item <CommandPrimitive.Item
ref={ref} ref={ref}
className={cn( className={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', // cmdk 1.x always renders data-disabled="true|false", so the variant must
// check the value (bare data-[disabled] matches attribute presence).
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',
className, className,
)} )}
{...props} {...props}
@@ -103,15 +103,10 @@ export const FieldContent = ({ field, documentMeta }: FieldIconProps) => {
) { ) {
return ( return (
<div className="flex flex-col gap-y-2 py-0.5"> <div className="flex flex-col gap-y-2 py-0.5">
<RadioGroup className="gap-y-1"> <RadioGroup value={field.customText ?? ''} className="gap-y-1">
{field.fieldMeta.values.map((item, index) => ( {field.fieldMeta.values.map((item, index) => (
<div key={index} className="flex items-center"> <div key={index} className="flex items-center">
<RadioGroupItem <RadioGroupItem className="pointer-events-none h-3 w-3" value={item.value} id={`option-${index}`} />
className="pointer-events-none h-3 w-3"
value={item.value}
id={`option-${index}`}
checked={item.value === field.customText}
/>
{item.value && ( {item.value && (
<Label htmlFor={`option-${index}`} className="ml-1.5 font-normal text-foreground text-xs"> <Label htmlFor={`option-${index}`} className="ml-1.5 font-normal text-foreground text-xs">
{item.value} {item.value}
@@ -1,5 +1,6 @@
import type { RecipientRole } from '@prisma/client'; import type { RecipientRole } from '@prisma/client';
import { BadgeCheck, Copy, Eye, PencilLine, User } from 'lucide-react'; import { BadgeCheck, Copy, Eye, PencilLine, User } from 'lucide-react';
import type { JSX } from 'react';
export const ROLE_ICONS: Record<RecipientRole, JSX.Element> = { export const ROLE_ICONS: Record<RecipientRole, JSX.Element> = {
SIGNER: <PencilLine className="h-4 w-4" />, SIGNER: <PencilLine className="h-4 w-4" />,
@@ -13,7 +13,7 @@ import { getSvgPathFromStroke } from './helper';
import { Point } from './point'; import { Point } from './point';
import { SignaturePadColorPicker } from './signature-pad-color-picker'; import { SignaturePadColorPicker } from './signature-pad-color-picker';
const checkSignatureValidity = (element: RefObject<HTMLCanvasElement>) => { const checkSignatureValidity = (element: RefObject<HTMLCanvasElement | null>) => {
if (!element.current) { if (!element.current) {
return false; return false;
} }