@@ -177,9 +177,81 @@ mountedReview.reset();
177177mountedReview .unmount ();
178178```
179179
180- The inline renderer provides accessible short-text, long-text, and rating controls. Choosing a star
181- changes only local form state; it never submits. A GitHub Issue is created only after the explicit
182- Submit button succeeds.
180+ The inline renderer provides accessible short-text, long-text, rating, and single-choice controls.
181+ Choosing an option changes only local form state; it never submits. A GitHub Issue is created only
182+ after the explicit Submit button succeeds.
183+
184+ For example, an inline poll keeps stable answer values separate from its visible labels and optional
185+ descriptions. ` radio ` , ` cards ` , and ` buttons ` displays all retain native radio keyboard semantics:
186+
187+ ``` js
188+ const poll = window .BugDrop .registerVariant ({
189+ id: ' next-integration-poll' ,
190+ presentation: { kind: ' inline' },
191+ content: { title: ' What should we build next?' , submitLabel: ' Vote' },
192+ fields: [
193+ {
194+ id: ' choice' ,
195+ type: ' singleChoice' ,
196+ label: ' Choose one' ,
197+ required: true ,
198+ display: ' cards' ,
199+ options: [
200+ { value: ' onedrive' , label: ' OneDrive' },
201+ { value: ' box' , label: ' Box' },
202+ { value: ' other' , label: ' Something else' },
203+ ],
204+ },
205+ { id: ' detail' , type: ' longText' , label: ' Optional detail' , maxLength: 500 },
206+ ],
207+ issue: {
208+ classification: ' feature' ,
209+ title: ' Integration vote — {{choice}}' ,
210+ sections: [
211+ { heading: ' Choice' , field: ' choice' , format: ' choice' },
212+ { heading: ' Detail' , field: ' detail' , omitWhenEmpty: true },
213+ ],
214+ },
215+ });
216+
217+ const mountedPoll = poll .mount (document .querySelector (' #poll-slot' ));
218+ ```
219+
220+ The title template receives the stable configured value (for example, ` onedrive ` ), while the
221+ ` choice ` section renders its display label (` OneDrive ` ). Configured labels and descriptions are
222+ inserted as text. Resetting a successful mounted poll restores its initial answers and creates a new
223+ submission identity; ` unmount() ` disposes only that instance.
224+
225+ Compact suggestions do not need a special renderer or field. Compose the existing short- and
226+ long-text controllers in the modal presentation:
227+
228+ ``` js
229+ const suggestion = window .BugDrop .registerVariant ({
230+ id: ' compact-suggestion' ,
231+ presentation: { kind: ' modal' , size: ' default' },
232+ content: { title: ' Share an idea' , submitLabel: ' Submit idea' },
233+ fields: [
234+ { id: ' summary' , type: ' shortText' , label: ' Idea' , required: true , maxLength: 120 },
235+ { id: ' detail' , type: ' longText' , label: ' How would this help?' , maxLength: 2000 },
236+ ],
237+ issue: {
238+ classification: ' feature' ,
239+ title: ' [Idea] {{summary}}' ,
240+ sections: [
241+ { heading: ' Idea' , field: ' summary' },
242+ { heading: ' Why it would help' , field: ' detail' , omitWhenEmpty: true },
243+ ],
244+ },
245+ });
246+
247+ suggestion .open ();
248+ ```
249+
250+ Every built-in controller follows the same internal controller contract for values, errors,
251+ disabled state, focus, reset, and disposal. Contributors extending the built-in field union add a
252+ controller and its shared conformance fixture; the browser still emits generic Issue sections, so
253+ the Worker formatter does not gain a field-specific branch. A public renderer registration API is
254+ not part of this contract.
183255
184256For a host-owned CTA, register a modal variant and call its handle instead of the legacy
185257` BugDrop.open() ` method:
@@ -222,10 +294,17 @@ as `submitted`, `closed`, or `busy`. A variant requested while the legacy wizard
222294` busy ` . Opening the legacy wizard while a variant modal is active closes the variant first. The
223295legacy ` BugDrop.close() ` method remains legacy-scoped.
224296
225- BugDrop's merge-queue preview checks render both this CTA modal and the inline star review from the
226- exact deployed widget bytes. They assert each normalized draft without creating Issues, followed by
227- one zero-retry rendered CTA canary that creates, independently verifies, closes, and sweeps one real
228- GitHub Issue through the existing GitHub App.
297+ BugDrop's merge-queue preview checks render the star review, CTA question, poll, and compact
298+ suggestion from the exact deployed widget bytes. Each UX intercepts and asserts its normalized draft
299+ without creating an Issue. A separate zero-retry representative canary then creates, independently
300+ verifies, closes, and sweeps exactly one real GitHub Issue through the shared Worker and GitHub App
301+ path; browser and UX coverage never multiply that destructive canary.
302+
303+ For component cleanup, keep the returned mounted or opened handle. Call ` unmount() ` for inline
304+ instances and ` close() ` for an open modal. Both are safe to call repeatedly and dispose only their
305+ own host, controller state, and listeners. ` reset() ` restores the supplied initial answers and, after
306+ a successful submission, starts a new submission identity without affecting another mounted
307+ instance or the legacy widget.
229308
230309If your application owns the UI, the same immutable handle also supports headless submission:
231310
0 commit comments