Repository navigation
RFC: form controls for preview props in the preview panel #3716
gazjones00
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Following up on #3678, which was closed pending a design discussion. Opening this as an RFC per the contribution guidelines. The two points raised there — how nested objects are handled, and whether inferring controls is a good idea at all, are the questions I'd most like to settle here, before any more implementation.
Goals
Background
Where things stand. The props panel is a raw JSON editor over
PreviewProps. It's complete — any value is expressible — but it's the wrong instrument for the frequent edits. Toggling one boolean means finding it in a JSON blob and retypingtrue, and a mistyped brace invalidates the whole document, so the preview blanks out until it's fixed. The editor is also the only entry point, which means anyone reviewing a template (rather than writing it) has to understand its props object before they can vary anything.Prior art. Storybook's
argTypesis the closest analogue and the model I'd borrow from: the component author names the control per prop (text,number,boolean,select, …), and the UI renders a form from that. Storybook also does inference, from a mix of static analysis and runtime values, and its own docs treat inferred controls as a starting point that authors are expected to override — which is relevant to the question below. CMS-style form generators (JSON Schema → form) solve the same shape of problem from a schema instead of from code.Alternatives today. Editing the template's
PreviewPropsin the editor and letting hot reload pick it up; or maintaining several template variants. Both work, neither is fast, and neither is available to someone who only has the preview open.One clarification on #3678, since the framing in the review was "inferring input fields from types": that PR did no type introspection at all. Nothing reads the TypeScript signature. Inference ran off the runtime values already present in
PreviewPropstypeof value === 'boolean'→ switch, finite number → number input, string → text input, everything else → a raw JSON field. That's a narrower mechanism than type inference, and I think it changes the risk calculus somewhat, but it does not remove the concern, which I've tried to take seriously below.Proposal
The part I think is uncontroversial: explicit declaration. A static property alongside
PreviewProps, validated server-side when the template renders and passed to the client in the rendering metadata:An invalid declaration logs a warning and the panel degrades rather than breaking the preview; strict object validation means a typo'd field fails loudly instead of being silently dropped. The JSON editor stays as the escape hatch and the source of truth for anything a control can't express.
This part is author-opt-in, so it can't produce a wrong control for anyone who hasn't asked for it. Everything genuinely open is downstream of it.
Open question 1: nested objects and arrays.
Options, roughly in order of ambition:
'user.name': { type: 'text' },'items[0].qty': { type: 'number' }— and the panel renders a flat list. Cheap, explicit, no traversal guessing. Awkward for arrays of variable length, and the flat list loses the shape.object/arraycontrol. Real nesting: grouped sections, add/remove for array items. The best UI, clearly the most work, and it raises follow-on questions (how deep, are heterogeneous arrays supported, what does "add an item" construct).I'd propose (A) for a first pass and (B) as the natural follow-up, on the grounds that (A) is strictly better than today for flat props and no worse for nested ones, and that (B) can be added without changing the declaration format's meaning. (C) seems worth designing only once there's evidence people want to edit nested email props frequently. But I don't have strong data here, and if the preference is (D) — keep the surface small and explicit — that's a coherent position and I'd rather build that than argue.
Open question 2: should anything be inferred?
The case against is the one raised in the review, and I think it's basically right in the general case: a control that looks authoritative but edits the wrong thing is worse than an honest JSON field. Concretely, where value-based inference goes wrong:
string | null, or one whose sample value is'', tells you very little.PreviewPropsgets no control at all. So inference is not even complete on its own terms — which is itself an argument for declaration being the real API.Options:
booleanis the one case with no lost information and the highest-friction JSON edit. Narrow, safe, and probably where most of the day-to-day value is.My preference is (ii), possibly widening to (iv) later. It concedes the review's point rather than working around it: booleans are the case where inference can't be wrong, and going no further means the panel never asserts a structure it doesn't actually know. (i) is also fine by me if the preference is to make the feature purely declarative — the honest tradeoff there is that nothing improves for any template nobody has annotated.
Things I'd want to agree on before writing more code
MyEmail.PreviewControlsthe right shape and name, or should this live insidePreviewProps/ somewhere else entirely?text,number,boolean,select,json) the right starting set? Obvious candidates to add or defer:textarea,date,color,radio,range,multi-select.PreviewProps) be an error, or should they render with an empty value?On contributing: yes, happy to. #3678 is a working implementation with tests, so most of the options above are a reshape of existing code rather than a from-scratch build — including the smaller ones. I'd rather land the narrow version everyone agrees on than the broad one I happened to write first, so I'm glad to cut it down to whatever comes out of this thread.
All reactions