@wp-typia/project-tools 0.17.0 → 0.19.0

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.
Files changed (76) hide show
  1. package/dist/runtime/alternate-render-targets.d.ts +5 -0
  2. package/dist/runtime/alternate-render-targets.js +29 -0
  3. package/dist/runtime/block-generator-service-core.d.ts +2 -2
  4. package/dist/runtime/block-generator-service-core.js +13 -8
  5. package/dist/runtime/block-generator-service-spec.d.ts +10 -2
  6. package/dist/runtime/block-generator-service-spec.js +43 -1
  7. package/dist/runtime/built-in-block-artifacts.js +1 -0
  8. package/dist/runtime/built-in-block-code-templates/compound-child.d.ts +2 -2
  9. package/dist/runtime/built-in-block-code-templates/compound-child.js +35 -2
  10. package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +2 -2
  11. package/dist/runtime/built-in-block-code-templates/compound-parent.js +204 -27
  12. package/dist/runtime/built-in-block-code-templates/compound-persistence.d.ts +1 -1
  13. package/dist/runtime/built-in-block-code-templates/compound-persistence.js +11 -8
  14. package/dist/runtime/built-in-block-non-ts-artifacts.js +505 -2
  15. package/dist/runtime/cli-add-block.d.ts +6 -2
  16. package/dist/runtime/cli-add-block.js +71 -24
  17. package/dist/runtime/cli-add-shared.d.ts +58 -2
  18. package/dist/runtime/cli-add-shared.js +111 -12
  19. package/dist/runtime/cli-add-workspace-assets.d.ts +21 -1
  20. package/dist/runtime/cli-add-workspace-assets.js +417 -1
  21. package/dist/runtime/cli-add-workspace-rest.d.ts +14 -0
  22. package/dist/runtime/cli-add-workspace-rest.js +1060 -0
  23. package/dist/runtime/cli-add-workspace.d.ts +10 -1
  24. package/dist/runtime/cli-add-workspace.js +10 -1
  25. package/dist/runtime/cli-add.d.ts +3 -3
  26. package/dist/runtime/cli-add.js +2 -2
  27. package/dist/runtime/cli-core.d.ts +5 -1
  28. package/dist/runtime/cli-core.js +3 -1
  29. package/dist/runtime/cli-doctor-workspace.js +135 -1
  30. package/dist/runtime/cli-help.js +12 -7
  31. package/dist/runtime/cli-scaffold.d.ts +12 -2
  32. package/dist/runtime/cli-scaffold.js +222 -46
  33. package/dist/runtime/cli-templates.d.ts +4 -4
  34. package/dist/runtime/cli-templates.js +104 -39
  35. package/dist/runtime/cli-validation.d.ts +66 -0
  36. package/dist/runtime/cli-validation.js +92 -0
  37. package/dist/runtime/compound-inner-blocks.d.ts +78 -0
  38. package/dist/runtime/compound-inner-blocks.js +88 -0
  39. package/dist/runtime/index.d.ts +6 -3
  40. package/dist/runtime/index.js +4 -2
  41. package/dist/runtime/local-dev-presets.js +7 -2
  42. package/dist/runtime/migration-command-surface.js +2 -0
  43. package/dist/runtime/package-versions.d.ts +1 -0
  44. package/dist/runtime/package-versions.js +12 -0
  45. package/dist/runtime/rest-resource-artifacts.d.ts +35 -0
  46. package/dist/runtime/rest-resource-artifacts.js +158 -0
  47. package/dist/runtime/scaffold-answer-resolution.js +78 -8
  48. package/dist/runtime/scaffold-apply-utils.d.ts +4 -3
  49. package/dist/runtime/scaffold-apply-utils.js +34 -17
  50. package/dist/runtime/scaffold-bootstrap.d.ts +15 -0
  51. package/dist/runtime/scaffold-bootstrap.js +29 -7
  52. package/dist/runtime/scaffold-documents.js +24 -3
  53. package/dist/runtime/scaffold-identifiers.d.ts +17 -0
  54. package/dist/runtime/scaffold-identifiers.js +22 -0
  55. package/dist/runtime/scaffold-onboarding.js +25 -13
  56. package/dist/runtime/scaffold-package-manager-files.js +6 -1
  57. package/dist/runtime/scaffold-template-variables.js +22 -0
  58. package/dist/runtime/scaffold.d.ts +22 -1
  59. package/dist/runtime/scaffold.js +56 -11
  60. package/dist/runtime/template-render.d.ts +5 -2
  61. package/dist/runtime/template-render.js +9 -3
  62. package/dist/runtime/template-source-contracts.d.ts +11 -0
  63. package/dist/runtime/template-source-external.d.ts +1 -1
  64. package/dist/runtime/template-source-external.js +45 -13
  65. package/dist/runtime/template-source-normalization.d.ts +1 -1
  66. package/dist/runtime/template-source-normalization.js +5 -1
  67. package/dist/runtime/template-source-remote.d.ts +5 -0
  68. package/dist/runtime/template-source-remote.js +33 -0
  69. package/dist/runtime/template-source.js +35 -4
  70. package/dist/runtime/workspace-inventory.d.ts +43 -1
  71. package/dist/runtime/workspace-inventory.js +132 -1
  72. package/dist/runtime/workspace-project.d.ts +1 -1
  73. package/dist/runtime/workspace-project.js +3 -3
  74. package/package.json +9 -4
  75. package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +728 -49
  76. package/templates/query-loop/src/validator-toolkit.ts.mustache +0 -1
