@aduptive/strapi-blockscene 2.0.0-alpha.7 → 2.0.0-alpha.9

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
@@ -1,8 +1,8 @@
1
1
  # Blockscene for Strapi
2
2
 
3
3
  A visual gallery for the components already allowed in a native Dynamic Zone,
4
- with configurable thumbnails, SVG wireframes, editor preferences and, on
5
- Strapi 5, a whole-page preview that edits the form through your own frontend.
4
+ with configurable thumbnails, SVG wireframes, editor preferences and a
5
+ whole-page preview that edits the form through your own frontend.
6
6
  No renderer, framework or content migration is required.
7
7
 
8
8
  **Alpha.** Published as pre-releases; APIs, settings and the preview bridge may
@@ -64,7 +64,7 @@ Right beside the native zone label ("blocks (3)") each zone gets a short bar:
64
64
  both off there is no button.
65
65
  - **Undo and Redo** (Strapi 5, first zone only): icon and text, the shortcut in
66
66
  the tooltip. See [Undo and redo](#undo-and-redo).
67
- - **Editing mode** (Strapi 5, first zone only, when a preview route exists): a
67
+ - **Editing mode** (first zone only, when a preview route exists): a
68
68
  menu with Fields, Fields + page and Visual editor. Without a preview route the
69
69
  menu is not shown; Settings, Blockscene says why.
70
70
  - **"…" (More actions)**: Select blocks, and "Paste N blocks" while the
@@ -104,8 +104,9 @@ The modal is a block browser (80vw wide):
104
104
  under `prefers-reduced-motion: reduce`. The panel shows a large live preview
105
105
  with Fit / Mobile / Tablet / Desktop widths (scaled to fit, as in the page
106
106
  preview) and a compact strip: label, uid, description, badges, fields (on
107
- demand), star and Insert. Double click, "+" or Enter on a focused card
108
- inserts without it.
107
+ demand), the variant choice (see [Insert variants](#insert-variants)), star
108
+ and Insert. Double click, "+" or Enter on a focused card inserts without it
109
+ (the first variant, when the block has variants).
109
110
 
110
111
  The magnified preview shows the card's thumbnail at once and fades the live
111
112
  page in over it once it has loaded. Live source, first match wins:
@@ -113,14 +114,16 @@ page in over it once it has loaded. Live source, first match wins:
113
114
  1. **Block preview URL** (`editor.blockPreviewUrl`, Settings, both versions):
114
115
  a plain page per block in a plain iframe, no bridge. Placeholders, URL
115
116
  encoded: `{uid}`, `{name}` (after the dot), `{category}` (before the dot),
116
- `{variant}` (`default`) and `{locale}` (the entry's locale, empty when the
117
- type is not localized). Example:
117
+ `{variant}` (the chosen [insert variant](#insert-variants)'s id, else
118
+ `default`) and `{locale}` (the entry's locale, empty when the type is not
119
+ localized). Example:
118
120
  `http://localhost:3026/{locale}/block-preview/{name}/{variant}`. Such a
119
121
  fixtures route is usually dev-only: leave the option empty on production.
120
- 2. **Page preview route** (Strapi 5: the preview route base URL, else the
122
+ 2. **Page preview route** (the preview route base URL, else on Strapi 5 the
121
123
  native Preview origin + `/block-preview/page`): the same bridge as the
122
- whole-page preview, sent one block made from the schema defaults, mode
123
- `preview`. Read-only: every message except `ready` is ignored.
124
+ whole-page preview, sent one block made from the chosen variant over the
125
+ schema defaults, mode `preview`. Read-only: every message except `ready`
126
+ is ignored.
124
127
  3. Otherwise the image only.
125
128
 
126
129
  If the live page neither loads nor says `ready` within 8 s, the image stays
@@ -144,9 +147,10 @@ layout, guessed from the component name and display name (hero, banner,
144
147
  cover; text, rich, quote, title; image, media, video, gallery, carousel; list,
145
148
  query, archive, related, posts, projects; card; cta, button, link; form,
146
149
  contact; wrapper, column, grid, divider, spacer, section; else text). Override
147
- it, and add up to 10 tags (1 to 24 characters), in Settings, Blockscene, or in
148
- the plugin config: `components[uid].typology` and `components[uid].tags`. A
149
- Settings value wins over the config. The former `category` config key still
150
+ it, and add up to 10 tags (1 to 24 characters), in Settings, Blockscene, in
151
+ the plugin config (`components[uid].typology` and `components[uid].tags`) or in
152
+ the component schema ([`pluginOptions.blockscene`](#describing-blocks-and-fields-in-the-schema)).
153
+ A Settings value wins over the config, the config over the schema. The former `category` config key still
150
154
  works: it becomes the block's tag when no tags are set.
151
155
 
152
156
  The native "Add a component to <zone>" button of an editable zone opens this
@@ -157,6 +161,59 @@ label ending with the raw zone name, which Strapi's message carries in every
157
161
  locale; a zone whose name ends another zone's name (`blocks` and `sub blocks`)
158
162
  is the documented limit.
159
163
 
164
+ ### Insert variants
165
+
166
+ A block can offer named presets of its field values, so the editor inserts
167
+ "Hero, dark" instead of the bare schema defaults. Variants come from the
168
+ project's code, never from the Settings page: the plugin config
169
+ `components[uid].variants`, a list of `{ id, label, values }`.
170
+
171
+ ```js
172
+ // config/plugins.js
173
+ components: {
174
+ 'blocks.hero': {
175
+ variants: [
176
+ { id: 'default', label: 'Default', values: {} },
177
+ { id: 'dark', label: { en: 'Dark', 'pt-BR': 'Escuro' }, values: {
178
+ title: 'Big launch', theme: 'dark',
179
+ link: { text: 'Read more', url: '/news' },
180
+ items: [{ label: 'One' }, { label: 'Two' }],
181
+ } },
182
+ // A frontend fixture works as is: ids, __component, media and relations are dropped.
183
+ { id: 'cases', label: 'Cases', values: require('../fixtures/hero/cases.json').data },
184
+ ],
185
+ },
186
+ },
187
+ ```
188
+
189
+ - **Choosing**: with two or more variants the magnified block shows them as a
190
+ row of buttons; the live preview follows the choice (`{variant}` in the
191
+ block preview URL, or the variant's block sent through the bridge) and
192
+ Insert inserts it. Double click, "+" and Enter insert the first variant.
193
+ The picker opened from a page preview insertion seam offers the same
194
+ choice. A block without variants behaves as before; Settings, Blockscene
195
+ lists each block's variants read-only.
196
+ - **Merge**: `values` is a partial field map over the schema defaults. A
197
+ nested component merges over its own defaults; a repeatable list replaces
198
+ the default list, each item over the item's defaults. The row goes through
199
+ the same form path as any gallery insert (Strapi 5 `addFieldRow`, Strapi 4
200
+ `addComponentToDynamicZone` then the fields' `onChange`), so nothing is
201
+ saved until Save and undo/redo covers it.
202
+ - **Supported values**, checked against the schema once at boot: text-like
203
+ fields (strings, rich text, email, uid, dates as strings), numbers
204
+ (integers, big integers, floats, decimals), booleans, enumerations (one of
205
+ their values), JSON, blocks (an array) and `null`; nested components,
206
+ single or repeatable (up to the attribute's `max`, and 100), each validated
207
+ against its own schema. Media and relation values are dropped with a boot
208
+ warning: their ids belong to one install and are not checked here. `id` and
209
+ `__component` keys are ignored, so a content-API shaped block works.
210
+ Unknown attributes, passwords and Dynamic Zones reject the variant.
211
+ - **Bounds**: `id` is 1 to 40 of `a-z 0-9 - _`, unique per block (it is the
212
+ `{variant}` URL segment); `label` a string of 1 to 60 characters or
213
+ `{ "<locale>": string }`; at most 12 variants per block, 16 KB of values
214
+ per variant and 256 KB for all of them. An invalid variant is left out with
215
+ a warning naming the problem; the block keeps its valid ones.
216
+
160
217
  ## Row thumbnails
161
218
 
162
219
  Each added block shows its thumbnail at the left of the native accordion
@@ -213,7 +270,16 @@ as an input: the plugin removes it from the components' edit layouts through
213
270
  the Content Manager's layout hook (it may be listed in "Configure the view" of
214
271
  a component; leave it out of the layout). It is not marked `visible: false`,
215
272
  because before Strapi 5.45 the edit view crashes on a value whose attribute the
216
- admin does not know. Rename it with the plugin config
273
+ admin does not know. It is kept out of the Content-Type Builder instead (the
274
+ plugin wraps the builder's component reads), so saving a component there in
275
+ `strapi develop` never writes it to the component's JSON file. With earlier
276
+ versions (up to 2.0.0-alpha.8, and 1.0.0-alpha.8 on Strapi 4) the builder did
277
+ write it (`"bsHidden": { "type": "boolean", "configurable": false, "default": false }`);
278
+ a file that has it keeps working, and the builder keeps it there on later saves.
279
+ To clean it up, delete that entry from the component JSON by hand (the plugin
280
+ still adds the attribute at startup, so the column and its data stay). To check,
281
+ edit a Dynamic Zone component in the builder (for example its display name),
282
+ save, and diff its JSON file: only your change is there. Rename it with the plugin config
217
283
  `hiddenAttribute: 'myName'`, or set `hiddenAttribute: false` to add nothing (no
218
284
  eye, nothing stripped). A component that already has an attribute of that name
219
285
  with another type is skipped with a warning. Removing the plugin (or setting
@@ -253,13 +319,14 @@ needed for the gallery to pick them up. Reading requires the
253
319
  and "Restore default colors". Colors must be `#RRGGBB`.
254
320
  - Component list with the effective source, choose/replace image from the
255
321
  Media Library, "Use automatic image", the wireframe template, the gallery
256
- typology ("Automatic" shows the guess) and tags (comma separated).
322
+ typology ("Automatic" shows the guess) and tags (comma separated); a group
323
+ OPEN also has its layout grid fields (see [Layout grid](#layout-grid)).
257
324
  - Editor preferences: enhancements on/off, visibility of each collective
258
325
  button, initial accordion state and the initial block mode.
259
326
  - Version history (Strapi 5): module switch, covered content types, retention
260
327
  (see "Version history").
261
328
  - Content types: every project type with a Dynamic Zone, each with on/off
262
- (off leaves its edit view fully native) and, on Strapi 5, the mode its edit
329
+ (off leaves its edit view fully native), the mode its edit
263
330
  views open in ("Default" follows the global preview mode), its visual
264
331
  editor sidebar and optionally its own page preview toolbar (see below).
265
332
  - "Restore project defaults" (or "Reset to defaults" when the project has no
@@ -322,16 +389,16 @@ ignored (boot continues). `GET /blockscene/settings` returns them as
322
389
  | Initial accordion state | all closed / all open / remember | all closed |
323
390
  | Load rich-text editors on demand (`lazyEditors`, Strapi 5) | yes/no | yes |
324
391
  | Custom fields loaded on demand (`lazyFields`, Strapi 5) | up to 20 uids `plugin::x.y` / `global::x` | `["plugin::ckeditor5.CKEditor"]` |
325
- | Preview route base URL (Strapi 5) | full URL or empty | empty: native Preview origin |
392
+ | Preview route base URL | full URL or empty | empty: native Preview origin (Strapi 5; none on Strapi 4) |
326
393
  | Block preview URL | http(s) URL with placeholders, up to 500 characters, or empty | empty: page preview route, else image |
327
- | Initial preview mode (Strapi 5) | form / side by side / preview | form |
394
+ | Initial preview mode | form / side by side / preview | form |
328
395
  | Confirm before deleting a block (`confirmDelete`) | yes/no | yes |
329
396
  | Duplicate on each block (`duplicate`) | yes/no | yes |
330
397
  | Copy and Paste (`clipboard`) | yes/no | yes |
331
398
  | Blocks hidden on the site (`hiddenBlocks`) | `strip` / `flag` / `off` | `strip` |
332
399
  | Friendly field labels (`friendlyLabels`, see [Field labels](#field-labels)) | yes/no | yes |
333
- | Page preview toolbar (`previewToolbar`, Strapi 5, see [Pane toolbar](#pane-toolbar)) | ordered list of `modes`, `history`, `devices`, `status`, `actions` | all five |
334
- | Page widths (`previewDevices`, Strapi 5) | 1 to 8 of `fit`, `mobile`, `tablet`, `desktop`, `{ label, width }` | the four built-in |
400
+ | Page preview toolbar (`previewToolbar`, see [Pane toolbar](#pane-toolbar)) | ordered list of `modes`, `history`, `devices`, `status`, `actions` | all five |
401
+ | Page widths (`previewDevices`) | 1 to 8 of `fit`, `mobile`, `tablet`, `desktop`, `{ label, width }` | the four built-in |
335
402
 
336
403
  Every edit view opens in its content type's mode, else the initial preview
337
404
  mode. Editors can switch while they edit; the switch is not remembered.
@@ -362,9 +429,9 @@ The accordion controls drive the native Dynamic Zone accordions through their
362
429
  `aria-expanded` headers, so no Strapi source is patched. They are validated on
363
430
  the two supported versions only.
364
431
 
365
- ## Whole-page preview (Strapi 5)
432
+ ## Whole-page preview
366
433
 
367
- The Strapi 5 distribution adds a page preview with three modes, chosen from the
434
+ Both distributions add a page preview with three modes, chosen from the
368
435
  first zone's bar and from the pane toolbar: Fields (form), Fields + page (side
369
436
  by side: resizable pane, native actions moved to a bar above the form) and
370
437
  Visual editor. It posts the live values of the first Dynamic Zone to a page
@@ -455,7 +522,30 @@ page updates while you type; Done, Esc or the backdrop put the block back. Side
455
522
  by side focuses the field in the form on the left instead. Media
456
523
  fields open the native Media Library. Everything is validated against the schema
457
524
  and the zone's edit permission; a published page never receives unsaved values
458
- by itself. Strapi 4 does not have the page preview yet (see `docs/BACKLOG.md`).
525
+ by itself.
526
+
527
+ On Strapi 4 (run on 4.26.1; the edit view APIs it uses are the same in 4.11.0)
528
+ the page preview is the same: the three modes, the same bridge
529
+ (`blockscene:page-preview:v1`, so one frontend route serves both), widths,
530
+ hover sync, the block dialog, the visual editor sidebar, custom panels,
531
+ insertion, groups and paste from the page, and the per content type settings.
532
+ It reads and writes the edit view's own data (`useCMEditViewDataManager`); new
533
+ blocks use the native insertion at a position. Differences:
534
+
535
+ - No undo and redo (no History buttons, no shortcuts). Strapi 4's form has no
536
+ way to set all values at once, and restoring each field would also undo the
537
+ relations it loads lazily, which Save would then disconnect.
538
+ - No native Preview to fall back on: set the preview route base URL.
539
+ - The toolbar's status shows Draft or Published (Strapi 4 has no Modified
540
+ state) and the unsaved hint; its Save and Publish (or Unpublish) click the
541
+ edit view header's own buttons, so their checks and dialogs are Strapi's.
542
+ - The browser smoke covers split mode, select, inline and live edits, widths,
543
+ hover, the block dialog, a sidebar item, media, insertion and toolbar Save
544
+ on 4.26.1; group tools, paste and custom panels from the page share the
545
+ Strapi 5 code and are checked there only.
546
+ - With Strapi 4's two navigation columns the content area is narrower: the
547
+ form keeps at least 520 px, so side by side the page gets less than half on
548
+ a 1440 px screen.
459
549
 
460
550
  ### Pane toolbar
461
551
 
@@ -528,8 +618,9 @@ every plugin's `register` before any `bootstrap`, then the host's `bootstrap`:
528
618
  calling `registerPanel` from either bootstrap works. An invalid panel is logged
529
619
  (`[blockscene] registerPanel: ...`) and ignored; `registerPanel` returns `true`
530
620
  or `false`. A panel that throws while rendering shows the plugin's error notice
531
- in its drawer; the editor keeps working. Strapi 5 only (the Strapi 4 package has
532
- no visual editor).
621
+ in its drawer; the editor keeps working. On Strapi 4 the same call works (its
622
+ `values` and `onChange` are the edit view data manager's); the lab smoke covers
623
+ panels on Strapi 5 only.
533
624
 
534
625
  ### Undo and redo
535
626
 
@@ -642,6 +733,50 @@ The edit view draws the same structure over Strapi's native rows (Strapi 5 and
642
733
  Unclosed groups and stray markers are indented as the page preview shows them
643
734
  but have no chevron and are never moved (the diagnostics list them).
644
735
 
736
+ ### Layout grid
737
+
738
+ An OPEN whose component lays its children out in columns (a "grid columns"
739
+ wrapper) can show them that way in the form. Name the OPEN attribute that holds
740
+ its desktop column count, per component, in Settings (the OPEN's card, "Layout
741
+ grid") or in the code `settings`:
742
+
743
+ ```json
744
+ { "components": { "wrappers.grid-columns": { "layout": { "columnsField": "columnsMd", "mobileColumnsField": "columns", "maxColumns": 3 } } } }
745
+ ```
746
+
747
+ - `columnsField` (required) and `mobileColumnsField` (optional) must be
748
+ attributes of that component that can hold a count: `integer`, `biginteger`,
749
+ `float`, `decimal`, `string`, or an `enumeration` whose every value is a whole
750
+ number (`["1", "2", "3"]`). `maxColumns` is 1 to 12 (default 12). Checked on
751
+ `PUT` and on the code settings at boot; a saved layout whose attribute was
752
+ removed is dropped on read. A layout on a component that is not a configured
753
+ OPEN does nothing.
754
+ - The count is read live from the OPEN's form: its value, else the attribute's
755
+ default, else 1, capped at `maxColumns` (a value that is not a whole number
756
+ from 1 counts as missing). The grid shows the desktop count; the mobile one is
757
+ named in its caption.
758
+ - Each child is a cell under the OPEN's header (its name and the first text of
759
+ its fields); a nested group is one cell ("N blocks"); the CLOSE stays a row
760
+ below. The children's own rows are hidden but stay mounted, so the form,
761
+ validation, Save and the row tools keep working on them; Expand all skips
762
+ them as it skips a folded group.
763
+ - A cell opens its block's native form in the block dialog (the one of the
764
+ visual editor), in any mode, with every field type. A validation error inside
765
+ a child gives its cell a red border; the dialog shows the field.
766
+ - Reorder by dragging a cell onto another, or with Alt+Arrow keys on a focused
767
+ cell (left/right one cell, up/down one row of the grid); nested groups move
768
+ whole. "Remove from group" in a cell's "…" menu moves the block right after
769
+ the CLOSE. "Add a block" opens the gallery (the zone's allowed components) and
770
+ inserts at the end of the group; an OPEN brings its CLOSE. Each of these is
771
+ one form change: one undo step on Strapi 5, nothing saved before Save.
772
+ - The icon on the OPEN's header switches that group between grid and list (the
773
+ native rows) for the session, per document and group. A folded group shows no
774
+ grid.
775
+ - Dragging a cell out of the grid onto the list is not supported (it would need
776
+ Strapi's own drag and drop): use "Remove from group", or the list view.
777
+
778
+ Strapi 5 and 4 (the block dialog is shared by both since the page preview core).
779
+
645
780
  ## Field labels
646
781
 
647
782
  The Content Manager shows each field under its "Configure the view" label, which
@@ -652,8 +787,10 @@ same hook the i18n plugin uses), so nothing in the DOM is patched and the
652
787
  saved view configuration is never changed. Per field, the first that applies:
653
788
 
654
789
  1. **Project texts** from the plugin config `fields` (below);
655
- 2. **a label set in "Configure the view"** (anything other than the attribute name);
656
- 3. **the humanized name** when "Friendly field labels" is on: `mobileColumnsCount`
790
+ 2. **schema metadata**: `pluginOptions.blockscene` on the attribute, with its
791
+ translations (see [Describing blocks and fields in the schema](#describing-blocks-and-fields-in-the-schema));
792
+ 3. **a label set in "Configure the view"** (anything other than the attribute name);
793
+ 4. **the humanized name** when "Friendly field labels" is on: `mobileColumnsCount`
657
794
  reads "Mobile columns count", `page_seo` "Page seo", acronym runs stay
658
795
  (`pageSEO` "Page SEO", `ctaURL` "Cta URL").
659
796
 
@@ -713,6 +850,85 @@ content type turned off all leave the native labels; any error leaves the
713
850
  layout untouched. Changing the interface language applies from the next edit
714
851
  view.
715
852
 
853
+ ## Describing blocks and fields in the schema
854
+
855
+ The same texts can live in the component and content type JSON files, next to
856
+ what they describe, instead of the long `components` and `fields` config maps:
857
+
858
+ ```jsonc
859
+ // src/components/sections/rich-text.json
860
+ {
861
+ "collectionName": "components_sections_rich_texts",
862
+ "info": { "displayName": "Rich text", "description": "Formatted text with an optional title and anchor." },
863
+ "pluginOptions": { "blockscene": { "tags": ["Editorial"] } },
864
+ "attributes": {
865
+ "anchor": { "type": "string", "pluginOptions": { "blockscene": { "help": "Id for links to this block (#id), without the \"#\"." } } },
866
+ "text": { "type": "richtext" }
867
+ }
868
+ }
869
+ // src/components/shared/tag.json, attribute "label"
870
+ "label": { "type": "string", "pluginOptions": { "blockscene": { "label": "Tag text", "help": "One or two words." } } }
871
+ ```
872
+
873
+ - **Block**: the native `info.description` is the gallery description;
874
+ `pluginOptions.blockscene` takes `label`, `typology`, `tags`, `keywords` and
875
+ `image`, with the same rules as the `components` config entries.
876
+ - **Field** (any content type or component attribute): `pluginOptions.blockscene`
877
+ takes `label` (up to 80 characters), `description` (300), `placeholder` (120)
878
+ and `help` (500), each a plain string in the source language, English.
879
+
880
+ Other languages go in one flat file per locale, given to the plugin config:
881
+
882
+ ```js
883
+ // config/plugins.js
884
+ blockscene: { config: { translations: { 'pt-BR': require('./blockscene/pt-BR.json') } } },
885
+ ```
886
+
887
+ ```json
888
+ {
889
+ "sections.rich-text": "Texto formatado",
890
+ "sections.rich-text.description": "Texto formatado com título e âncora opcionais.",
891
+ "sections.rich-text.anchor": "Âncora",
892
+ "sections.rich-text.anchor.help": "Id para links a este bloco (#id), sem o \"#\".",
893
+ "shared.tag.label": "Texto da tag"
894
+ }
895
+ ```
896
+
897
+ Keys are `<uid>` (block label, else the `displayName`), `<uid>.description`
898
+ (block description), `<uid>.<attribute>` (field label) and
899
+ `<uid>.<attribute>.<description|placeholder|help>`. A component attribute named
900
+ `description` takes its label as `<uid>.description.label`. The admin picks the
901
+ language as for the field labels above; a missing key shows the schema's
902
+ English text, and a translated field label with no English one in the schema
903
+ shows Strapi's own label in English.
904
+
905
+ Precedence, per text: the plugin config (`components`, `fields`, and Settings
906
+ for typology and tags) > schema metadata > native Strapi ("Configure the view"
907
+ labels, `displayName`) > automatic (humanized names, guessed typology). The
908
+ existing config keeps working unchanged. Everything is read once at boot:
909
+ invalid values (a typology outside the list, a label over 80 characters, an
910
+ unknown key) and translation keys naming no known block or field are left out,
911
+ with one warning listing them by uid.
912
+
913
+ **Content-Type Builder.** Tested on Strapi 5.52.1 and 4.26.1 in development
914
+ mode: editing and saving a component in the Content-Type Builder keeps
915
+ `pluginOptions.blockscene` (block and attributes) and `info.description`. It
916
+ has no field for them, so add and change them in the JSON files.
917
+
918
+ To move an existing config, from a clone of this repository (idempotent; each
919
+ schema file keeps its indentation and key order; labels equal to what the
920
+ plugin would show anyway, the humanized name or the `displayName`, are dropped):
921
+
922
+ ```bash
923
+ node scripts/schema-metadata.mjs ../my-project/backend --fields fields.json --components components.json [--out dir] [--source en] [--dry-run]
924
+ ```
925
+
926
+ `fields.json` and `components.json` hold the two config maps as JSON. The
927
+ translation files go to `config/blockscene/<locale>.json`; the script lists
928
+ what it could not place and the `components` keys that stay in the config
929
+ (`variants`, `template`). Remove the migrated entries from the config
930
+ afterwards: the config wins.
931
+
716
932
  ## Version history (Strapi 5)
717
933
 
718
934
  Off by default. Turn it on in Settings, Blockscene, "Version history" (or from