Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/rename-boxed-text-to-comb-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@simplepdf/react-embed-pdf": major
---

Renames the `BOXED_TEXT` tool type to `COMB_TEXT`. "Comb" is the Acrobat / PDF-spec term for box-per-character fields (IBAN, dates, CERFA), so `actions.selectTool(...)` and the `SELECT_TOOL` iframe event now use `COMB_TEXT`, and the `ToolType` union exposes `COMB_TEXT` instead of `BOXED_TEXT`.

Already-deployed embeds keep working without a code change: the editor still accepts the legacy `BOXED_TEXT` value at runtime, so this only changes the TypeScript type. If you are not calling `actions.selectTool('BOXED_TEXT')` or `sendEvent("SELECT_TOOL", { tool: "BOXED_TEXT" })`, you can safely update to this new major version.

```ts
// Before
await actions.selectTool('BOXED_TEXT');

// After
await actions.selectTool('COMB_TEXT');
```
2 changes: 1 addition & 1 deletion copilot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ The chat sidebar advertises these tools to the model. Each runs inside the ifram
| `detect_fields` | Auto-detect missing fields on scanned PDFs |
| `focus_field` | Highlight + scroll to a field |
| `set_field_value` | Write a value into a field |
| `select_tool` | Switch the editor toolbar (`TEXT`, `BOXED_TEXT`, `CHECKBOX`, `SIGNATURE`, `PICTURE`) |
| `select_tool` | Switch the editor toolbar (`TEXT`, `COMB_TEXT`, `CHECKBOX`, `SIGNATURE`, `PICTURE`) |
| `go_to_page` | Navigate to a specific page (1-indexed) |
| `move_page` | Reorder a visible page (`from_page` → `to_page`, both 1-indexed). Destructive — only fired on explicit user request |
| `delete_page` | Remove a visible page and its fields (last remaining page can't be deleted). Destructive — only fired on explicit user request |
Expand Down
9 changes: 6 additions & 3 deletions copilot/src/components/chat/chat_pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ type CompactedDocumentContent = { name: string | null; pages: DocumentContentPag
const isToolbarTool = (value: unknown): value is ToolbarTool =>
value === null ||
value === 'TEXT' ||
value === 'BOXED_TEXT' ||
value === 'COMB_TEXT' ||
value === 'CHECKBOX' ||
value === 'SIGNATURE' ||
value === 'PICTURE'
Expand All @@ -156,7 +156,7 @@ type PlacementTool = Exclude<ToolbarTool, null>
// dedupes for icon rendering.
type NewFieldHintMetadata = { kind: 'new_field_hint'; tools: PlacementTool[]; delta: number }

const PLACEMENT_TOOLS: readonly PlacementTool[] = ['TEXT', 'BOXED_TEXT', 'CHECKBOX', 'SIGNATURE', 'PICTURE']
const PLACEMENT_TOOLS: readonly PlacementTool[] = ['TEXT', 'COMB_TEXT', 'CHECKBOX', 'SIGNATURE', 'PICTURE']
const isPlacementTool = (value: unknown): value is PlacementTool =>
typeof value === 'string' && PLACEMENT_TOOLS.some((candidate) => candidate === value)

Expand All @@ -174,7 +174,9 @@ const buildNewFieldMessage = ({
if (uniqueTools.length === 1) {
return `${delta} new ${uniqueTools[0]} fields were just added to the document. Please continue helping me with them.`
}
const breakdown = uniqueTools.map((tool) => `${tools.filter((t) => t === tool).length} ${tool}`).join(', ')
const breakdown = uniqueTools
.map((tool) => `${tools.filter((t) => t === tool).length} ${tool}`)
.join(', ')
return `${delta} new fields were just added to the document (${breakdown}). Please continue helping me with them.`
})()
return { text, metadata: { kind: 'new_field_hint', tools, delta } }
Expand Down Expand Up @@ -859,6 +861,7 @@ export const ChatPane = ({
// the visible width. Reset height to 'auto' first so scrollHeight reflects
// the wrapped content, then clamp to MAX. The CSS transition on the element
// animates the height change.
// biome-ignore lint/correctness/useExhaustiveDependencies: `draft` is a deliberate re-run trigger (the body reads scrollHeight, not draft) so the textarea resizes on every keystroke; removing it freezes the height.
useLayoutEffect(() => {
const textarea = inputRef.current
if (textarea === null) {
Expand Down
4 changes: 2 additions & 2 deletions copilot/src/components/chat/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type ToolbarProps = {
onFinalisation: () => void
}

const BoxedTextIcon = ({ size = 14 }: { size?: number; strokeWidth?: number }) => (
const CombTextIcon = ({ size = 14 }: { size?: number; strokeWidth?: number }) => (
<svg
viewBox="0 0 5515 4463"
width={size}
Expand Down Expand Up @@ -48,7 +48,7 @@ export const TOOLBAR_OPTIONS: ToolOption[] = [
{ value: 'CHECKBOX', labelKey: 'toolbar.checkbox', icon: Check },
{ value: 'SIGNATURE', labelKey: 'toolbar.signature', icon: PenTool },
{ value: 'PICTURE', labelKey: 'toolbar.picture', icon: ImageIcon },
{ value: 'BOXED_TEXT', labelKey: 'toolbar.boxedText', icon: BoxedTextIcon },
{ value: 'COMB_TEXT', labelKey: 'toolbar.combText', icon: CombTextIcon },
]

export const Toolbar = ({
Expand Down
4 changes: 3 additions & 1 deletion copilot/src/lib/embed-bridge-adapters/client-tools/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import {
// in factory.ts. The switch is exhaustive over ClientToolName, so any
// addition forces a matching arm at compile time.

const tool = <TSchema extends z.ZodType>(inputSchema: TSchema): { description: string; inputSchema: TSchema } => ({
const tool = <TSchema extends z.ZodType>(
inputSchema: TSchema,
): { description: string; inputSchema: TSchema } => ({
description: inputSchema.description ?? '',
inputSchema,
})
Expand Down
30 changes: 15 additions & 15 deletions copilot/src/lib/embed-bridge/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,7 @@ export const createBridge = ({
notify()
}

const sendRequest = <TData>(
type: BridgeRequestType,
data: unknown,
): Promise<BridgeResult<TData>> =>
const sendRequest = <TData>(type: BridgeRequestType, data: unknown): Promise<BridgeResult<TData>> =>
new Promise((resolve) => {
const iframe = getIframe()
if (iframe === null || iframe.contentWindow === null) {
Expand Down Expand Up @@ -407,20 +404,23 @@ export const createBridge = ({
getState: () => state,
loadDocument: (args) => parseAndSend(LoadDocumentInput, 'LOAD_DOCUMENT', args),
getFields: () => sendRequest<{ fields: FieldRecord[] }>('GET_FIELDS', {}),
getDocumentContent: (args) => parseAndSend<typeof GetDocumentContentInput, DocumentContentResult>(
GetDocumentContentInput,
'GET_DOCUMENT_CONTENT',
args,
),
getDocumentContent: (args) =>
parseAndSend<typeof GetDocumentContentInput, DocumentContentResult>(
GetDocumentContentInput,
'GET_DOCUMENT_CONTENT',
args,
),
detectFields: () => sendRequest('DETECT_FIELDS', {}),
deleteFields: (args) => parseAndSend<typeof DeleteFieldsInput, { deleted_count: number }>(
DeleteFieldsInput,
'DELETE_FIELDS',
args,
),
deleteFields: (args) =>
parseAndSend<typeof DeleteFieldsInput, { deleted_count: number }>(
DeleteFieldsInput,
'DELETE_FIELDS',
args,
),
selectTool: (args) => parseAndSend(SelectToolInput, 'SELECT_TOOL', args),
setFieldValue: (args) => parseAndSend(SetFieldValueInput, 'SET_FIELD_VALUE', args),
focusField: (args) => parseAndSend<typeof FocusFieldInput, FocusFieldResult>(FocusFieldInput, 'FOCUS_FIELD', args),
focusField: (args) =>
parseAndSend<typeof FocusFieldInput, FocusFieldResult>(FocusFieldInput, 'FOCUS_FIELD', args),
goTo: (args) => parseAndSend(GoToInput, 'GO_TO', args),
movePage: (args) => parseAndSend(MovePageInput, 'MOVE_PAGE', args),
deletePages: (args) => parseAndSend(DeletePagesInput, 'DELETE_PAGES', args),
Expand Down
22 changes: 16 additions & 6 deletions copilot/src/lib/embed-bridge/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { z } from 'zod'
// One file, one schema per operation. The shape is the snake_case payload
// that travels over postMessage; nothing converts keys between layers.

export const SupportedFieldTypeSchema = z.enum(['TEXT', 'BOXED_TEXT', 'CHECKBOX', 'PICTURE', 'SIGNATURE'])
export const SupportedFieldTypeSchema = z.enum(['TEXT', 'COMB_TEXT', 'CHECKBOX', 'PICTURE', 'SIGNATURE'])

export const NoInput = z.object({})

Expand All @@ -28,19 +28,29 @@ export const DetectFieldsInput = NoInput.describe(

export const DeleteFieldsInput = z
.object({
field_ids: z.array(z.string()).optional().describe('Specific field identifiers to delete (omit to target by page or all)'),
page: z.number().int().positive().optional().describe('1-indexed visible page to clear (omit to target specific ids or all)'),
field_ids: z
.array(z.string())
.optional()
.describe('Specific field identifiers to delete (omit to target by page or all)'),
page: z
.number()
.int()
.positive()
.optional()
.describe('1-indexed visible page to clear (omit to target specific ids or all)'),
})
.describe(
'Deletes fields from the document. Pass field_ids to delete specific fields, page to clear a single page, or both omitted to delete every field. Destructive: only call when the user explicitly asks.',
)

export const SelectToolInput = z
.object({
tool: SupportedFieldTypeSchema.nullable().describe('Editor tool to activate. Pass null to return to the cursor.'),
tool: SupportedFieldTypeSchema.nullable().describe(
'Editor tool to activate. Pass null to return to the cursor.',
),
})
.describe(
'Switches the active editor tool. Use tool="TEXT" for free-form text, "BOXED_TEXT" for box-per-character fields (e.g. IBAN), or any of the other field types to let the user drop fields on a document without native AcroFields.',
'Switches the active editor tool. Use tool="TEXT" for free-form text, "COMB_TEXT" for box-per-character fields (e.g. IBAN), or any of the other field types to let the user drop fields on a document without native AcroFields.',
)

export const SetFieldValueInput = z
Expand All @@ -50,7 +60,7 @@ export const SetFieldValueInput = z
.string()
.nullable()
.describe(
'Value to write. TEXT/BOXED_TEXT: any string. CHECKBOX: "checked" ticks, null un-ticks (never "true"/"false"). Do not use this tool for SIGNATURE or PICTURE fields.',
'Value to write. TEXT/COMB_TEXT: any string. CHECKBOX: "checked" ticks, null un-ticks (never "true"/"false"). Do not use this tool for SIGNATURE or PICTURE fields.',
),
})
.describe('Writes a value into a single field in the PDF')
Expand Down
9 changes: 7 additions & 2 deletions copilot/src/lib/embed-bridge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
// in the union preserves IDE autocomplete for the bridge-owned literals
// while still accepting arbitrary forwarded codes — narrowing on a
// specific iframe code stays the consumer's responsibility.
type BridgeOwnedErrorCode = 'bad_input' | 'bridge_disposed' | 'iframe_not_ready' | 'missing_result' | 'timeout'
type BridgeOwnedErrorCode =
| 'bad_input'
| 'bridge_disposed'
| 'iframe_not_ready'
| 'missing_result'
| 'timeout'

export type BridgeErrorCode = BridgeOwnedErrorCode | (string & {})

Expand Down Expand Up @@ -52,7 +57,7 @@ export const isBridgeResultLike = (value: unknown): value is BridgeResult<unknow
return false
}

export type SupportedFieldType = 'TEXT' | 'BOXED_TEXT' | 'CHECKBOX' | 'PICTURE' | 'SIGNATURE'
export type SupportedFieldType = 'TEXT' | 'COMB_TEXT' | 'CHECKBOX' | 'PICTURE' | 'SIGNATURE'

export type FieldRecord = {
field_id: string
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
"checkbox": "مربع اختيار",
"signature": "توقيع",
"picture": "صورة",
"boxedText": "نص في خانات",
"combText": "نص في خانات",
"download": "تنزيل",
"submit": "إرسال"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
"checkbox": "Zaškrtávací políčko",
"signature": "Podpis",
"picture": "Obrázek",
"boxedText": "Text v polích",
"combText": "Text v polích",
"download": "Stáhnout",
"submit": "Odeslat"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Afkrydsningsfelt",
"signature": "Underskrift",
"picture": "Billede",
"boxedText": "Tekst i felter",
"combText": "Tekst i felter",
"download": "Download",
"submit": "Indsend"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Kontrollkästchen",
"signature": "Unterschrift",
"picture": "Bild",
"boxedText": "Kästchentext",
"combText": "Kästchentext",
"download": "Herunterladen",
"submit": "Senden"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Πλαίσιο ελέγχου",
"signature": "Υπογραφή",
"picture": "Εικόνα",
"boxedText": "Κείμενο σε πλαίσια",
"combText": "Κείμενο σε πλαίσια",
"download": "Λήψη",
"submit": "Υποβολή"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
"checkbox": "Checkbox",
"signature": "Signature",
"picture": "Picture",
"boxedText": "Boxed Text",
"combText": "Comb text",
"download": "Download",
"submit": "Submit"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Casilla",
"signature": "Firma",
"picture": "Imagen",
"boxedText": "Texto en casillas",
"combText": "Texto en casillas",
"download": "Descargar",
"submit": "Enviar"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/et.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Märkeruut",
"signature": "Allkiri",
"picture": "Pilt",
"boxedText": "Tekst lahtrites",
"combText": "Tekst lahtrites",
"download": "Laadi alla",
"submit": "Esita"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Valintaruutu",
"signature": "Allekirjoitus",
"picture": "Kuva",
"boxedText": "Teksti ruuduissa",
"combText": "Teksti ruuduissa",
"download": "Lataa",
"submit": "Lähetä"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Case à cocher",
"signature": "Signature",
"picture": "Image",
"boxedText": "Texte en cases",
"combText": "Texte en cases",
"download": "Télécharger",
"submit": "Envoyer"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
"checkbox": "תיבת סימון",
"signature": "חתימה",
"picture": "תמונה",
"boxedText": "טקסט בתאים",
"combText": "טקסט בתאים",
"download": "הורד",
"submit": "שלח"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "चेकबॉक्स",
"signature": "हस्ताक्षर",
"picture": "चित्र",
"boxedText": "खानों में टेक्स्ट",
"combText": "खानों में टेक्स्ट",
"download": "डाउनलोड करें",
"submit": "सबमिट करें"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Casella di controllo",
"signature": "Firma",
"picture": "Immagine",
"boxedText": "Testo in caselle",
"combText": "Testo in caselle",
"download": "Scarica",
"submit": "Invia"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Selectievakje",
"signature": "Handtekening",
"picture": "Afbeelding",
"boxedText": "Tekst in vakjes",
"combText": "Tekst in vakjes",
"download": "Downloaden",
"submit": "Verzenden"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Avkrysningsboks",
"signature": "Signatur",
"picture": "Bilde",
"boxedText": "Tekst i ruter",
"combText": "Tekst i ruter",
"download": "Last ned",
"submit": "Send inn"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
"checkbox": "Pole wyboru",
"signature": "Podpis",
"picture": "Obraz",
"boxedText": "Tekst w kratkach",
"combText": "Tekst w kratkach",
"download": "Pobierz",
"submit": "Wyślij"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Caixa de verificação",
"signature": "Assinatura",
"picture": "Imagem",
"boxedText": "Texto em quadrículas",
"combText": "Texto em quadrículas",
"download": "Transferir",
"submit": "Submeter"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/ro.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
"checkbox": "Casetă de selectare",
"signature": "Semnătură",
"picture": "Imagine",
"boxedText": "Text în căsuțe",
"combText": "Text în căsuțe",
"download": "Descarcă",
"submit": "Trimite"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Kryssruta",
"signature": "Signatur",
"picture": "Bild",
"boxedText": "Text i rutor",
"combText": "Text i rutor",
"download": "Ladda ner",
"submit": "Skicka in"
},
Expand Down
2 changes: 1 addition & 1 deletion copilot/src/locales/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"checkbox": "Onay kutusu",
"signature": "İmza",
"picture": "Resim",
"boxedText": "Kutucuklu metin",
"combText": "Kutucuklu metin",
"download": "İndir",
"submit": "Gönder"
},
Expand Down
Loading
Loading