From d82d40a8482e12c5130f09f0ff7fe782db6fae51 Mon Sep 17 00:00:00 2001 From: prismiwi2015 Date: Sun, 16 Aug 2026 01:05:47 +0200 Subject: [PATCH] Make every setting a field type declares reachable from the builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A field type says what it supports; the inspector decides what to draw. Nothing joined those two, and the result was not a bug anybody could see: thirty-two supported settings had no control anywhere. The heading level on a heading. The markup in an HTML block. The file types a file field accepts. How many rows a repeater allows. The words on the ends of a scale. The button at the bottom of a page break — which is where this started, because a multi-page form in any language other than English shipped a button saying "Next" and there was nothing to be done about it. Every one of them worked perfectly once set, which is exactly why nobody noticed: the renderer honoured them, the schema stored them, the tests passed, and the only way to set one was to export the form as JSON, edit it by hand, and import it back. The join is now a table — one line per setting — and a test that reads the PHP registrations and fails when a flag has no control and no stated reason to lack one. A hand-kept list here would have agreed with itself forever while disagreeing with the plugin. On the canvas, the settings that are visible parts of the field are edited where they appear: the hint under any control that offers one, the page break's own Next and Back buttons, the repeater's Add button, the name of the step. Both panes stay in step by naming the property they edit rather than by two hand-kept lists of keys, which is one list fewer to forget. Also fixed, all found while doing the above: - `prevLabel` never rendered. A page's Back button read the break that *closes* that page, but the wording belongs to the break that opened it — the same one whose Next brought the visitor there. On a two-page form the setting was unreachable by construction. - The form title sat outside `.atf-form`, where the theme's tokens are scoped, so every `var( --atf-* )` on it was invalid — taking its font, size, colour and bottom margin with them. It had been wearing the site theme's `h2` and sitting flush against the step indicator. The tokens are now scoped to the wrapper, which is what the instance id is on anyway. - A switch rendered as a tick box. It now draws a switch, and the preview tells the two apart the same way the front end does. - A toggle drew its label twice, once as the field label and once beside the control. - The hint sat above the control on the canvas and below it on the page. - `calc`, `confirm`, `counter`, `searchable`, `disabledays`, `defaultcountry`, `explanation` and a rating `icon` were declared and read by nothing. Removed rather than given controls that would do nothing. Likert statements are edited as one per line, and a row's key is what its answers are stored against — so keys survive rewording. Correcting a typo in a statement must not detach every answer already given to it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp --- assets/css/builder.css | 64 + assets/css/form.css | 114 ++ assets/js/builder.js | 693 +++++++- assets/js/builder.min.js | 4 +- composer.lock | 2496 +++++++++++++++++++++++++++ docs/field-types.md | 64 +- docs/hooks-reference.md | 5 + docs/javascript.md | 6 + includes/field-types.php | 32 +- includes/fields.php | 34 + includes/render-controls.php | 11 +- includes/render.php | 45 +- includes/rest.php | 5 + src/builder.ts | 666 ++++++- src/field-preview.ts | 295 +++- src/types.ts | 3 + tests/phpunit/tests/render.php | 246 +++ tests/vitest/field-preview.test.ts | 180 ++ tests/vitest/field-settings.test.ts | 177 ++ 19 files changed, 4907 insertions(+), 233 deletions(-) create mode 100644 composer.lock create mode 100644 tests/vitest/field-settings.test.ts diff --git a/assets/css/builder.css b/assets/css/builder.css index 4a4c141..a94441c 100644 --- a/assets/css/builder.css +++ b/assets/css/builder.css @@ -2246,6 +2246,70 @@ os-checkbox-label.atfb-check { background: var( --atfb-accent-soft ); } +/* A control and the chrome that belongs to it — a repeater and its add button, + a page break and its navigation — kept together as one block. */ +.atfb-preview__stack { + display: flex; + flex-direction: column; + gap: 6px; +} + +/* The hint keeps `.atf-hint` from the front end, so its size and colour are the + theme's. This only stops an empty one collapsing: an editable with nothing in + it still has to be a target you can click, and the placeholder inside it is + what invites the first hint anybody writes. */ +.atfb-preview__hint { + margin: 4px 0 0; +} + +.atfb-preview__hint .atfb-editable { + display: block; + min-block-size: 1lh; +} + +/* A button whose words are the editable part. `.atf-button` gives it the + theme's real fill, radius and padding; it is a `` rather than a + `