@wp-typia/project-tools 0.19.1 → 0.19.3

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 (39) hide show
  1. package/dist/runtime/built-in-block-non-ts-artifacts.js +1 -1039
  2. package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +30 -0
  3. package/dist/runtime/built-in-block-non-ts-family-artifacts.js +1035 -0
  4. package/dist/runtime/built-in-block-non-ts-render-utils.d.ts +27 -0
  5. package/dist/runtime/built-in-block-non-ts-render-utils.js +51 -0
  6. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +3 -0
  7. package/dist/runtime/cli-add-workspace-rest-anchors.js +188 -0
  8. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +7 -0
  9. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +379 -0
  10. package/dist/runtime/cli-add-workspace-rest.js +5 -564
  11. package/dist/runtime/cli-diagnostics.d.ts +2 -0
  12. package/dist/runtime/cli-diagnostics.js +10 -1
  13. package/dist/runtime/cli-help.js +3 -0
  14. package/dist/runtime/cli-init.d.ts +49 -0
  15. package/dist/runtime/cli-init.js +354 -0
  16. package/dist/runtime/cli-scaffold.d.ts +1 -0
  17. package/dist/runtime/cli-scaffold.js +5 -1
  18. package/dist/runtime/cli-templates.js +36 -6
  19. package/dist/runtime/external-template-guards.d.ts +31 -0
  20. package/dist/runtime/external-template-guards.js +132 -0
  21. package/dist/runtime/package-managers.d.ts +8 -0
  22. package/dist/runtime/package-managers.js +13 -0
  23. package/dist/runtime/package-versions.d.ts +8 -0
  24. package/dist/runtime/package-versions.js +84 -19
  25. package/dist/runtime/scaffold-documents.js +19 -1
  26. package/dist/runtime/scaffold-onboarding.d.ts +4 -0
  27. package/dist/runtime/scaffold-onboarding.js +25 -1
  28. package/dist/runtime/scaffold.js +2 -5
  29. package/dist/runtime/template-registry.d.ts +23 -1
  30. package/dist/runtime/template-registry.js +37 -3
  31. package/dist/runtime/template-source-external.js +9 -3
  32. package/dist/runtime/template-source-remote.js +5 -0
  33. package/dist/runtime/template-source-seeds.js +40 -6
  34. package/package.json +7 -2
  35. package/templates/_shared/base/package.json.mustache +0 -1
  36. package/templates/_shared/compound/core/package.json.mustache +0 -1
  37. package/templates/_shared/compound/persistence/package.json.mustache +0 -1
  38. package/templates/_shared/persistence/core/package.json.mustache +0 -1
  39. package/templates/interactivity/package.json.mustache +0 -1