@@ -9,8 +9,7 @@ import {
9
9
  import { Notice, PanelBody, ToggleControl } from '@wordpress/components';
10
10
 
11
11
  import {
12
- ALLOWED_CHILD_BLOCKS,
13
- DEFAULT_CHILD_TEMPLATE,
12
+ getRootInnerBlocksPropsOptions,
14
13
  } from './children';
15
14
  import { useTypiaValidation } from './hooks';
16
15
  import type { {{pascalCase}}Attributes } from './types';
@@ -20,6 +19,14 @@ import {
20
19
  } from './validators';
21
20
 
22
21
  type EditProps = BlockEditProps< {{pascalCase}}Attributes >;
22
+ type CompoundInnerBlocksProps = Parameters< typeof InnerBlocks >[ 0 ] & {
23
+ defaultBlock?: [ string, Record< string, unknown > ];
24
+ directInsert?: boolean;
25
+ };
26
+
27
+ const TypedInnerBlocks = InnerBlocks as unknown as (
28
+ props: CompoundInnerBlocksProps
29
+ ) => ReturnType< typeof InnerBlocks >;
23
30
 
24
31
  export default function Edit( {
25
32
  attributes,
@@ -33,6 +40,7 @@ export default function Edit( {
33
40
  const blockProps = useBlockProps( {
34
41
  className: '{{cssClassName}}',
35
42
  } );
43
+ const rootInnerBlocksPropsOptions = getRootInnerBlocksPropsOptions();
36
44
 
37
45
  return (
38
46
  <>
@@ -80,12 +88,7 @@ export default function Edit( {
80
88
  </Notice>
81
89
  ) }
82
90
  <div className="{{cssClassName}}__items">
83
- <InnerBlocks
84
- allowedBlocks={ ALLOWED_CHILD_BLOCKS }
85
- renderAppender={ InnerBlocks.ButtonBlockAppender }
86
- template={ DEFAULT_CHILD_TEMPLATE }
87
- templateLock={ false }
88
- />
91
+ <TypedInnerBlocks { ...rootInnerBlocksPropsOptions } />
89
92
  </div>
90
93
  </div>
91
94
  </>
@@ -200,28 +203,202 @@ export const sanitize{{pascalCase}}Attributes =
200
203
  export const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;
201
204
  `;
202
205
  export const COMPOUND_CHILDREN_TEMPLATE = `import type { BlockTemplate } from '@wp-typia/block-types/blocks/registration';
206
+ import { InnerBlocks } from '@wordpress/block-editor';
203
207
 
204
208
  export const DEFAULT_CHILD_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}-item';
205
209
 
206
- export const ALLOWED_CHILD_BLOCKS = [
207
- \tDEFAULT_CHILD_BLOCK_NAME,
208
- \t// add-child: insert new allowed child block names here
209
- ];
210
+ export interface CompoundChildSpec {
211
+ \tancestorKeys: string[];
212
+ \tblockName: string;
213
+ \tbodyPlaceholder: string;
214
+ \tcontainer: boolean;
215
+ \tfolderSlug: string;
216
+ \tkey: string;
217
+ \tplacement: 'nested' | 'root';
218
+ \tsupportsInserter: boolean;
219
+ \ttemplateInstances: Array< Record< string, unknown > >;
220
+ \ttitle: string;
221
+ }
222
+
223
+ export interface CompoundInnerBlocksConfig {
224
+ \tdefaultBlock?: [ string, Record< string, unknown > ];
225
+ \tdirectInsert: boolean;
226
+ \torientation?: 'horizontal' | 'vertical';
227
+ \ttemplate?: BlockTemplate;
228
+ \ttemplateLock: false | 'insert' | 'all';
229
+ }
230
+
231
+ export type CompoundInnerBlocksPropsOptions = CompoundInnerBlocksConfig & {
232
+ \trenderAppender?: typeof InnerBlocks.ButtonBlockAppender;
233
+ };
210
234
 
211
- export const DEFAULT_CHILD_TEMPLATE: BlockTemplate = [
212
- \t[
213
- \t\tDEFAULT_CHILD_BLOCK_NAME,
214
- \t\t{
215
- \t\t\tbody: 'Add supporting details for the first internal item.',
216
- \t\t\ttitle: 'First Item',
217
- \t\t},
218
- \t],
219
- \t[
220
- \t\tDEFAULT_CHILD_BLOCK_NAME,
221
- \t\t{
222
- \t\t\tbody: 'Add supporting details for the second internal item.',
223
- \t\t\ttitle: 'Second Item',
224
- \t\t},
225
- \t],
235
+ export const ROOT_INNER_BLOCKS_PRESET_ID = '{{compoundInnerBlocksPreset}}';
236
+ export const ROOT_INNER_BLOCKS_PRESET_DESCRIPTION =
237
+ \t'{{compoundInnerBlocksPresetDescription}}';
238
+
239
+ const BASE_INNER_BLOCKS_CONFIG: Omit<
240
+ \tCompoundInnerBlocksConfig,
241
+ \t'defaultBlock' | 'template'
242
+ > = {
243
+ \tdirectInsert: {{compoundInnerBlocksDirectInsert}},
244
+ \torientation: {{compoundInnerBlocksOrientationExpression}},
245
+ \ttemplateLock: {{compoundInnerBlocksTemplateLockExpression}},
246
+ };
247
+
248
+ const ROOT_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}';
249
+
250
+ export const COMPOUND_CHILD_SPECS: CompoundChildSpec[] = [
251
+ \t{
252
+ \t\tancestorKeys: [],
253
+ \t\tblockName: DEFAULT_CHILD_BLOCK_NAME,
254
+ \t\tbodyPlaceholder: 'Add supporting details for this internal item.',
255
+ \t\tcontainer: false,
256
+ \t\tfolderSlug: '{{slugKebabCase}}-item',
257
+ \t\tkey: 'item',
258
+ \t\tplacement: 'root',
259
+ \t\tsupportsInserter: false,
260
+ \t\ttemplateInstances: [
261
+ \t\t\t{
262
+ \t\t\t\tbody: 'Add supporting details for the first internal item.',
263
+ \t\t\t\ttitle: 'First Item',
264
+ \t\t\t},
265
+ \t\t\t{
266
+ \t\t\t\tbody: 'Add supporting details for the second internal item.',
267
+ \t\t\t\ttitle: 'Second Item',
268
+ \t\t\t},
269
+ \t\t],
270
+ \t\ttitle: '{{compoundChildTitle}}',
271
+ \t},
272
+ \t// add-child: insert new child specs here
226
273
  ];
274
+
275
+ function buildTemplateEntriesForSpec( spec: CompoundChildSpec ): BlockTemplate {
276
+ \tconst nestedTemplate = buildNestedTemplateForKey( spec.key );
277
+
278
+ \treturn spec.templateInstances.map( ( attributes ) =>
279
+ \t\tnestedTemplate.length > 0
280
+ \t\t\t? [ spec.blockName, attributes, nestedTemplate ]
281
+ \t\t\t: [ spec.blockName, attributes ]
282
+ \t);
283
+ }
284
+
285
+ function buildNestedTemplateForKey( key: string ): BlockTemplate {
286
+ \treturn COMPOUND_CHILD_SPECS.filter(
287
+ \t\t( spec ) =>
288
+ \t\t\tspec.placement === 'nested' &&
289
+ \t\t\tspec.ancestorKeys[ spec.ancestorKeys.length - 1 ] === key
290
+ \t).flatMap( ( spec ) => buildTemplateEntriesForSpec( spec ) );
291
+ }
292
+
293
+ export const DEFAULT_CHILD_TEMPLATE: BlockTemplate =
294
+ \tCOMPOUND_CHILD_SPECS.filter( ( spec ) => spec.placement === 'root' ).flatMap(
295
+ \t\t( spec ) => buildTemplateEntriesForSpec( spec )
296
+ \t);
297
+
298
+ function buildDefaultBlockEntry(
299
+ \ttemplate?: BlockTemplate
300
+ ): [ string, Record< string, unknown > ] | undefined {
301
+ \tif (
302
+ \t\t! BASE_INNER_BLOCKS_CONFIG.directInsert ||
303
+ \t\t! Array.isArray( template ) ||
304
+ \t\ttemplate.length === 0 ||
305
+ \t\ttypeof template[ 0 ]?.[ 0 ] !== 'string'
306
+ \t) {
307
+ \t\treturn undefined;
308
+ \t}
309
+
310
+ \treturn [ template[ 0 ][ 0 ], {} ];
311
+ }
312
+
313
+ function buildInnerBlocksPropsOptions(
314
+ \tconfig: CompoundInnerBlocksConfig
315
+ ): CompoundInnerBlocksPropsOptions {
316
+ \treturn {
317
+ \t\t...config,
318
+ \t\trenderAppender:
319
+ \t\t\tconfig.templateLock === 'all'
320
+ \t\t\t\t? undefined
321
+ \t\t\t\t: InnerBlocks.ButtonBlockAppender,
322
+ \t};
323
+ }
324
+
325
+ export function getRootInnerBlocksConfig(): CompoundInnerBlocksConfig {
326
+ \treturn {
327
+ \t\t...BASE_INNER_BLOCKS_CONFIG,
328
+ \t\tdefaultBlock: buildDefaultBlockEntry( DEFAULT_CHILD_TEMPLATE ),
329
+ \t\ttemplate: DEFAULT_CHILD_TEMPLATE,
330
+ \t};
331
+ }
332
+
333
+ export function getRootInnerBlocksPropsOptions(): CompoundInnerBlocksPropsOptions {
334
+ \treturn buildInnerBlocksPropsOptions( getRootInnerBlocksConfig() );
335
+ }
336
+
337
+ export function getChildSpec( blockName: string ): CompoundChildSpec | undefined {
338
+ \treturn COMPOUND_CHILD_SPECS.find( ( spec ) => spec.blockName === blockName );
339
+ }
340
+
341
+ export function getChildTemplate(
342
+ \tblockName: string
343
+ ): BlockTemplate | undefined {
344
+ \tconst childSpec = getChildSpec( blockName );
345
+ \tif ( ! childSpec ) {
346
+ \t\treturn undefined;
347
+ \t}
348
+
349
+ \tconst nestedTemplate = buildNestedTemplateForKey( childSpec.key );
350
+ \tif ( nestedTemplate.length > 0 ) {
351
+ \t\treturn nestedTemplate;
352
+ \t}
353
+
354
+ \treturn childSpec.container ? [] : undefined;
355
+ }
356
+
357
+ export function getChildInnerBlocksConfig(
358
+ \tblockName: string
359
+ ): CompoundInnerBlocksConfig | undefined {
360
+ \tconst childSpec = getChildSpec( blockName );
361
+ \tif ( ! childSpec ) {
362
+ \t\treturn undefined;
363
+ \t}
364
+
365
+ \tconst template = getChildTemplate( blockName );
366
+
367
+ \tif ( ! childSpec.container && ! template ) {
368
+ \t\treturn undefined;
369
+ \t}
370
+
371
+ \treturn {
372
+ \t\t...BASE_INNER_BLOCKS_CONFIG,
373
+ \t\tdefaultBlock: buildDefaultBlockEntry( template ),
374
+ \t\ttemplate,
375
+ \t};
376
+ }
377
+
378
+ export function getChildInnerBlocksPropsOptions(
379
+ \tblockName: string
380
+ ): CompoundInnerBlocksPropsOptions | undefined {
381
+ \tconst config = getChildInnerBlocksConfig( blockName );
382
+ \tif ( ! config ) {
383
+ \t\treturn undefined;
384
+ \t}
385
+
386
+ \treturn buildInnerBlocksPropsOptions( config );
387
+ }
388
+
389
+ export function hasNestedChildBlocks( blockName: string ): boolean {
390
+ \tconst childSpec = getChildSpec( blockName );
391
+ \tif ( ! childSpec ) {
392
+ \t\treturn false;
393
+ \t}
394
+
395
+ \treturn childSpec.container || buildNestedTemplateForKey( childSpec.key ).length > 0;
396
+ }
397
+
398
+ export function isRootCompoundChildBlock( blockName: string ): boolean {
399
+ \tconst childSpec = getChildSpec( blockName );
400
+ \treturn childSpec?.placement === 'root';
401
+ }
402
+
403
+ export { ROOT_BLOCK_NAME };
227
404
  `;
@@ -1,4 +1,4 @@
1
- export declare const COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tInspectorControls,\n\tInnerBlocks,\n\tRichText,\n\tuseBlockProps,\n} from '@wordpress/block-editor';\nimport {\n\tNotice,\n\tPanelBody,\n\tTextControl,\n\tToggleControl,\n} from '@wordpress/components';\n\nimport {\n\tALLOWED_CHILD_BLOCKS,\n\tDEFAULT_CHILD_TEMPLATE,\n} from './children';\nimport { useTypiaValidation } from './hooks';\nimport type { {{pascalCase}}Attributes } from './types';\nimport {\n\tcreateAttributeUpdater,\n\tvalidate{{pascalCase}}Attributes,\n} from './validators';\n\ntype EditProps = BlockEditProps< {{pascalCase}}Attributes >;\n\nexport default function Edit( {\n\tattributes,\n\tsetAttributes,\n}: EditProps ) {\n\tconst { errorMessages, isValid } = useTypiaValidation(\n\t\tattributes,\n\t\tvalidate{{pascalCase}}Attributes\n\t);\n\tconst updateAttribute = createAttributeUpdater( attributes, setAttributes );\n\tconst blockProps = useBlockProps( {\n\t\tclassName: '{{cssClassName}}',\n\t} );\n\n\treturn (\n\t\t<>\n\t\t\t<InspectorControls>\n\t\t\t\t<PanelBody title={ __( 'Compound Settings', '{{textDomain}}' ) }>\n\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\tlabel={ __( 'Show dividers between items', '{{textDomain}}' ) }\n\t\t\t\t\t\tchecked={ attributes.showDividers ?? true }\n\t\t\t\t\t\tonChange={ ( value ) => updateAttribute( 'showDividers', value ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\tlabel={ __( 'Show persisted count', '{{textDomain}}' ) }\n\t\t\t\t\t\tchecked={ attributes.showCount ?? true }\n\t\t\t\t\t\tonChange={ ( value ) => updateAttribute( 'showCount', value ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<TextControl\n\t\t\t\t\t\tlabel={ __( 'Button label', '{{textDomain}}' ) }\n\t\t\t\t\t\tvalue={ attributes.buttonLabel ?? 'Persist Count' }\n\t\t\t\t\t\tonChange={ ( buttonLabel ) => updateAttribute( 'buttonLabel', buttonLabel ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<TextControl\n\t\t\t\t\t\tlabel={ __( 'Resource key', '{{textDomain}}' ) }\n\t\t\t\t\t\tvalue={ attributes.resourceKey ?? '' }\n\t\t\t\t\t\tonChange={ ( resourceKey ) => updateAttribute( 'resourceKey', resourceKey ) }\n\t\t\t\t\t\thelp={ __( 'Stable key used by the persisted counter endpoint.', '{{textDomain}}' ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<Notice status=\"info\" isDismissible={ false }>\n\t\t\t\t\t\t{ __( 'Storage mode: {{dataStorageMode}}', '{{textDomain}}' ) }\n\t\t\t\t\t</Notice>\n\t\t\t\t\t<Notice status=\"info\" isDismissible={ false }>\n\t\t\t\t\t\t{ __( 'Persistence policy: {{persistencePolicy}}', '{{textDomain}}' ) }\n\t\t\t\t\t</Notice>\n\t\t\t\t</PanelBody>\n\t\t\t\t{ ! isValid && (\n\t\t\t\t\t<PanelBody title={ __( 'Validation Errors', '{{textDomain}}' ) } initialOpen>\n\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => (\n\t\t\t\t\t\t\t<Notice key={ index } status=\"error\" isDismissible={ false }>\n\t\t\t\t\t\t\t\t{ error }\n\t\t\t\t\t\t\t</Notice>\n\t\t\t\t\t\t) ) }\n\t\t\t\t\t</PanelBody>\n\t\t\t\t) }\n\t\t\t</InspectorControls>\n\t\t\t<div { ...blockProps }>\n\t\t\t\t<RichText\n\t\t\t\t\ttagName=\"h3\"\n\t\t\t\t\tclassName=\"{{cssClassName}}__heading\"\n\t\t\t\t\tvalue={ attributes.heading }\n\t\t\t\t\tonChange={ ( heading ) => updateAttribute( 'heading', heading ) }\n\t\t\t\t\tplaceholder={ __( {{titleJson}}, '{{textDomain}}' ) }\n\t\t\t\t/>\n\t\t\t\t<RichText\n\t\t\t\t\ttagName=\"p\"\n\t\t\t\t\tclassName=\"{{cssClassName}}__intro\"\n\t\t\t\t\tvalue={ attributes.intro ?? '' }\n\t\t\t\t\tonChange={ ( intro ) => updateAttribute( 'intro', intro ) }\n\t\t\t\t\tplaceholder={ __(\n\t\t\t\t\t\t'Add and reorder internal items inside this compound block.',\n\t\t\t\t\t\t'{{textDomain}}'\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t\t{ ! isValid && (\n\t\t\t\t\t<Notice status=\"error\" isDismissible={ false }>\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => <li key={ index }>{ error }</li> ) }\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</Notice>\n\t\t\t\t) }\n\t\t\t\t<p className=\"{{cssClassName}}__meta\">\n\t\t\t\t\t{ __( 'Resource key:', '{{textDomain}}' ) } { attributes.resourceKey || '\u2014' }\n\t\t\t\t</p>\n\t\t\t\t<div className=\"{{cssClassName}}__items\">\n\t\t\t\t\t<InnerBlocks\n\t\t\t\t\t\tallowedBlocks={ ALLOWED_CHILD_BLOCKS }\n\t\t\t\t\t\trenderAppender={ InnerBlocks.ButtonBlockAppender }\n\t\t\t\t\t\ttemplate={ DEFAULT_CHILD_TEMPLATE }\n\t\t\t\t\t\ttemplateLock={ false }\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n";
1
+ export declare const COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tInspectorControls,\n\tInnerBlocks,\n\tRichText,\n\tuseBlockProps,\n} from '@wordpress/block-editor';\nimport {\n\tNotice,\n\tPanelBody,\n\tTextControl,\n\tToggleControl,\n} from '@wordpress/components';\n\nimport {\n\tgetRootInnerBlocksPropsOptions,\n} from './children';\nimport { useTypiaValidation } from './hooks';\nimport type { {{pascalCase}}Attributes } from './types';\nimport {\n\tcreateAttributeUpdater,\n\tvalidate{{pascalCase}}Attributes,\n} from './validators';\n\ntype EditProps = BlockEditProps< {{pascalCase}}Attributes >;\ntype CompoundInnerBlocksProps = Parameters< typeof InnerBlocks >[ 0 ] & {\n\tdefaultBlock?: [ string, Record< string, unknown > ];\n\tdirectInsert?: boolean;\n};\n\nconst TypedInnerBlocks = InnerBlocks as unknown as (\n\tprops: CompoundInnerBlocksProps\n) => ReturnType< typeof InnerBlocks >;\n\nexport default function Edit( {\n\tattributes,\n\tsetAttributes,\n}: EditProps ) {\n\tconst { errorMessages, isValid } = useTypiaValidation(\n\t\tattributes,\n\t\tvalidate{{pascalCase}}Attributes\n\t);\n\tconst updateAttribute = createAttributeUpdater( attributes, setAttributes );\n\tconst blockProps = useBlockProps( {\n\t\tclassName: '{{cssClassName}}',\n\t} );\n\tconst rootInnerBlocksPropsOptions = getRootInnerBlocksPropsOptions();\n\n\treturn (\n\t\t<>\n\t\t\t<InspectorControls>\n\t\t\t\t<PanelBody title={ __( 'Compound Settings', '{{textDomain}}' ) }>\n\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\tlabel={ __( 'Show dividers between items', '{{textDomain}}' ) }\n\t\t\t\t\t\tchecked={ attributes.showDividers ?? true }\n\t\t\t\t\t\tonChange={ ( value ) => updateAttribute( 'showDividers', value ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<ToggleControl\n\t\t\t\t\t\tlabel={ __( 'Show persisted count', '{{textDomain}}' ) }\n\t\t\t\t\t\tchecked={ attributes.showCount ?? true }\n\t\t\t\t\t\tonChange={ ( value ) => updateAttribute( 'showCount', value ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<TextControl\n\t\t\t\t\t\tlabel={ __( 'Button label', '{{textDomain}}' ) }\n\t\t\t\t\t\tvalue={ attributes.buttonLabel ?? 'Persist Count' }\n\t\t\t\t\t\tonChange={ ( buttonLabel ) => updateAttribute( 'buttonLabel', buttonLabel ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<TextControl\n\t\t\t\t\t\tlabel={ __( 'Resource key', '{{textDomain}}' ) }\n\t\t\t\t\t\tvalue={ attributes.resourceKey ?? '' }\n\t\t\t\t\t\tonChange={ ( resourceKey ) => updateAttribute( 'resourceKey', resourceKey ) }\n\t\t\t\t\t\thelp={ __( 'Stable key used by the persisted counter endpoint.', '{{textDomain}}' ) }\n\t\t\t\t\t/>\n\t\t\t\t\t<Notice status=\"info\" isDismissible={ false }>\n\t\t\t\t\t\t{ __( 'Storage mode: {{dataStorageMode}}', '{{textDomain}}' ) }\n\t\t\t\t\t</Notice>\n\t\t\t\t\t<Notice status=\"info\" isDismissible={ false }>\n\t\t\t\t\t\t{ __( 'Persistence policy: {{persistencePolicy}}', '{{textDomain}}' ) }\n\t\t\t\t\t</Notice>\n\t\t\t\t</PanelBody>\n\t\t\t\t{ ! isValid && (\n\t\t\t\t\t<PanelBody title={ __( 'Validation Errors', '{{textDomain}}' ) } initialOpen>\n\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => (\n\t\t\t\t\t\t\t<Notice key={ index } status=\"error\" isDismissible={ false }>\n\t\t\t\t\t\t\t\t{ error }\n\t\t\t\t\t\t\t</Notice>\n\t\t\t\t\t\t) ) }\n\t\t\t\t\t</PanelBody>\n\t\t\t\t) }\n\t\t\t</InspectorControls>\n\t\t\t<div { ...blockProps }>\n\t\t\t\t<RichText\n\t\t\t\t\ttagName=\"h3\"\n\t\t\t\t\tclassName=\"{{cssClassName}}__heading\"\n\t\t\t\t\tvalue={ attributes.heading }\n\t\t\t\t\tonChange={ ( heading ) => updateAttribute( 'heading', heading ) }\n\t\t\t\t\tplaceholder={ __( {{titleJson}}, '{{textDomain}}' ) }\n\t\t\t\t/>\n\t\t\t\t<RichText\n\t\t\t\t\ttagName=\"p\"\n\t\t\t\t\tclassName=\"{{cssClassName}}__intro\"\n\t\t\t\t\tvalue={ attributes.intro ?? '' }\n\t\t\t\t\tonChange={ ( intro ) => updateAttribute( 'intro', intro ) }\n\t\t\t\t\tplaceholder={ __(\n\t\t\t\t\t\t'Add and reorder internal items inside this compound block.',\n\t\t\t\t\t\t'{{textDomain}}'\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t\t{ ! isValid && (\n\t\t\t\t\t<Notice status=\"error\" isDismissible={ false }>\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => <li key={ index }>{ error }</li> ) }\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</Notice>\n\t\t\t\t) }\n\t\t\t\t<p className=\"{{cssClassName}}__meta\">\n\t\t\t\t\t{ __( 'Resource key:', '{{textDomain}}' ) } { attributes.resourceKey || '\u2014' }\n\t\t\t\t</p>\n\t\t\t\t<div className=\"{{cssClassName}}__items\">\n\t\t\t\t\t<TypedInnerBlocks { ...rootInnerBlocksPropsOptions } />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</>\n\t);\n}\n";
2
2
  export declare const COMPOUND_PERSISTENCE_PARENT_SAVE_TEMPLATE = "export default function Save() {\n\treturn null;\n}\n";
3
3
  export declare const COMPOUND_PERSISTENCE_PARENT_VALIDATORS_TEMPLATE = "import typia from 'typia';\nimport currentManifest from './manifest-defaults-document';\nimport type {\n\t{{pascalCase}}Attributes,\n\t{{pascalCase}}ValidationResult,\n} from './types';\nimport { generateResourceKey } from '@wp-typia/block-runtime/identifiers';\nimport { createTemplateValidatorToolkit } from '../../validator-toolkit';\n\nconst scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {\n\tassert: typia.createAssert< {{pascalCase}}Attributes >(),\n\tclone: typia.misc.createClone< {{pascalCase}}Attributes >() as (\n\t\tvalue: {{pascalCase}}Attributes,\n\t) => {{pascalCase}}Attributes,\n\tis: typia.createIs< {{pascalCase}}Attributes >(),\n\tmanifest: currentManifest,\n\tprune: typia.misc.createPrune< {{pascalCase}}Attributes >(),\n\trandom: typia.createRandom< {{pascalCase}}Attributes >() as (\n\t\t...args: unknown[]\n\t) => {{pascalCase}}Attributes,\n\tfinalize: ( normalized ) => ( {\n\t\t...normalized,\n\t\tresourceKey:\n\t\t\tnormalized.resourceKey && normalized.resourceKey.length > 0\n\t\t\t\t? normalized.resourceKey\n\t\t\t\t: generateResourceKey( '{{slugKebabCase}}' ),\n\t} ),\n\tvalidate: typia.createValidate< {{pascalCase}}Attributes >(),\n} );\n\nexport const validators = scaffoldValidators.validators;\n\nexport const validate{{pascalCase}}Attributes =\n\tscaffoldValidators.validateAttributes as (\n\t\tattributes: unknown\n\t) => {{pascalCase}}ValidationResult;\n\nexport const sanitize{{pascalCase}}Attributes =\n\tscaffoldValidators.sanitizeAttributes as (\n\t\tattributes: Partial< {{pascalCase}}Attributes >\n\t) => {{pascalCase}}Attributes;\n\nexport const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;\n";
4
4
  export declare const COMPOUND_PERSISTENCE_PARENT_INTERACTIVITY_TEMPLATE = "import { getContext, store } from '@wordpress/interactivity';\nimport { generatePublicWriteRequestId } from '@wp-typia/block-runtime/identifiers';\n\nimport { fetchBootstrap, fetchState, writeState } from './api';\nimport type {\n\t{{pascalCase}}ClientState,\n\t{{pascalCase}}Context,\n\t{{pascalCase}}State,\n} from './types';\n\nfunction hasExpiredPublicWriteToken(\n\texpiresAt?: number\n): boolean {\n\treturn (\n\t\ttypeof expiresAt === 'number' &&\n\t\texpiresAt > 0 &&\n\t\tDate.now() >= expiresAt * 1000\n\t);\n}\n\nfunction getWriteBlockedMessage(\n\tcontext: {{pascalCase}}Context\n): string {\n\treturn context.persistencePolicy === 'authenticated'\n\t\t? 'Sign in to persist this counter.'\n\t\t: 'Public writes are temporarily unavailable.';\n}\n\nconst BOOTSTRAP_MAX_ATTEMPTS = 3;\nconst BOOTSTRAP_RETRY_DELAYS_MS = [ 250, 500 ];\n\nasync function waitForBootstrapRetry( delayMs: number ): Promise< void > {\n\tawait new Promise( ( resolve ) => {\n\t\tsetTimeout( resolve, delayMs );\n\t} );\n}\n\nfunction getClientState(\n\tcontext: {{pascalCase}}Context\n): {{pascalCase}}ClientState {\n\tif ( context.client ) {\n\t\treturn context.client;\n\t}\n\n\tcontext.client = {\n\t\tbootstrapError: '',\n\t\twriteExpiry: 0,\n\t\twriteNonce: '',\n\t\twriteToken: '',\n\t};\n\n\treturn context.client;\n}\n\nfunction clearBootstrapError(\n\tcontext: {{pascalCase}}Context,\n\tclientState: {{pascalCase}}ClientState\n): void {\n\tif ( context.error === clientState.bootstrapError ) {\n\t\tcontext.error = '';\n\t}\n\tclientState.bootstrapError = '';\n}\n\nfunction setBootstrapError(\n\tcontext: {{pascalCase}}Context,\n\tclientState: {{pascalCase}}ClientState,\n\tmessage: string\n): void {\n\tclientState.bootstrapError = message;\n\tcontext.error = message;\n}\n\nconst { actions, state } = store( '{{slugKebabCase}}', {\n\tstate: {\n\t\tisHydrated: false,\n\t} as {{pascalCase}}State,\n\n\tactions: {\n\t\tasync loadState() {\n\t\t\tconst context = getContext< {{pascalCase}}Context >();\n\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcontext.isLoading = true;\n\t\t\tcontext.error = '';\n\n\t\t\ttry {\n\t\t\t\tconst result = await fetchState( {\n\t\t\t\t\tpostId: context.postId,\n\t\t\t\t\tresourceKey: context.resourceKey,\n\t\t\t\t}, {\n\t\t\t\t\ttransportTarget: 'frontend',\n\t\t\t\t} );\n\t\t\t\tif ( ! result.isValid || ! result.data ) {\n\t\t\t\t\tcontext.error = result.errors[ 0 ]?.expected ?? 'Unable to load counter';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcontext.count = result.data.count;\n\t\t\t} catch ( error ) {\n\t\t\t\tcontext.error =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown loading error';\n\t\t\t} finally {\n\t\t\t\tcontext.isLoading = false;\n\t\t\t}\n\t\t},\n\t\tasync loadBootstrap() {\n\t\t\tconst context = getContext< {{pascalCase}}Context >();\n\t\t\tconst clientState = getClientState( context );\n\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {\n\t\t\t\tcontext.bootstrapReady = true;\n\t\t\t\tcontext.canWrite = false;\n\t\t\t\tclientState.bootstrapError = '';\n\t\t\t\tclientState.writeExpiry = 0;\n\t\t\t\tclientState.writeNonce = '';\n\t\t\t\tclientState.writeToken = '';\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcontext.isBootstrapping = true;\n\n\t\t\tlet bootstrapSucceeded = false;\n\t\t\tlet lastBootstrapError =\n\t\t\t\t'Unable to initialize write access';\n\t\t\tconst includePublicWriteCredentials = {{isPublicPersistencePolicy}};\n\t\t\tconst includeRestNonce = {{isAuthenticatedPersistencePolicy}};\n\n\t\t\tfor ( let attempt = 1; attempt <= BOOTSTRAP_MAX_ATTEMPTS; attempt += 1 ) {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await fetchBootstrap( {\n\t\t\t\t\t\tpostId: context.postId,\n\t\t\t\t\t\tresourceKey: context.resourceKey,\n\t\t\t\t\t}, {\n\t\t\t\t\t\ttransportTarget: 'frontend',\n\t\t\t\t\t} );\n\t\t\t\t\tif ( ! result.isValid || ! result.data ) {\n\t\t\t\t\t\tlastBootstrapError =\n\t\t\t\t\t\t\tresult.errors[ 0 ]?.expected ??\n\t\t\t\t\t\t\t'Unable to initialize write access';\n\t\t\t\t\t\tif ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {\n\t\t\t\t\t\t\tawait waitForBootstrapRetry(\n\t\t\t\t\t\t\t\tBOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tclientState.writeExpiry =\n\t\t\t\t\t\tincludePublicWriteCredentials &&\n\t\t\t\t\t\t'publicWriteExpiresAt' in result.data &&\n\t\t\t\t\t\ttypeof result.data.publicWriteExpiresAt === 'number' &&\n\t\t\t\t\t\tresult.data.publicWriteExpiresAt > 0\n\t\t\t\t\t\t\t? result.data.publicWriteExpiresAt\n\t\t\t\t\t\t\t: 0;\n\t\t\t\t\tclientState.writeToken =\n\t\t\t\t\t\tincludePublicWriteCredentials &&\n\t\t\t\t\t\t'publicWriteToken' in result.data &&\n\t\t\t\t\t\ttypeof result.data.publicWriteToken === 'string' &&\n\t\t\t\t\t\tresult.data.publicWriteToken.length > 0\n\t\t\t\t\t\t\t? result.data.publicWriteToken\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\tclientState.writeNonce =\n\t\t\t\t\t\tincludeRestNonce &&\n\t\t\t\t\t\t'restNonce' in result.data &&\n\t\t\t\t\t\ttypeof result.data.restNonce === 'string' &&\n\t\t\t\t\t\tresult.data.restNonce.length > 0\n\t\t\t\t\t\t\t? result.data.restNonce\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\tcontext.bootstrapReady = true;\n\t\t\t\t\tcontext.canWrite =\n\t\t\t\t\t\tresult.data.canWrite === true &&\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tcontext.persistencePolicy === 'authenticated'\n\t\t\t\t\t\t\t\t? clientState.writeNonce.length > 0\n\t\t\t\t\t\t\t\t: clientState.writeToken.length > 0 &&\n\t\t\t\t\t\t\t\t\t! hasExpiredPublicWriteToken( clientState.writeExpiry )\n\t\t\t\t\t\t);\n\t\t\t\t\tclearBootstrapError( context, clientState );\n\t\t\t\t\tbootstrapSucceeded = true;\n\t\t\t\t\tbreak;\n\t\t\t\t} catch ( error ) {\n\t\t\t\t\tlastBootstrapError =\n\t\t\t\t\t\terror instanceof Error ? error.message : 'Unknown bootstrap error';\n\t\t\t\t\tif ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {\n\t\t\t\t\t\tawait waitForBootstrapRetry(\n\t\t\t\t\t\t\tBOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( ! bootstrapSucceeded ) {\n\t\t\t\tcontext.bootstrapReady = false;\n\t\t\t\tcontext.canWrite = false;\n\t\t\t\tclientState.writeExpiry = 0;\n\t\t\t\tclientState.writeNonce = '';\n\t\t\t\tclientState.writeToken = '';\n\t\t\t\tsetBootstrapError( context, clientState, lastBootstrapError );\n\t\t\t}\n\t\t\tcontext.isBootstrapping = false;\n\t\t},\n\t\tasync increment() {\n\t\t\tconst context = getContext< {{pascalCase}}Context >();\n\t\t\tconst clientState = getClientState( context );\n\t\t\tif ( context.postId <= 0 || ! context.resourceKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( ! context.bootstrapReady ) {\n\t\t\t\tawait actions.loadBootstrap();\n\t\t\t}\n\t\t\tif ( ! context.bootstrapReady ) {\n\t\t\t\tcontext.error = 'Write access is still initializing.';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcontext.persistencePolicy === 'public' &&\n\t\t\t\thasExpiredPublicWriteToken( clientState.writeExpiry )\n\t\t\t) {\n\t\t\t\tawait actions.loadBootstrap();\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcontext.persistencePolicy === 'public' &&\n\t\t\t\thasExpiredPublicWriteToken( clientState.writeExpiry )\n\t\t\t) {\n\t\t\t\tcontext.canWrite = false;\n\t\t\t\tcontext.error = getWriteBlockedMessage( context );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( ! context.canWrite ) {\n\t\t\t\tcontext.error = getWriteBlockedMessage( context );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcontext.isSaving = true;\n\t\t\tcontext.error = '';\n\n\t\t\ttry {\n\t\t\t\tconst result = await writeState( {\n\t\t\t\t\tdelta: 1,\n\t\t\t\t\tpostId: context.postId,\n\t\t\t\t\tpublicWriteRequestId:\n\t\t\t\t\t\tcontext.persistencePolicy === 'public'\n\t\t\t\t\t\t\t? generatePublicWriteRequestId()\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\tpublicWriteToken:\n\t\t\t\t\t\tcontext.persistencePolicy === 'public' &&\n\t\t\t\t\t\tclientState.writeToken.length > 0\n\t\t\t\t\t\t\t? clientState.writeToken\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\tresourceKey: context.resourceKey,\n\t\t\t\t}, {\n\t\t\t\t\trestNonce:\n\t\t\t\t\t\tclientState.writeNonce.length > 0\n\t\t\t\t\t\t\t? clientState.writeNonce\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\ttransportTarget: 'frontend',\n\t\t\t\t} );\n\t\t\t\tif ( ! result.isValid || ! result.data ) {\n\t\t\t\t\tcontext.error = result.errors[ 0 ]?.expected ?? 'Unable to update counter';\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcontext.count = result.data.count;\n\t\t\t\tcontext.storage = result.data.storage;\n\t\t\t} catch ( error ) {\n\t\t\t\tcontext.error =\n\t\t\t\t\terror instanceof Error ? error.message : 'Unknown update error';\n\t\t\t} finally {\n\t\t\t\tcontext.isSaving = false;\n\t\t\t}\n\t\t},\n\t},\n\n\tcallbacks: {\n\t\tinit() {\n\t\t\tconst context = getContext< {{pascalCase}}Context >();\n\t\t\tcontext.client = {\n\t\t\t\tbootstrapError: '',\n\t\t\t\twriteExpiry: 0,\n\t\t\t\twriteNonce: '',\n\t\t\t\twriteToken: '',\n\t\t\t};\n\t\t\tcontext.bootstrapReady = false;\n\t\t\tcontext.canWrite = false;\n\t\t\tcontext.count = 0;\n\t\t\tcontext.error = '';\n\t\t\tcontext.isBootstrapping = false;\n\t\t\tcontext.isLoading = false;\n\t\t\tcontext.isSaving = false;\n\t\t},\n\t\tmounted() {\n\t\t\tstate.isHydrated = true;\n\t\t\tif ( typeof document !== 'undefined' ) {\n\t\t\t\tdocument.documentElement.dataset[ '{{slugCamelCase}}Hydrated' ] = 'true';\n\t\t\t}\n\t\t\tvoid Promise.allSettled( [\n\t\t\t\tactions.loadState(),\n\t\t\t\tactions.loadBootstrap(),\n\t\t\t] );\n\t\t},\n\t},\n} );\n";
@@ -14,8 +14,7 @@ import {
14
14
  } from '@wordpress/components';
15
15
 
16
16
  import {
17
- \tALLOWED_CHILD_BLOCKS,
18
- \tDEFAULT_CHILD_TEMPLATE,
17
+ \tgetRootInnerBlocksPropsOptions,
19
18
  } from './children';
20
19
  import { useTypiaValidation } from './hooks';
21
20
  import type { {{pascalCase}}Attributes } from './types';
@@ -25,6 +24,14 @@ import {
25
24
  } from './validators';
26
25
 
27
26
  type EditProps = BlockEditProps< {{pascalCase}}Attributes >;
27
+ type CompoundInnerBlocksProps = Parameters< typeof InnerBlocks >[ 0 ] & {
28
+ \tdefaultBlock?: [ string, Record< string, unknown > ];
29
+ \tdirectInsert?: boolean;
30
+ };
31
+
32
+ const TypedInnerBlocks = InnerBlocks as unknown as (
33
+ \tprops: CompoundInnerBlocksProps
34
+ ) => ReturnType< typeof InnerBlocks >;
28
35
 
29
36
  export default function Edit( {
30
37
  \tattributes,
@@ -38,6 +45,7 @@ export default function Edit( {
38
45
  \tconst blockProps = useBlockProps( {
39
46
  \t\tclassName: '{{cssClassName}}',
40
47
  \t} );
48
+ \tconst rootInnerBlocksPropsOptions = getRootInnerBlocksPropsOptions();
41
49
 
42
50
  \treturn (
43
51
  \t\t<>
@@ -110,12 +118,7 @@ export default function Edit( {
110
118
  \t\t\t\t\t{ __( 'Resource key:', '{{textDomain}}' ) } { attributes.resourceKey || '—' }
111
119
  \t\t\t\t</p>
112
120
  \t\t\t\t<div className="{{cssClassName}}__items">
113
- \t\t\t\t\t<InnerBlocks
114
- \t\t\t\t\t\tallowedBlocks={ ALLOWED_CHILD_BLOCKS }
115
- \t\t\t\t\t\trenderAppender={ InnerBlocks.ButtonBlockAppender }
116
- \t\t\t\t\t\ttemplate={ DEFAULT_CHILD_TEMPLATE }
117
- \t\t\t\t\t\ttemplateLock={ false }
118
- \t\t\t\t\t/>
121
+ \t\t\t\t\t<TypedInnerBlocks { ...rootInnerBlocksPropsOptions } />
119
122
  \t\t\t\t</div>
120
123
  \t\t\t</div>
121
124
  \t\t</>