@aduptive/strapi-blockscene 1.0.0-alpha.11 → 1.0.0-alpha.13

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
@@ -830,6 +830,87 @@ grid") or in the code `settings`:
830
830
 
831
831
  Strapi 5 and 4 (the block dialog is shared by both since the page preview core).
832
832
 
833
+ ## Text template custom field (pilot)
834
+
835
+ After Blockscene is installed and the admin is rebuilt, a component or content
836
+ type can declare a structured text field backed by JSON. Give component fields
837
+ an explicit binding: the Content Manager only supplies a path such as
838
+ `blocks.0.copy` to a nested custom input, not the component uid.
839
+ Direct content-type fields fall back to `<content-type uid>.<attribute>` (including
840
+ camelCase attribute names); an explicit binding remains supported there too.
841
+
842
+ ```jsonc
843
+ "copy": {
844
+ "type": "customField",
845
+ "customField": "plugin::blockscene.text-template",
846
+ "options": { "blockscene": { "textTemplate": "blocks.text.copy" } }
847
+ }
848
+ ```
849
+
850
+ Configure that binding separately from the content. Project defaults can stay
851
+ in `config/plugins.js`; a user with both Blockscene settings read and update
852
+ permissions also gets the pencil button beside the compact editor and can save
853
+ an override from there.
854
+
855
+ ```js
856
+ blockscene: { enabled: true, config: { settings: { textTemplates: {
857
+ 'blocks.text.copy': [
858
+ { id: 'eyebrow', label: 'Eyebrow', role: 'eyebrow', tag: 'p', token: 'label',
859
+ modifiers: ['uppercase'], required: false, allowBreaks: false,
860
+ maxChars: 24, demo: 'Example' },
861
+ { id: 'title', label: 'Title', role: 'title', tag: 'h2', token: 'title',
862
+ modifiers: [], required: true, allowBreaks: true, softLines: 2,
863
+ maxChars: 80, demo: 'A configurable title' },
864
+ ],
865
+ } } } }
866
+ ```
867
+
868
+ Entries are ordered and dynamic. Allowed tags are `h1`–`h6` and `p`; roles are
869
+ `eyebrow`, `title`, `description` and `body`; modifiers are `uppercase`,
870
+ `lowercase` and `underline`. `softLines` is guidance only and warns when the
871
+ rendered textarea actually overflows the recommended visual height. `maxChars`
872
+ is a hard Unicode character limit, including after an IME composition finishes.
873
+ An existing over-limit value remains editable while its character count does not
874
+ increase, so editors can correct legacy content incrementally.
875
+ Enter can be allowed per entry. Demo/reset is a manual editor action in this
876
+ pilot (there is no content-creation preset lifecycle) and asks before replacing
877
+ non-empty content. Removing an entry from the template hides it but does not
878
+ discard its saved text; newly added entries receive non-reused ids so that old
879
+ hidden text cannot reappear under a different part.
880
+
881
+ The stored value is deliberately small and frontend-neutral:
882
+
883
+ ```json
884
+ { "version": 1, "values": { "eyebrow": "Example", "title": "A title" } }
885
+ ```
886
+
887
+ Direct document-service and Content Manager writes use the same validation on
888
+ draft create, draft update and publish, including every draft locale selected by
889
+ an all-locales publish and Strapi 4 bulk updates. Only roots that can contain a configured
890
+ text-template field are populated for validation. Frontends can share the
891
+ allowlisted, SSR-safe projection without importing admin code:
892
+
893
+ ```js
894
+ const React = require('react')
895
+ const { renderTextTemplate, renderTextTemplateElement } = require('@aduptive/strapi-blockscene/text-template')
896
+ const parts = renderTextTemplate(template, entry.copy)
897
+ // [{ id, tag, text, lines, className }]
898
+
899
+ // React SSR: one semantic heading/paragraph, with safe text nodes and <br>.
900
+ parts.map(part => renderTextTemplateElement(part, React.createElement))
901
+ ```
902
+
903
+ `renderTextTemplateElement` passes the validated string to the element factory
904
+ as text children, never as HTML. `lines` is also available to other frameworks;
905
+ render it as text nodes and do not pass `text` or `lines` to raw-HTML APIs.
906
+
907
+ Current pilot evidence: unit/build/pack on both distributions, plus the full
908
+ field interaction and server write guards in the Strapi 5.57 local lab. Strapi
909
+ 4 compiles and shares the validation/input core, but this custom field has not
910
+ yet received a Strapi 4 browser smoke. The lab has not yet exercised a separate
911
+ restricted admin role; the pencil is permission-gated and the settings endpoint
912
+ remains the authoritative permission boundary.
913
+
833
914
  ## Field labels
834
915
 
835
916
  The Content Manager shows each field under its "Configure the view" label, which
@@ -1250,7 +1331,7 @@ the configured static base.
1250
1331
 
1251
1332
  ## Guarantees and limits
1252
1333
 
1253
- Tested versions: Strapi 4.11.0 and 4.26.1 (Node 20), 5.0.0 and 5.52.1
1334
+ Tested versions: Strapi 4.11.0 and 4.26.1 (Node 20), 5.0.0, 5.52.1 and 5.57.0
1254
1335
  (Node 22) in the local labs of this repository, and 5.23.5 and 5.31.0 in two
1255
1336
  real site projects. The peer ranges (`>=5.0.0 <6`, `>=4.11.0 <5`) express what
1256
1337
  installs without overrides, not a promise for every minor in between. Strapi