Replies: 2 comments 2 replies
|
@all3f0r1 I think most of this should now be implemented, right? |
2 replies
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.
Context
#637 reports that custom Portable Text block types declared by plugins (e.g.
marketing.hero,marketing.text-image) are not editable in the admin: they show up as opaque[Marketing.hero]labels with no way to expand or modify their fields. The blocks render correctly on the site via<PortableText components={…} />, and the field data is intact in the DB — the gap is entirely in the admin editing surface.Related: #84 (slash discoverability), #103 (toolbar intercepts PT clicks), #152 (marketplace plugins with PT blocks).
Per CONTRIBUTING.md, opening this in Ideas before any feature PR.
Problem (with file:line evidence)
The plugin API and runtime already declare and surface custom block schemas. The editor just doesn't read them.
packages/core/src/plugins/types.ts:1170-1183definesPortableTextBlockConfig.fields?: PortableTextBlockField[](Block Kit elements).packages/core/src/emdash-runtime.ts:1228-1267exposesplugins[id].portableTextBlocks(withfields) onGET /_emdash/api/manifest.packages/core/src/components/InlinePortableTextEditor.tsx:ptToPM(lines 415-430) coerces unknown block types into apluginBlocknode that only keeps{ blockType, id }— every other field is dropped.pmToPT(lines 205-210) serialises back as{ _type, _key, id }— the PT → PM → PT round-trip is lossy and silently destroys structured field data.useEditor({ extensions: [...] })at lines 1700-1738 has nopluginBlockextension, no NodeView, no way to render the declaredfieldsas inputs.createSlashCommandsExtension(...)at line 1690 has no input from the manifest, which is the discoverability gap in Make custom blocks explorable #84.packages/core/src/visual-editing/toolbar.ts(~line 1200) has noportableTextarm and falls through toopenAdmin(), stealing clicks from the inline editor.Proposed implementation
Five small, additive changes in the admin/editor — no DB migration, no schema change, no plugin API break.
pluginBlockTipTap node. Add adata: Record<string, unknown>attribute carrying the entire block payload minus_type/_key. Stays anatom— the React NodeView owns its layout.ptToPMroutes any block whose_typematches a registered plugin block intopluginBlockwithdata = { …rest }.pmToPTspreadsdataback out. Result: lossless round-trip even for blocks whose plugin is currently disabled.usePluginBlocks()React hook returns aMap<qualifiedType, PortableTextBlockConfig & { pluginId }>from the cached admin manifest.NodeViewdriven by Block Kit. Looks up the config, renders the declaredfieldsusing the existing@emdash-cms/blocksrenderer (packages/blocks/src/renderer.tsx) bound tonode.attrs.data, and writes back viaupdateAttributes({ data }). This is the same renderer sandboxed plugins already use for settings UI, so trusted and sandboxed plugins both get an editable block UI for free — which is the missing piece for Marketplace support for native plugins with componentsEntry and Portable Text blocks #152.datafrom each field's default value. Closes Make custom blocks explorable #84.portableText/richtextarm to the toolbar switch that no-ops, letting the inline editor receive the click. One line.Compatibility & migration
{ _type, id }) keep working: the NodeView renders declared fields with their defaults if the corresponding key is missing indata.fields. Falls back to the existing simple URL/id input, so URL-style embed plugins behave exactly as today.<PortableText components=…>is unchanged — the JSON shape on disk stays the same.Worked example
A plugin declaring a
marketing.heroblock withheadline,subheadline,image,ctaLabel,ctaHreffields. With the proposal applied, the block appears in the slash menu under "Marketing → Hero", inserts with field defaults, renders its fields as a Block Kit form inside the NodeView, and serialises to the same PT JSON the site-sidecomponents.types["marketing.hero"]already consumes.Repo
Full design doc, file:line citations, and per-step code sketches:
👉 https://github.com/all3f0r1/emdash-637-pt-blocks-editable
The repo is not a PR. It exists so the API surface and per-file diff shape can be reviewed in one place before any code lands in
packages/core. If the approach is approved here, the implementation is ~5 small commits, one per numbered file inproposal/.Out of scope (deliberate)
Asks
data-attribute approach the right shape, or do you prefer modelling each plugin block as its own typed TipTap node (per-block extension generated from the manifest)?@emdash-cms/blocks' renderer the right reuse target inside the editor, or does the admin already have a different form runtime I should reach for instead?All reactions