diff --git a/CHANGELOG.md b/CHANGELOG.md index f0a210ae..630a9272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Unreleased +- Add a `hidden` option to form annotation methods, for a field that should start hidden (e.g. one an interactive action reveals later) instead of the usual default of visible and printable + ### [v0.20.2] - 2026-08-29 - Fix bundlers and file tracers packing the ESM copies of the standard font metrics instead of the CommonJS ones the Node build actually loads, which left `Cannot find module` errors for every standard font at runtime, by resolving the internal `#standard-fonts/*` mapping to a single file under all conditions diff --git a/docs/forms.md b/docs/forms.md index 544eafb6..8b36ec77 100644 --- a/docs/forms.md +++ b/docs/forms.md @@ -55,6 +55,9 @@ The following `options` are accepted by all form annotation methods: - `borderColor` - Field border color. - `fontSize` [_number_] - Sets the font size used in the field appearance string. The default, `0`, means auto sizing. +- `hidden` [_boolean_] - Builds the field starting hidden, instead of the + usual default of visible and printable, for a field an interactive action + (see `onClick` below) will reveal later. Color options accept an array of RGB values, a hex color, or a named CSS color. Method-specific options listed below are accepted in addition to these common diff --git a/lib/mixins/acroform.js b/lib/mixins/acroform.js index d283b1c4..6ae9ee56 100644 --- a/lib/mixins/acroform.js +++ b/lib/mixins/acroform.js @@ -73,6 +73,18 @@ function mapTypeAndFlags(type, userOptions, pdfObject) { } } +// The Widget annotation's own visibility/print flags (PDF spec Table 168), +// distinct from the field's `Ff` flags mapTypeAndFlags() handles above. +// formAnnotation() defaults this to 4 (print only) when left unset. +function mapVisibility(options, pdfObject) { + if (options.hidden) { + // Hidden (2) + Print (4): not shown or interactive until an action + // reveals it (e.g. a sibling field's onClick), but still printable once + // it is. + pdfObject.F = 6; + } +} + function mapJustify(userOptions, pdfObject) { const result = FIELD_JUSTIFY[userOptions.align]; if (typeof result === 'number' && result !== 0) { @@ -307,6 +319,7 @@ export default { const pdfObject = {}; mapTypeAndFlags(type, options, pdfObject); + mapVisibility(options, pdfObject); mapJustify(options, pdfObject); this._mapFont(options, pdfObject); mapStrings(options, pdfObject); diff --git a/tests/unit/acroform.spec.js b/tests/unit/acroform.spec.js index ac01fe6a..c610e0f9 100644 --- a/tests/unit/acroform.spec.js +++ b/tests/unit/acroform.spec.js @@ -139,6 +139,21 @@ describe('acroform', () => { expect(docData[2]).toBe(expected[2]); }); + test('a field built with hidden: true starts hidden', () => { + doc.initForm(); + const docData = logData(doc); + doc.formPushButton('btn1', 20, 20, 100, 30, { hidden: true }); + // 6 = Hidden + Print, overriding the usual default of 4 (print only) + expect(docData[1]).toContain('/F 6'); + }); + + test('a field without hidden keeps the usual print-only default', () => { + doc.initForm(); + const docData = logData(doc); + doc.formPushButton('btn1', 20, 20, 100, 30, {}); + expect(docData[1]).toContain('/F 4'); + }); + test('type flags do not leak implementation markers', () => { doc.initForm(); const docData = logData(doc);