@@ -1,1042 +1,4 @@
1
- import { renderMustacheTemplateString } from "./template-render.js";
2
- const BASIC_STYLE_TEMPLATE = `/**
3
- * {{title}} Block Styles
4
- */
5
-
6
- .{{cssClassName}} {
7
- padding: 20px;
8
- border: 1px solid #ddd;
9
- border-radius: 4px;
10
- background-color: #fff;
11
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
12
-
13
- &.is-hidden {
14
- display: none;
15
- }
16
-
17
- &__content {
18
- font-size: 16px;
19
- line-height: 1.6;
20
- color: #333;
21
-
22
- // Alignment styles
23
- &[data-align="center"] {
24
- text-align: center;
25
- }
26
-
27
- &[data-align="right"] {
28
- text-align: right;
29
- }
30
-
31
- &[data-align="justify"] {
32
- text-align: justify;
33
- }
34
- }
35
-
36
- // Hover state
37
- &:hover {
38
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
39
- transition: box-shadow 0.2s ease;
40
- }
41
- }
42
- `;
43
- const BASIC_EDITOR_STYLE_TEMPLATE = `/**
44
- * {{title}} Block Editor Styles
45
- */
46
-
47
- .{{cssClassName}} {
48
- outline: 1px dashed #ddd;
49
- outline-offset: -1px;
50
- }
51
- `;
52
- const BASIC_RENDER_TEMPLATE = `<?php
53
- /**
54
- * Optional server render placeholder for {{title}}.
55
- *
56
- * The basic scaffold stays static by default. Keep \`src/save.tsx\` as the
57
- * canonical frontend output unless you intentionally convert this block into a
58
- * dynamic render path and add \`render\` to \`block.json\`.
59
- *
60
- * @package {{slug}}
61
- */
62
-
63
- if ( ! defined( 'ABSPATH' ) ) {
64
- exit;
65
- }
66
-
67
- ?>
68
- <div class="{{cssClassName}}__server-placeholder" hidden>
69
- <?php esc_html_e( 'Server render placeholder.', '{{textDomain}}' ); ?>
70
- </div>
71
- `;
72
- const INTERACTIVITY_STYLE_TEMPLATE = `.{{cssClassName}} {
73
- position: relative;
74
- padding: 1rem;
75
- border: 1px solid #dcdcde;
76
- border-radius: 0.75rem;
77
- background: #fff;
78
-
79
- &__content {
80
- display: grid;
81
- gap: 0.75rem;
82
- }
83
-
84
- &__counter {
85
- display: inline-flex;
86
- gap: 0.35rem;
87
- align-items: center;
88
- font-size: 0.9rem;
89
- font-weight: 600;
90
- }
91
-
92
- &__progress {
93
- width: 100%;
94
- height: 0.5rem;
95
- overflow: hidden;
96
- background: #f0f0f1;
97
- border-radius: 999px;
98
- }
99
-
100
- &__progress-bar {
101
- height: 100%;
102
- background: #3858e9;
103
- transition: width 0.2s ease;
104
- }
105
-
106
- &__animation {
107
- min-height: 1.5rem;
108
- font-size: 0.85rem;
109
- color: #3858e9;
110
- opacity: 0;
111
- transition: opacity 0.2s ease;
112
-
113
- &.is-active {
114
- opacity: 1;
115
- }
116
- }
117
-
118
- &__completion {
119
- font-weight: 700;
120
- color: #06752d;
121
- }
122
-
123
- &__reset {
124
- align-self: start;
125
- padding: 0.4rem 0.7rem;
126
- border: 1px solid #dcdcde;
127
- border-radius: 999px;
128
- background: transparent;
129
- cursor: pointer;
130
- }
131
- }
132
- `;
133
- const INTERACTIVITY_EDITOR_STYLE_TEMPLATE = `/**
134
- * {{title}} Block Editor Styles
135
- */
136
-
137
- .{{cssClassName}} {
138
- outline: 1px dashed #ddd;
139
- outline-offset: -1px;
140
- }
141
- `;
142
- const PERSISTENCE_STYLE_TEMPLATE = `.{{cssClassName}} {
143
- border: 1px solid #dcdcde;
144
- border-radius: 12px;
145
- padding: 16px;
146
- background: #fff;
147
-
148
- &__meta {
149
- color: #50575e;
150
- font-size: 13px;
151
- margin: 8px 0 0;
152
- }
153
- }
154
-
155
- .{{frontendCssClassName}} {
156
- display: grid;
157
- gap: 12px;
158
- border: 1px solid #dcdcde;
159
- border-radius: 12px;
160
- padding: 16px;
161
- background: #f6f7f7;
162
-
163
- &__count {
164
- display: inline-flex;
165
- min-width: 3rem;
166
- justify-content: center;
167
- font-weight: 700;
168
- }
169
-
170
- &__notice,
171
- &__error {
172
- margin: 0;
173
- font-size: 13px;
174
- }
175
-
176
- &__notice {
177
- color: #50575e;
178
- }
179
-
180
- &__error {
181
- color: #b32d2e;
182
- }
183
-
184
- button {
185
- width: fit-content;
186
- }
187
- }
188
- `;
189
- const PERSISTENCE_RENDER_TEMPLATE = `<?php
190
- /**
191
- * Dynamic render entry for the {{title}} block.
192
- *
193
- * @package {{pascalCase}}
194
- */
195
-
196
- if ( ! defined( 'ABSPATH' ) ) {
197
- exit;
198
- }
199
-
200
- $validator_path = __DIR__ . '/typia-validator.php';
201
- if ( ! file_exists( $validator_path ) ) {
202
- return '';
203
- }
204
-
205
- $validator = require $validator_path;
206
- if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
207
- return '';
208
- }
209
-
210
- $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
211
- $validation = $validator->validate( $normalized );
212
- $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
213
-
214
- if ( empty( $validation['valid'] ) || '' === $resource_key ) {
215
- return '';
216
- }
217
-
218
- $alignment = isset( $normalized['alignment'] ) ? (string) $normalized['alignment'] : 'left';
219
- $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
220
- $content = isset( $normalized['content'] ) ? (string) $normalized['content'] : '';
221
- $post_id = is_object( $block ) && isset( $block->context['postId'] )
222
- ? (int) $block->context['postId']
223
- : (int) get_queried_object_id();
224
- $storage_mode = '{{dataStorageMode}}';
225
- $persistence_policy = '{{persistencePolicy}}';
226
-
227
- {{phpPrefix}}_record_rendered_block_instance(
228
- (int) $post_id,
229
- '{{namespace}}/{{slugKebabCase}}',
230
- $resource_key
231
- );
232
-
233
- $notice_message = 'authenticated' === $persistence_policy
234
- ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
235
- : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
236
- $context = array(
237
- 'bootstrapReady' => false,
238
- 'buttonLabel' => $button_label,
239
- 'canWrite' => false,
240
- 'client' => array(
241
- 'writeExpiry' => 0,
242
- 'writeNonce' => '',
243
- 'writeToken' => '',
244
- ),
245
- 'count' => 0,
246
- 'error' => '',
247
- 'isBootstrapping' => false,
248
- 'isLoading' => false,
249
- 'isSaving' => false,
250
- 'isVisible' => ! empty( $normalized['isVisible'] ),
251
- 'persistencePolicy' => $persistence_policy,
252
- 'postId' => (int) $post_id,
253
- 'resourceKey' => $resource_key,
254
- 'storage' => $storage_mode,
255
- );
256
-
257
- $wrapper_attributes = get_block_wrapper_attributes(
258
- array(
259
- 'data-wp-context' => wp_json_encode( $context ),
260
- 'data-wp-interactive' => '{{slugKebabCase}}',
261
- 'data-wp-init' => 'callbacks.init',
262
- 'data-wp-run--mounted' => 'callbacks.mounted',
263
- )
264
- );
265
- ?>
266
-
267
- <div <?php echo $wrapper_attributes; ?>>
268
- <div class="{{frontendCssClassName}}">
269
- <p class="{{frontendCssClassName}}__content" style="<?php echo esc_attr( 'text-align:' . $alignment ); ?>">
270
- <?php echo esc_html( $content ); ?>
271
- </p>
272
- <p
273
- class="{{frontendCssClassName}}__notice"
274
- data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
275
- hidden
276
- >
277
- <?php echo esc_html( $notice_message ); ?>
278
- </p>
279
- <p
280
- class="{{frontendCssClassName}}__error"
281
- role="status"
282
- aria-live="polite"
283
- aria-atomic="true"
284
- data-wp-bind--hidden="!context.error"
285
- data-wp-text="context.error"
286
- hidden
287
- ></p>
288
- <?php if ( ! empty( $normalized['showCount'] ) ) : ?>
289
- <span
290
- class="{{frontendCssClassName}}__count"
291
- role="status"
292
- aria-live="polite"
293
- aria-atomic="true"
294
- data-wp-text="context.count"
295
- >
296
- 0
297
- </span>
298
- <?php endif; ?>
299
- <button
300
- type="button"
301
- disabled
302
- data-wp-bind--disabled="!context.canWrite"
303
- data-wp-on--click="actions.increment"
304
- >
305
- <?php echo esc_html( $button_label ); ?>
306
- </button>
307
- </div>
308
- </div>
309
- `;
310
- const PERSISTENCE_RENDER_TARGETS_TEMPLATE = `<?php
311
- /**
312
- * Alternate render target helpers for the {{title}} block.
313
- *
314
- * @package {{pascalCase}}
315
- */
316
-
317
- if ( ! defined( 'ABSPATH' ) ) {
318
- exit;
319
- }
320
-
321
- if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_build_render_context' ) ) {
322
- function {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block ) {
323
- $validator_path = __DIR__ . '/typia-validator.php';
324
- if ( ! file_exists( $validator_path ) ) {
325
- return null;
326
- }
327
-
328
- $validator = require $validator_path;
329
- if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
330
- return null;
331
- }
332
-
333
- $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
334
- $validation = $validator->validate( $normalized );
335
- $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
336
-
337
- if ( empty( $validation['valid'] ) || '' === $resource_key ) {
338
- return null;
339
- }
340
-
341
- $alignment = isset( $normalized['alignment'] ) ? (string) $normalized['alignment'] : 'left';
342
- $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
343
- $rendered_content = isset( $normalized['content'] ) ? (string) $normalized['content'] : '';
344
- $post_id = is_object( $block ) && isset( $block->context['postId'] )
345
- ? (int) $block->context['postId']
346
- : (int) get_queried_object_id();
347
- $storage_mode = '{{dataStorageMode}}';
348
- $persistence_policy = '{{persistencePolicy}}';
349
-
350
- {{phpPrefix}}_record_rendered_block_instance(
351
- (int) $post_id,
352
- '{{namespace}}/{{slugKebabCase}}',
353
- $resource_key
354
- );
355
-
356
- $notice_message = 'authenticated' === $persistence_policy
357
- ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
358
- : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
359
- $web_context = array(
360
- 'bootstrapReady' => false,
361
- 'buttonLabel' => $button_label,
362
- 'canWrite' => false,
363
- 'client' => array(
364
- 'writeExpiry' => 0,
365
- 'writeNonce' => '',
366
- 'writeToken' => '',
367
- ),
368
- 'count' => 0,
369
- 'error' => '',
370
- 'isBootstrapping' => false,
371
- 'isLoading' => false,
372
- 'isSaving' => false,
373
- 'isVisible' => ! empty( $normalized['isVisible'] ),
374
- 'persistencePolicy' => $persistence_policy,
375
- 'postId' => (int) $post_id,
376
- 'resourceKey' => $resource_key,
377
- 'storage' => $storage_mode,
378
- );
379
-
380
- return array(
381
- 'alignment' => $alignment,
382
- 'buttonLabel' => $button_label,
383
- 'content' => $rendered_content,
384
- 'frontendClassName' => '{{frontendCssClassName}}',
385
- 'isVisible' => ! empty( $normalized['isVisible'] ),
386
- 'normalized' => $normalized,
387
- 'noticeMessage' => $notice_message,
388
- 'postId' => (int) $post_id,
389
- 'resourceKey' => $resource_key,
390
- 'showCount' => ! empty( $normalized['showCount'] ),
391
- 'title' => {{titleJson}},
392
- 'webContext' => $web_context,
393
- );
394
- }
395
- }
396
-
397
- if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_render_target' ) ) {
398
- function {{phpPrefix}}_{{slugSnakeCase}}_render_target( string $target, $attributes, $content = '', $block = null ): string {
399
- $context = {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block );
400
- if ( null === $context || empty( $context['isVisible'] ) ) {
401
- return '';
402
- }
403
-
404
- $target_context = apply_filters(
405
- '{{phpPrefix}}_{{slugSnakeCase}}_render_target_context',
406
- $context,
407
- $target,
408
- $attributes,
409
- $block
410
- );
411
-
412
- $markup = '';
413
- switch ( $target ) {
414
- case 'email':
415
- $parts = array(
416
- '<div class="' . esc_attr( $target_context['frontendClassName'] ) . '-email">',
417
- '<p style="text-align:' . esc_attr( $target_context['alignment'] ) . ';">' . esc_html( $target_context['content'] ) . '</p>',
418
- );
419
- if ( ! empty( $target_context['showCount'] ) ) {
420
- $parts[] = '<p><strong>' . esc_html__( 'Count', '{{textDomain}}' ) . ':</strong> ' . esc_html( (string) $target_context['webContext']['count'] ) . '</p>';
421
- }
422
- $parts[] = '<p>' . esc_html( $target_context['noticeMessage'] ) . '</p>';
423
- $parts[] = '</div>';
424
- $markup = implode( '', $parts );
425
- break;
426
- case 'mjml':
427
- $markup = '<mjml><mj-body><mj-section><mj-column><mj-text align="' . esc_attr( $target_context['alignment'] ) . '">' . esc_html( $target_context['content'] ) . '</mj-text>';
428
- if ( ! empty( $target_context['showCount'] ) ) {
429
- $markup .= '<mj-text>' . esc_html__( 'Count', '{{textDomain}}' ) . ': ' . esc_html( (string) $target_context['webContext']['count'] ) . '</mj-text>';
430
- }
431
- $markup .= '<mj-text>' . esc_html( $target_context['noticeMessage'] ) . '</mj-text></mj-column></mj-section></mj-body></mjml>';
432
- break;
433
- case 'plain-text':
434
- $markup = implode(
435
- "\\n",
436
- array_filter(
437
- array(
438
- $target_context['title'],
439
- $target_context['content'],
440
- ! empty( $target_context['showCount'] )
441
- ? sprintf( '%s: %s', __( 'Count', '{{textDomain}}' ), (string) $target_context['webContext']['count'] )
442
- : null,
443
- $target_context['noticeMessage'],
444
- ),
445
- static fn( $value ) => is_string( $value ) && '' !== $value
446
- )
447
- );
448
- break;
449
- case 'web':
450
- default:
451
- $wrapper_attributes = get_block_wrapper_attributes(
452
- array(
453
- 'data-wp-context' => wp_json_encode( $target_context['webContext'] ),
454
- 'data-wp-interactive' => '{{slugKebabCase}}',
455
- 'data-wp-init' => 'callbacks.init',
456
- 'data-wp-run--mounted' => 'callbacks.mounted',
457
- )
458
- );
459
- ob_start();
460
- ?>
461
- <div <?php echo $wrapper_attributes; ?>>
462
- <div class="{{frontendCssClassName}}">
463
- <p class="{{frontendCssClassName}}__content" style="<?php echo esc_attr( 'text-align:' . $target_context['alignment'] ); ?>">
464
- <?php echo esc_html( $target_context['content'] ); ?>
465
- </p>
466
- <p
467
- class="{{frontendCssClassName}}__notice"
468
- data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
469
- hidden
470
- >
471
- <?php echo esc_html( $target_context['noticeMessage'] ); ?>
472
- </p>
473
- <p
474
- class="{{frontendCssClassName}}__error"
475
- role="status"
476
- aria-live="polite"
477
- aria-atomic="true"
478
- data-wp-bind--hidden="!context.error"
479
- data-wp-text="context.error"
480
- hidden
481
- ></p>
482
- <?php if ( ! empty( $target_context['showCount'] ) ) : ?>
483
- <span
484
- class="{{frontendCssClassName}}__count"
485
- role="status"
486
- aria-live="polite"
487
- aria-atomic="true"
488
- data-wp-text="context.count"
489
- >
490
- 0
491
- </span>
492
- <?php endif; ?>
493
- <button
494
- type="button"
495
- disabled
496
- data-wp-bind--disabled="!context.canWrite"
497
- data-wp-on--click="actions.increment"
498
- >
499
- <?php echo esc_html( $target_context['buttonLabel'] ); ?>
500
- </button>
501
- </div>
502
- </div>
503
- <?php
504
- $markup = (string) ob_get_clean();
505
- break;
506
- }
507
-
508
- return apply_filters(
509
- '{{phpPrefix}}_{{slugSnakeCase}}_render_target_markup',
510
- $markup,
511
- $target,
512
- $target_context
513
- );
514
- }
515
- }
516
- `;
517
- const COMPOUND_PERSISTENCE_RENDER_TARGETS_TEMPLATE = `<?php
518
- /**
519
- * Alternate render target helpers for the {{title}} compound parent block.
520
- *
521
- * @package {{pascalCase}}
522
- */
523
-
524
- if ( ! defined( 'ABSPATH' ) ) {
525
- exit;
526
- }
527
-
528
- if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_build_render_context' ) ) {
529
- function {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block ) {
530
- $validator_path = __DIR__ . '/typia-validator.php';
531
- if ( ! file_exists( $validator_path ) ) {
532
- return null;
533
- }
534
-
535
- $validator = require $validator_path;
536
- if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
537
- return null;
538
- }
539
-
540
- $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
541
- $validation = $validator->validate( $normalized );
542
- $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
543
- $heading = isset( $normalized['heading'] ) ? (string) $normalized['heading'] : {{titlePhpLiteral}};
544
- $intro = isset( $normalized['intro'] ) ? (string) $normalized['intro'] : '';
545
- $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
546
- $show_count = ! empty( $normalized['showCount'] );
547
- $show_dividers = ! empty( $normalized['showDividers'] );
548
- $post_id = is_object( $block ) && isset( $block->context['postId'] )
549
- ? (int) $block->context['postId']
550
- : (int) get_queried_object_id();
551
- $storage_mode = '{{dataStorageMode}}';
552
- $persistence_policy = '{{persistencePolicy}}';
553
-
554
- {{phpPrefix}}_record_rendered_block_instance(
555
- (int) $post_id,
556
- '{{namespace}}/{{slugKebabCase}}',
557
- $resource_key
558
- );
559
-
560
- $notice_message = 'authenticated' === $persistence_policy
561
- ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
562
- : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
563
-
564
- if ( empty( $validation['valid'] ) || '' === $resource_key ) {
565
- return null;
566
- }
567
-
568
- $web_context = array(
569
- 'bootstrapReady' => false,
570
- 'buttonLabel' => $button_label,
571
- 'canWrite' => false,
572
- 'client' => array(
573
- 'writeExpiry' => 0,
574
- 'writeNonce' => '',
575
- 'writeToken' => '',
576
- ),
577
- 'count' => 0,
578
- 'error' => '',
579
- 'isBootstrapping' => false,
580
- 'isLoading' => false,
581
- 'isSaving' => false,
582
- 'persistencePolicy' => $persistence_policy,
583
- 'postId' => (int) $post_id,
584
- 'resourceKey' => $resource_key,
585
- 'showCount' => $show_count,
586
- 'storage' => $storage_mode,
587
- );
588
-
589
- $allowed_inner_html = wp_kses_allowed_html( 'post' );
590
-
591
- foreach ( $allowed_inner_html as &$allowed_attributes ) {
592
- if ( ! is_array( $allowed_attributes ) ) {
593
- continue;
594
- }
595
-
596
- $allowed_attributes['data-wp-bind--disabled'] = true;
597
- $allowed_attributes['data-wp-bind--hidden'] = true;
598
- $allowed_attributes['data-wp-bind--value'] = true;
599
- $allowed_attributes['data-wp-class'] = true;
600
- $allowed_attributes['data-wp-class--active'] = true;
601
- $allowed_attributes['data-wp-context'] = true;
602
- $allowed_attributes['data-wp-init'] = true;
603
- $allowed_attributes['data-wp-interactive'] = true;
604
- $allowed_attributes['data-wp-on--click'] = true;
605
- $allowed_attributes['data-wp-on--mouseenter'] = true;
606
- $allowed_attributes['data-wp-on--mouseleave'] = true;
607
- $allowed_attributes['data-wp-run--mounted'] = true;
608
- $allowed_attributes['data-wp-style--width'] = true;
609
- $allowed_attributes['data-wp-text'] = true;
610
- }
611
- unset( $allowed_attributes );
612
-
613
- return array(
614
- 'buttonLabel' => $button_label,
615
- 'frontendClassName' => '{{cssClassName}}',
616
- 'heading' => $heading,
617
- 'intro' => $intro,
618
- 'isVisible' => true,
619
- 'normalized' => $normalized,
620
- 'noticeMessage' => $notice_message,
621
- 'postId' => (int) $post_id,
622
- 'resourceKey' => $resource_key,
623
- 'sanitizedContent' => wp_kses( $content, $allowed_inner_html ),
624
- 'showCount' => $show_count,
625
- 'showDividers' => $show_dividers,
626
- 'title' => {{titleJson}},
627
- 'webContext' => $web_context,
628
- );
629
- }
630
- }
631
-
632
- if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_render_target' ) ) {
633
- function {{phpPrefix}}_{{slugSnakeCase}}_render_target( string $target, $attributes, $content = '', $block = null ): string {
634
- $context = {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block );
635
- if ( null === $context ) {
636
- return '';
637
- }
638
-
639
- $target_context = apply_filters(
640
- '{{phpPrefix}}_{{slugSnakeCase}}_render_target_context',
641
- $context,
642
- $target,
643
- $attributes,
644
- $block
645
- );
646
-
647
- $markup = '';
648
- switch ( $target ) {
649
- case 'email':
650
- $parts = array(
651
- '<div class="' . esc_attr( $target_context['frontendClassName'] ) . '-email">',
652
- '<h3>' . esc_html( $target_context['heading'] ) . '</h3>',
653
- );
654
- if ( '' !== $target_context['intro'] ) {
655
- $parts[] = '<p>' . esc_html( $target_context['intro'] ) . '</p>';
656
- }
657
- if ( ! empty( $target_context['showCount'] ) ) {
658
- $parts[] = '<p><strong>' . esc_html__( 'Count', '{{textDomain}}' ) . ':</strong> ' . esc_html( (string) $target_context['webContext']['count'] ) . '</p>';
659
- }
660
- $parts[] = wp_kses_post( $target_context['sanitizedContent'] );
661
- $parts[] = '<p>' . esc_html( $target_context['noticeMessage'] ) . '</p>';
662
- $parts[] = '</div>';
663
- $markup = implode( '', $parts );
664
- break;
665
- case 'mjml':
666
- $markup = '<mjml><mj-body><mj-section><mj-column><mj-text font-weight="700">' . esc_html( $target_context['heading'] ) . '</mj-text>';
667
- if ( '' !== $target_context['intro'] ) {
668
- $markup .= '<mj-text>' . esc_html( $target_context['intro'] ) . '</mj-text>';
669
- }
670
- if ( ! empty( $target_context['showCount'] ) ) {
671
- $markup .= '<mj-text>' . esc_html__( 'Count', '{{textDomain}}' ) . ': ' . esc_html( (string) $target_context['webContext']['count'] ) . '</mj-text>';
672
- }
673
- $markup .= '<mj-text>' . esc_html( wp_strip_all_tags( $target_context['sanitizedContent'] ) ) . '</mj-text>';
674
- $markup .= '<mj-text>' . esc_html( $target_context['noticeMessage'] ) . '</mj-text></mj-column></mj-section></mj-body></mjml>';
675
- break;
676
- case 'plain-text':
677
- $markup = implode(
678
- "\\n",
679
- array_filter(
680
- array(
681
- $target_context['heading'],
682
- $target_context['intro'],
683
- wp_strip_all_tags( $target_context['sanitizedContent'] ),
684
- ! empty( $target_context['showCount'] )
685
- ? sprintf( '%s: %s', __( 'Count', '{{textDomain}}' ), (string) $target_context['webContext']['count'] )
686
- : null,
687
- $target_context['noticeMessage'],
688
- ),
689
- static fn( $value ) => is_string( $value ) && '' !== $value
690
- )
691
- );
692
- break;
693
- case 'web':
694
- default:
695
- $wrapper_attributes = get_block_wrapper_attributes(
696
- array(
697
- 'class' => '{{cssClassName}}',
698
- 'data-show-dividers' => $target_context['showDividers'] ? 'true' : 'false',
699
- 'data-wp-context' => wp_json_encode( $target_context['webContext'] ),
700
- 'data-wp-init' => 'callbacks.init',
701
- 'data-wp-interactive' => '{{slugKebabCase}}',
702
- 'data-wp-run--mounted' => 'callbacks.mounted',
703
- )
704
- );
705
- ob_start();
706
- ?>
707
- <div <?php echo $wrapper_attributes; ?>>
708
- <h3 class="{{cssClassName}}__heading"><?php echo esc_html( $target_context['heading'] ); ?></h3>
709
- <?php if ( '' !== $target_context['intro'] ) : ?>
710
- <p class="{{cssClassName}}__intro"><?php echo esc_html( $target_context['intro'] ); ?></p>
711
- <?php endif; ?>
712
- <p
713
- class="{{cssClassName}}__notice"
714
- data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
715
- hidden
716
- >
717
- <?php echo esc_html( $target_context['noticeMessage'] ); ?>
718
- </p>
719
- <p
720
- class="{{cssClassName}}__error"
721
- role="status"
722
- aria-live="polite"
723
- aria-atomic="true"
724
- data-wp-bind--hidden="!context.error"
725
- data-wp-text="context.error"
726
- hidden
727
- ></p>
728
- <?php if ( ! empty( $target_context['showCount'] ) ) : ?>
729
- <div class="{{cssClassName}}__counter">
730
- <span
731
- class="{{cssClassName}}__count"
732
- role="status"
733
- aria-live="polite"
734
- aria-atomic="true"
735
- data-wp-text="context.count"
736
- >0</span>
737
- <button
738
- type="button"
739
- disabled
740
- data-wp-bind--disabled="!context.canWrite"
741
- data-wp-on--click="actions.increment"
742
- >
743
- <?php echo esc_html( $target_context['buttonLabel'] ); ?>
744
- </button>
745
- </div>
746
- <?php endif; ?>
747
- <div class="{{cssClassName}}__items">
748
- <?php echo wp_kses_post( $target_context['sanitizedContent'] ); ?>
749
- </div>
750
- </div>
751
- <?php
752
- $markup = (string) ob_get_clean();
753
- break;
754
- }
755
-
756
- return apply_filters(
757
- '{{phpPrefix}}_{{slugSnakeCase}}_render_target_markup',
758
- $markup,
759
- $target,
760
- $target_context
761
- );
762
- }
763
- }
764
- `;
765
- const COMPOUND_STYLE_TEMPLATE = `.{{cssClassName}} {
766
- border: 1px solid #dcdcde;
767
- border-radius: 12px;
768
- padding: 1.25rem;
769
- background: #fff;
770
- }
771
-
772
- .{{cssClassName}}__heading {
773
- margin: 0 0 0.5rem;
774
- font-size: 1.2rem;
775
- }
776
-
777
- .{{cssClassName}}__intro {
778
- margin: 0 0 1rem;
779
- color: #50575e;
780
- }
781
-
782
- .{{cssClassName}}__items {
783
- display: grid;
784
- gap: 0.75rem;
785
- }
786
-
787
- .{{cssClassName}}[data-show-dividers='true'] .{{compoundChildCssClassName}} {
788
- border-top: 1px solid #dcdcde;
789
- padding-top: 0.75rem;
790
- }
791
-
792
- .{{cssClassName}}[data-show-dividers='true'] .{{compoundChildCssClassName}}:first-child {
793
- border-top: 0;
794
- padding-top: 0;
795
- }
796
- `;
797
- function renderArtifact(relativePath, template, view) {
798
- const source = renderMustacheTemplateString(template, view);
799
- return {
800
- relativePath,
801
- source: source.endsWith("\n") ? source : `${source}\n`,
802
- };
803
- }
804
- function buildAlternateRenderEntryArtifact(relativePath, target, variables) {
805
- const template = `<?php
806
- /**
807
- * Alternate ${target} render entry for {{title}}.
808
- *
809
- * @package {{pascalCase}}
810
- */
811
-
812
- if ( ! defined( 'ABSPATH' ) ) {
813
- exit;
814
- }
815
-
816
- require_once __DIR__ . '/render-targets.php';
817
-
818
- return {{phpPrefix}}_{{slugSnakeCase}}_render_target( '${target}', $attributes, $content ?? '', $block ?? null );
819
- `;
820
- return renderArtifact(relativePath, template, variables);
821
- }
822
- function toPhpSingleQuotedString(value) {
823
- return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
824
- }
825
- function buildBasicArtifacts(variables) {
826
- return [
827
- renderArtifact("src/editor.scss", BASIC_EDITOR_STYLE_TEMPLATE, variables),
828
- renderArtifact("src/style.scss", BASIC_STYLE_TEMPLATE, variables),
829
- renderArtifact("src/render.php", BASIC_RENDER_TEMPLATE, variables),
830
- ];
831
- }
832
- function buildInteractivityArtifacts(variables) {
833
- return [
834
- renderArtifact("src/editor.scss", INTERACTIVITY_EDITOR_STYLE_TEMPLATE, variables),
835
- renderArtifact("src/style.scss", INTERACTIVITY_STYLE_TEMPLATE, variables),
836
- ];
837
- }
838
- function buildPersistenceArtifacts(variables) {
839
- if (variables.hasAlternateRenderTargets !== "true") {
840
- return [
841
- renderArtifact("src/style.scss", PERSISTENCE_STYLE_TEMPLATE, variables),
842
- renderArtifact("src/render.php", PERSISTENCE_RENDER_TEMPLATE, variables),
843
- ];
844
- }
845
- const artifacts = [
846
- renderArtifact("src/style.scss", PERSISTENCE_STYLE_TEMPLATE, variables),
847
- renderArtifact("src/render-targets.php", PERSISTENCE_RENDER_TARGETS_TEMPLATE, variables),
848
- buildAlternateRenderEntryArtifact("src/render.php", "web", variables),
849
- ];
850
- if (variables.hasAlternateEmailRenderTarget === "true") {
851
- artifacts.push(buildAlternateRenderEntryArtifact("src/render-email.php", "email", variables));
852
- }
853
- if (variables.hasAlternateMjmlRenderTarget === "true") {
854
- artifacts.push(buildAlternateRenderEntryArtifact("src/render-mjml.php", "mjml", variables));
855
- }
856
- if (variables.hasAlternatePlainTextRenderTarget === "true") {
857
- artifacts.push(buildAlternateRenderEntryArtifact("src/render-text.php", "plain-text", variables));
858
- }
859
- return artifacts;
860
- }
861
- function buildCompoundArtifacts(variables) {
862
- const artifacts = [
863
- renderArtifact(`src/blocks/${variables.slugKebabCase}/style.scss`, COMPOUND_STYLE_TEMPLATE, variables),
864
- ];
865
- if (variables.compoundPersistenceEnabled === "true") {
866
- const renderView = {
867
- ...variables,
868
- titlePhpLiteral: toPhpSingleQuotedString(variables.title),
869
- };
870
- if (variables.hasAlternateRenderTargets === "true") {
871
- artifacts.push(renderArtifact(`src/blocks/${variables.slugKebabCase}/render-targets.php`, COMPOUND_PERSISTENCE_RENDER_TARGETS_TEMPLATE, renderView), buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render.php`, "web", variables));
872
- if (variables.hasAlternateEmailRenderTarget === "true") {
873
- artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-email.php`, "email", variables));
874
- }
875
- if (variables.hasAlternateMjmlRenderTarget === "true") {
876
- artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-mjml.php`, "mjml", variables));
877
- }
878
- if (variables.hasAlternatePlainTextRenderTarget === "true") {
879
- artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-text.php`, "plain-text", variables));
880
- }
881
- return artifacts;
882
- }
883
- const renderSource = `<?php
884
- /**
885
- * Dynamic render entry for the {{title}} compound parent block.
886
- *
887
- * @package {{pascalCase}}
888
- */
889
-
890
- if ( ! defined( 'ABSPATH' ) ) {
891
- exit;
892
- }
893
-
894
- $validator_path = __DIR__ . '/typia-validator.php';
895
- if ( ! file_exists( $validator_path ) ) {
896
- return '';
897
- }
898
-
899
- $validator = require $validator_path;
900
- if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
901
- return '';
902
- }
903
-
904
- $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
905
- $validation = $validator->validate( $normalized );
906
- $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
907
- $heading = isset( $normalized['heading'] ) ? (string) $normalized['heading'] : {{titlePhpLiteral}};
908
- $intro = isset( $normalized['intro'] ) ? (string) $normalized['intro'] : '';
909
- $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
910
- $show_count = ! empty( $normalized['showCount'] );
911
- $show_dividers = ! empty( $normalized['showDividers'] );
912
- $post_id = is_object( $block ) && isset( $block->context['postId'] )
913
- ? (int) $block->context['postId']
914
- : (int) get_queried_object_id();
915
- $storage_mode = '{{dataStorageMode}}';
916
- $persistence_policy = '{{persistencePolicy}}';
917
-
918
- {{phpPrefix}}_record_rendered_block_instance(
919
- (int) $post_id,
920
- '{{namespace}}/{{slugKebabCase}}',
921
- $resource_key
922
- );
923
-
924
- $notice_message = 'authenticated' === $persistence_policy
925
- ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
926
- : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
927
-
928
- if ( empty( $validation['valid'] ) || '' === $resource_key ) {
929
- return '';
930
- }
931
-
932
- $context = array(
933
- 'bootstrapReady' => false,
934
- 'buttonLabel' => $button_label,
935
- 'canWrite' => false,
936
- 'client' => array(
937
- 'writeExpiry' => 0,
938
- 'writeNonce' => '',
939
- 'writeToken' => '',
940
- ),
941
- 'count' => 0,
942
- 'error' => '',
943
- 'isBootstrapping' => false,
944
- 'isLoading' => false,
945
- 'isSaving' => false,
946
- 'persistencePolicy' => $persistence_policy,
947
- 'postId' => (int) $post_id,
948
- 'resourceKey' => $resource_key,
949
- 'showCount' => $show_count,
950
- 'storage' => $storage_mode,
951
- );
952
-
953
- $allowed_inner_html = wp_kses_allowed_html( 'post' );
954
-
955
- foreach ( $allowed_inner_html as &$allowed_attributes ) {
956
- if ( ! is_array( $allowed_attributes ) ) {
957
- continue;
958
- }
959
-
960
- $allowed_attributes['data-wp-bind--disabled'] = true;
961
- $allowed_attributes['data-wp-bind--hidden'] = true;
962
- $allowed_attributes['data-wp-bind--value'] = true;
963
- $allowed_attributes['data-wp-class'] = true;
964
- $allowed_attributes['data-wp-class--active'] = true;
965
- $allowed_attributes['data-wp-context'] = true;
966
- $allowed_attributes['data-wp-init'] = true;
967
- $allowed_attributes['data-wp-interactive'] = true;
968
- $allowed_attributes['data-wp-on--click'] = true;
969
- $allowed_attributes['data-wp-on--mouseenter'] = true;
970
- $allowed_attributes['data-wp-on--mouseleave'] = true;
971
- $allowed_attributes['data-wp-run--mounted'] = true;
972
- $allowed_attributes['data-wp-style--width'] = true;
973
- $allowed_attributes['data-wp-text'] = true;
974
- }
975
- unset( $allowed_attributes );
976
-
977
- $sanitized_content = wp_kses( $content, $allowed_inner_html );
978
-
979
- $wrapper_attributes = get_block_wrapper_attributes(
980
- array(
981
- 'class' => '{{cssClassName}}',
982
- 'data-show-dividers' => $show_dividers ? 'true' : 'false',
983
- 'data-wp-context' => wp_json_encode( $context ),
984
- 'data-wp-init' => 'callbacks.init',
985
- 'data-wp-interactive' => '{{slugKebabCase}}',
986
- 'data-wp-run--mounted' => 'callbacks.mounted',
987
- )
988
- );
989
- ?>
990
-
991
- <div <?php echo $wrapper_attributes; ?>>
992
- <h3 class="{{cssClassName}}__heading"><?php echo esc_html( $heading ); ?></h3>
993
- <?php if ( '' !== $intro ) : ?>
994
- <p class="{{cssClassName}}__intro"><?php echo esc_html( $intro ); ?></p>
995
- <?php endif; ?>
996
- <p
997
- class="{{cssClassName}}__notice"
998
- data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
999
- hidden
1000
- >
1001
- <?php echo esc_html( $notice_message ); ?>
1002
- </p>
1003
- <p
1004
- class="{{cssClassName}}__error"
1005
- role="status"
1006
- aria-live="polite"
1007
- aria-atomic="true"
1008
- data-wp-bind--hidden="!context.error"
1009
- data-wp-text="context.error"
1010
- hidden
1011
- ></p>
1012
- <?php if ( $show_count ) : ?>
1013
- <div class="{{cssClassName}}__counter">
1014
- <span
1015
- class="{{cssClassName}}__count"
1016
- role="status"
1017
- aria-live="polite"
1018
- aria-atomic="true"
1019
- data-wp-text="context.count"
1020
- >0</span>
1021
- <button
1022
- type="button"
1023
- disabled
1024
- data-wp-bind--disabled="!context.canWrite"
1025
- data-wp-on--click="actions.increment"
1026
- >
1027
- <?php echo esc_html( $button_label ); ?>
1028
- </button>
1029
- </div>
1030
- <?php endif; ?>
1031
- <div class="{{cssClassName}}__items">
1032
- <?php echo $sanitized_content; ?>
1033
- </div>
1034
- </div>
1035
- `;
1036
- artifacts.push(renderArtifact(`src/blocks/${variables.slugKebabCase}/render.php`, renderSource, renderView));
1037
- }
1038
- return artifacts;
1039
- }
1
+ import { buildBasicArtifacts, buildCompoundArtifacts, buildInteractivityArtifacts, buildPersistenceArtifacts, } from "./built-in-block-non-ts-family-artifacts.js";
1040
2
  /**
1041
3
  * Builds non-TypeScript scaffold artifacts for built-in block templates.
1042
4
  *