@pramen/cms-editor 0.0.63 → 0.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,7 +79,9 @@ on the host's own `/blog` rendering the editor's "Nothing lives here").
79
79
 
80
80
  **To write your own shell** (a Worker route, another framework), render: the stylesheet, a
81
81
  `<div id="app" data-base-path="…">`, an inline script setting `window.PRAMEN_CMS_EDITOR`,
82
- and `<script type="module" src="…editor.js">` — in that order. The dev preview in
82
+ and `<script type="module" src="…editor.js">` — in that order. If the deployment has panels,
83
+ add a `<script type="importmap">` ahead of every module script mapping `react`, `react-dom`,
84
+ `react/jsx-runtime` and `react/jsx-dev-runtime` at `dist/panel-*.js`. The dev preview in
83
85
  `scripts/build.ts` is the smallest complete example.
84
86
 
85
87
  ## Configure it
@@ -93,9 +95,58 @@ admin: {
93
95
  // signInUrl: "/signin/", // ONLY once that page exists — see the warning
94
96
  // hidePages: true, // collections-only deployments
95
97
  // extraNav: [{ label: "Curation", href: "/curate", target: "_self" }],
98
+ // panels: ["/admin/curation.js"], // your own React screens — see below
96
99
  }
97
100
  ```
98
101
 
102
+ ## Panels — your own React screen inside the chrome
103
+
104
+ A **panel** is a component you build and this editor renders, at `/apps/<slug>`, inside the
105
+ same sidebar, header and theme as everything else. It is for the screen Block Kit
106
+ (`adminPage()`) cannot describe — one that needs local interaction: a control that responds
107
+ as you type, a row that expands, a dialog, a redirect.
108
+
109
+ The entry is declared **server-side** with `adminPanel()` in `app.ts` (label, icon,
110
+ `navOrder`, `roles`), so the nav position and the role filter are the same server facts they
111
+ are for a Block Kit page — a panel you may not open is absent from the listing. This bundle
112
+ supplies only the component:
113
+
114
+ ```tsx
115
+ import { useState } from "react";
116
+
117
+ function Curation({ api, basePath, theme, setError }) { /* ordinary React */ }
118
+
119
+ globalThis.PRAMEN_CMS_EDITOR_RUNTIME.registerPanel({
120
+ slug: "curation",
121
+ contract: 1, // the panel runtime contract this bundle was BUILT against
122
+ render: Curation,
123
+ });
124
+ ```
125
+
126
+ `contract` is required and is a literal you write. Your bundle is compiled against your React
127
+ and linked against the editor's, and nothing in the loading path notices if those disagree —
128
+ so the editor asks which contract you built against and **refuses a mismatch**, naming the
129
+ slug and the fix on the panel's own route. It is not readable off the runtime on purpose:
130
+ that would be this editor checking its own number. `PANEL_RUNTIME_CONTRACT` in `src/panels.ts`
131
+ is the current value and the list of what bumps it.
132
+
133
+ Build it with **react, react-dom and both JSX runtimes external** — that is the whole
134
+ contract:
135
+
136
+ ```
137
+ bun build src/admin/curation.tsx --outfile public/admin/curation.js --minify --target=browser \
138
+ --external react --external react-dom --external react/jsx-runtime --external react/jsx-dev-runtime
139
+ ```
140
+
141
+ The editor publishes its React on `globalThis.PRAMEN_CMS_EDITOR_RUNTIME` and the shell's
142
+ import map points those specifiers at `dist/panel-*.js`, which read it back out. Two copies of
143
+ React in one page share no hook dispatcher, so a bundled one throws on the panel's first hook.
144
+
145
+ A panel is handed `api` (`call`/`resolve`, as the signed-in user), `basePath` (the mount
146
+ prefix, so your links stay inside it), `theme`, and `setError` (the chrome's error banner) —
147
+ and nothing else. The full guide, including how the URLs are declared, is in
148
+ `docs/cms.md`.
149
+
99
150
  `extraNav` links open in a **new tab** by default, because the editor's catch-all route
100
151
  matches every same-origin path — a same-tab click would land on the editor's own 404 instead
101
152
  of your tool. Add `target: "_self"` to ask for a same-tab navigation; it is honoured only