@wp-typia/project-tools 0.16.2 → 0.16.5

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 (80) hide show
  1. package/README.md +13 -0
  2. package/dist/runtime/block-generator-service.d.ts +102 -0
  3. package/dist/runtime/block-generator-service.js +268 -0
  4. package/dist/runtime/built-in-block-artifacts.d.ts +37 -0
  5. package/dist/runtime/built-in-block-artifacts.js +1203 -0
  6. package/dist/runtime/built-in-block-code-artifacts.d.ts +31 -0
  7. package/dist/runtime/built-in-block-code-artifacts.js +137 -0
  8. package/dist/runtime/built-in-block-non-ts-artifacts.d.ts +18 -0
  9. package/dist/runtime/built-in-block-non-ts-artifacts.js +563 -0
  10. package/dist/runtime/cli-doctor.js +10 -5
  11. package/dist/runtime/index.d.ts +2 -0
  12. package/dist/runtime/index.js +1 -0
  13. package/dist/runtime/scaffold-apply-utils.d.ts +47 -0
  14. package/dist/runtime/scaffold-apply-utils.js +405 -0
  15. package/dist/runtime/scaffold-identifiers.d.ts +34 -0
  16. package/dist/runtime/scaffold-identifiers.js +82 -0
  17. package/dist/runtime/scaffold.js +33 -0
  18. package/dist/runtime/starter-manifests.d.ts +3 -2
  19. package/dist/runtime/starter-manifests.js +15 -365
  20. package/dist/runtime/template-builtins.d.ts +9 -0
  21. package/dist/runtime/template-builtins.js +31 -1
  22. package/dist/runtime/template-render.d.ts +5 -0
  23. package/dist/runtime/template-render.js +13 -3
  24. package/dist/runtime/template-source.js +9 -3
  25. package/package.json +2 -2
  26. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +4 -4
  27. package/templates/_shared/persistence/core/scripts/sync-rest-contracts.ts.mustache +4 -4
  28. package/templates/_shared/base/src/hooks.ts.mustache +0 -19
  29. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -52
  30. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -123
  31. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
  32. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/interactivity.ts.mustache +0 -305
  33. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/render.php.mustache +0 -152
  34. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -3
  35. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -61
  36. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -43
  37. package/templates/_shared/persistence/core/src/index.tsx.mustache +0 -25
  38. package/templates/_shared/persistence/core/src/interactivity.ts.mustache +0 -308
  39. package/templates/_shared/persistence/core/src/save.tsx.mustache +0 -5
  40. package/templates/_shared/persistence/core/src/validators.ts.mustache +0 -43
  41. package/templates/basic/src/block.json.mustache +0 -51
  42. package/templates/basic/src/edit.tsx.mustache +0 -128
  43. package/templates/basic/src/editor.scss.mustache +0 -8
  44. package/templates/basic/src/hooks.ts.mustache +0 -18
  45. package/templates/basic/src/index.tsx.mustache +0 -45
  46. package/templates/basic/src/render.php.mustache +0 -19
  47. package/templates/basic/src/save.tsx.mustache +0 -30
  48. package/templates/basic/src/style.scss.mustache +0 -40
  49. package/templates/basic/src/types.ts.mustache +0 -56
  50. package/templates/basic/src/validators.ts.mustache +0 -37
  51. package/templates/compound/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -37
  52. package/templates/compound/src/blocks/{{slugKebabCase}}/children.ts.mustache +0 -25
  53. package/templates/compound/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -93
  54. package/templates/compound/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
  55. package/templates/compound/src/blocks/{{slugKebabCase}}/index.tsx.mustache +0 -25
  56. package/templates/compound/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -32
  57. package/templates/compound/src/blocks/{{slugKebabCase}}/style.scss.mustache +0 -31
  58. package/templates/compound/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -18
  59. package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -35
  60. package/templates/compound/src/blocks/{{slugKebabCase}}-item/block.json.mustache +0 -35
  61. package/templates/compound/src/blocks/{{slugKebabCase}}-item/edit.tsx.mustache +0 -50
  62. package/templates/compound/src/blocks/{{slugKebabCase}}-item/hooks.ts.mustache +0 -11
  63. package/templates/compound/src/blocks/{{slugKebabCase}}-item/index.tsx.mustache +0 -25
  64. package/templates/compound/src/blocks/{{slugKebabCase}}-item/save.tsx.mustache +0 -24
  65. package/templates/compound/src/blocks/{{slugKebabCase}}-item/types.ts.mustache +0 -17
  66. package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +0 -35
  67. package/templates/interactivity/src/block.json.mustache +0 -74
  68. package/templates/interactivity/src/edit.tsx.mustache +0 -270
  69. package/templates/interactivity/src/editor.scss.mustache +0 -8
  70. package/templates/interactivity/src/index.tsx.mustache +0 -33
  71. package/templates/interactivity/src/interactivity.ts.mustache +0 -152
  72. package/templates/interactivity/src/save.tsx.mustache +0 -101
  73. package/templates/interactivity/src/style.scss.mustache +0 -60
  74. package/templates/interactivity/src/types.ts.mustache +0 -32
  75. package/templates/interactivity/src/validators.ts.mustache +0 -47
  76. package/templates/persistence/src/block.json.mustache +0 -52
  77. package/templates/persistence/src/edit.tsx.mustache +0 -165
  78. package/templates/persistence/src/render.php.mustache +0 -120
  79. package/templates/persistence/src/style.scss.mustache +0 -46
  80. package/templates/persistence/src/types.ts.mustache +0 -59
@@ -1,25 +0,0 @@
1
- import { registerBlockType } from '@wordpress/blocks';
2
- import type { BlockConfiguration } from '@wordpress/blocks';
3
- import {
4
- buildScaffoldBlockRegistration,
5
- type ScaffoldBlockMetadata,
6
- } from '@wp-typia/block-runtime/blocks';
7
-
8
- import Edit from './edit';
9
- import Save from './save';
10
- import metadata from './block.json';
11
- import './style.scss';
12
-
13
- import type { {{pascalCase}}Attributes } from './types';
14
-
15
- const registration = buildScaffoldBlockRegistration<
16
- BlockConfiguration< {{pascalCase}}Attributes >
17
- >( metadata as ScaffoldBlockMetadata, {
18
- edit: Edit,
19
- save: Save,
20
- } );
21
-
22
- registerBlockType< {{pascalCase}}Attributes >(
23
- registration.name,
24
- registration.settings
25
- );
@@ -1,308 +0,0 @@
1
- import { getContext, store } from '@wordpress/interactivity';
2
- import { generatePublicWriteRequestId } from '@wp-typia/block-runtime/identifiers';
3
-
4
- import { fetchBootstrap, fetchState, writeState } from './api';
5
- import type {
6
- {{pascalCase}}ClientState,
7
- {{pascalCase}}Context,
8
- {{pascalCase}}State,
9
- } from './types';
10
- import type {
11
- {{pascalCase}}WriteStateRequest,
12
- } from './api-types';
13
-
14
- function hasExpiredPublicWriteToken(
15
- expiresAt?: number
16
- ): boolean {
17
- return (
18
- typeof expiresAt === 'number' &&
19
- expiresAt > 0 &&
20
- Date.now() >= expiresAt * 1000
21
- );
22
- }
23
-
24
- function getWriteBlockedMessage(
25
- context: {{pascalCase}}Context
26
- ): string {
27
- return context.persistencePolicy === 'authenticated'
28
- ? 'Sign in to persist this counter.'
29
- : 'Public writes are temporarily unavailable.';
30
- }
31
-
32
- const BOOTSTRAP_MAX_ATTEMPTS = 3;
33
- const BOOTSTRAP_RETRY_DELAYS_MS = [ 250, 500 ];
34
-
35
- async function waitForBootstrapRetry( delayMs: number ): Promise< void > {
36
- await new Promise( ( resolve ) => {
37
- setTimeout( resolve, delayMs );
38
- } );
39
- }
40
-
41
- function getClientState(
42
- context: {{pascalCase}}Context
43
- ): {{pascalCase}}ClientState {
44
- if ( context.client ) {
45
- return context.client;
46
- }
47
-
48
- context.client = {
49
- bootstrapError: '',
50
- writeExpiry: 0,
51
- writeNonce: '',
52
- writeToken: '',
53
- };
54
-
55
- return context.client;
56
- }
57
-
58
- function clearBootstrapError(
59
- context: {{pascalCase}}Context,
60
- clientState: {{pascalCase}}ClientState
61
- ): void {
62
- if ( context.error === clientState.bootstrapError ) {
63
- context.error = '';
64
- }
65
- clientState.bootstrapError = '';
66
- }
67
-
68
- function setBootstrapError(
69
- context: {{pascalCase}}Context,
70
- clientState: {{pascalCase}}ClientState,
71
- message: string
72
- ): void {
73
- clientState.bootstrapError = message;
74
- context.error = message;
75
- }
76
-
77
- const { actions, state } = store( '{{slugKebabCase}}', {
78
- state: {
79
- isHydrated: false,
80
- } as {{pascalCase}}State,
81
-
82
- actions: {
83
- async loadState() {
84
- const context = getContext< {{pascalCase}}Context >();
85
- if ( context.postId <= 0 || ! context.resourceKey ) {
86
- return;
87
- }
88
-
89
- context.isLoading = true;
90
- context.error = '';
91
-
92
- try {
93
- const result = await fetchState( {
94
- postId: context.postId,
95
- resourceKey: context.resourceKey,
96
- }, {
97
- transportTarget: 'frontend',
98
- } );
99
- if ( ! result.isValid || ! result.data ) {
100
- context.error = result.errors[ 0 ]?.expected ?? 'Unable to load counter';
101
- return;
102
- }
103
- context.count = result.data.count;
104
- } catch ( error ) {
105
- context.error =
106
- error instanceof Error ? error.message : 'Unknown loading error';
107
- } finally {
108
- context.isLoading = false;
109
- }
110
- },
111
- async loadBootstrap() {
112
- const context = getContext< {{pascalCase}}Context >();
113
- const clientState = getClientState( context );
114
- if ( context.postId <= 0 || ! context.resourceKey ) {
115
- context.bootstrapReady = true;
116
- context.canWrite = false;
117
- clientState.bootstrapError = '';
118
- clientState.writeExpiry = 0;
119
- clientState.writeNonce = '';
120
- clientState.writeToken = '';
121
- return;
122
- }
123
-
124
- context.isBootstrapping = true;
125
-
126
- let bootstrapSucceeded = false;
127
- let lastBootstrapError =
128
- 'Unable to initialize write access';
129
- const includePublicWriteCredentials = {{isPublicPersistencePolicy}};
130
- const includeRestNonce = {{isAuthenticatedPersistencePolicy}};
131
-
132
- for ( let attempt = 1; attempt <= BOOTSTRAP_MAX_ATTEMPTS; attempt += 1 ) {
133
- try {
134
- const result = await fetchBootstrap( {
135
- postId: context.postId,
136
- resourceKey: context.resourceKey,
137
- }, {
138
- transportTarget: 'frontend',
139
- } );
140
- if ( ! result.isValid || ! result.data ) {
141
- lastBootstrapError =
142
- result.errors[ 0 ]?.expected ??
143
- 'Unable to initialize write access';
144
- if ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {
145
- await waitForBootstrapRetry(
146
- BOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750
147
- );
148
- continue;
149
- }
150
- break;
151
- }
152
-
153
- clientState.writeExpiry =
154
- includePublicWriteCredentials &&
155
- 'publicWriteExpiresAt' in result.data &&
156
- typeof result.data.publicWriteExpiresAt === 'number' &&
157
- result.data.publicWriteExpiresAt > 0
158
- ? result.data.publicWriteExpiresAt
159
- : 0;
160
- clientState.writeToken =
161
- includePublicWriteCredentials &&
162
- 'publicWriteToken' in result.data &&
163
- typeof result.data.publicWriteToken === 'string' &&
164
- result.data.publicWriteToken.length > 0
165
- ? result.data.publicWriteToken
166
- : '';
167
- clientState.writeNonce =
168
- includeRestNonce &&
169
- 'restNonce' in result.data &&
170
- typeof result.data.restNonce === 'string' &&
171
- result.data.restNonce.length > 0
172
- ? result.data.restNonce
173
- : '';
174
- context.bootstrapReady = true;
175
- context.canWrite =
176
- result.data.canWrite === true &&
177
- (
178
- context.persistencePolicy === 'authenticated'
179
- ? clientState.writeNonce.length > 0
180
- : clientState.writeToken.length > 0 &&
181
- ! hasExpiredPublicWriteToken( clientState.writeExpiry )
182
- );
183
- clearBootstrapError( context, clientState );
184
- bootstrapSucceeded = true;
185
- break;
186
- } catch ( error ) {
187
- lastBootstrapError =
188
- error instanceof Error ? error.message : 'Unknown bootstrap error';
189
- if ( attempt < BOOTSTRAP_MAX_ATTEMPTS ) {
190
- await waitForBootstrapRetry(
191
- BOOTSTRAP_RETRY_DELAYS_MS[ attempt - 1 ] ?? 750
192
- );
193
- continue;
194
- }
195
- break;
196
- }
197
- }
198
-
199
- if ( ! bootstrapSucceeded ) {
200
- context.bootstrapReady = false;
201
- context.canWrite = false;
202
- clientState.writeExpiry = 0;
203
- clientState.writeNonce = '';
204
- clientState.writeToken = '';
205
- setBootstrapError( context, clientState, lastBootstrapError );
206
- }
207
- context.isBootstrapping = false;
208
- },
209
- async increment() {
210
- const context = getContext< {{pascalCase}}Context >();
211
- const clientState = getClientState( context );
212
- if ( context.postId <= 0 || ! context.resourceKey ) {
213
- return;
214
- }
215
- if ( ! context.bootstrapReady ) {
216
- await actions.loadBootstrap();
217
- }
218
- if ( ! context.bootstrapReady ) {
219
- context.error = 'Write access is still initializing.';
220
- return;
221
- }
222
- if (
223
- context.persistencePolicy === 'public' &&
224
- hasExpiredPublicWriteToken( clientState.writeExpiry )
225
- ) {
226
- await actions.loadBootstrap();
227
- }
228
- if (
229
- context.persistencePolicy === 'public' &&
230
- hasExpiredPublicWriteToken( clientState.writeExpiry )
231
- ) {
232
- context.canWrite = false;
233
- context.error = getWriteBlockedMessage( context );
234
- return;
235
- }
236
- if ( ! context.canWrite ) {
237
- context.error = getWriteBlockedMessage( context );
238
- return;
239
- }
240
-
241
- context.isSaving = true;
242
- context.error = '';
243
-
244
- try {
245
- const request = {
246
- delta: 1,
247
- postId: context.postId,
248
- resourceKey: context.resourceKey,
249
- } as {{pascalCase}}WriteStateRequest;
250
- if ( {{isPublicPersistencePolicy}} ) {
251
- request.publicWriteRequestId =
252
- generatePublicWriteRequestId() as {{pascalCase}}WriteStateRequest[ 'publicWriteRequestId' ];
253
- if ( clientState.writeToken.length > 0 ) {
254
- request.publicWriteToken =
255
- clientState.writeToken as {{pascalCase}}WriteStateRequest[ 'publicWriteToken' ];
256
- }
257
- }
258
- const result = await writeState( request, {
259
- restNonce:
260
- clientState.writeNonce.length > 0
261
- ? clientState.writeNonce
262
- : undefined,
263
- transportTarget: 'frontend',
264
- } );
265
- if ( ! result.isValid || ! result.data ) {
266
- context.error = result.errors[ 0 ]?.expected ?? 'Unable to update counter';
267
- return;
268
- }
269
- context.count = result.data.count;
270
- context.storage = result.data.storage;
271
- } catch ( error ) {
272
- context.error =
273
- error instanceof Error ? error.message : 'Unknown update error';
274
- } finally {
275
- context.isSaving = false;
276
- }
277
- },
278
- },
279
-
280
- callbacks: {
281
- init() {
282
- const context = getContext< {{pascalCase}}Context >();
283
- context.client = {
284
- bootstrapError: '',
285
- writeExpiry: 0,
286
- writeNonce: '',
287
- writeToken: '',
288
- };
289
- context.bootstrapReady = false;
290
- context.canWrite = false;
291
- context.count = 0;
292
- context.error = '';
293
- context.isBootstrapping = false;
294
- context.isLoading = false;
295
- context.isSaving = false;
296
- },
297
- mounted() {
298
- state.isHydrated = true;
299
- if ( typeof document !== 'undefined' ) {
300
- document.documentElement.dataset[ '{{slugCamelCase}}Hydrated' ] = 'true';
301
- }
302
- void Promise.allSettled( [
303
- actions.loadState(),
304
- actions.loadBootstrap(),
305
- ] );
306
- },
307
- },
308
- } );
@@ -1,5 +0,0 @@
1
- export default function Save() {
2
- // This block is intentionally server-rendered. PHP bootstraps post context,
3
- // storage-backed state, and write-policy data before the frontend hydrates.
4
- return null;
5
- }
@@ -1,43 +0,0 @@
1
- import typia from 'typia';
2
- import currentManifest from './typia.manifest.json';
3
- import type {
4
- {{pascalCase}}Attributes,
5
- {{pascalCase}}ValidationResult,
6
- } from './types';
7
- import { generateResourceKey } from '@wp-typia/block-runtime/identifiers';
8
- import { createTemplateValidatorToolkit } from './validator-toolkit';
9
-
10
- const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {
11
- assert: typia.createAssert< {{pascalCase}}Attributes >(),
12
- clone: typia.misc.createClone< {{pascalCase}}Attributes >() as (
13
- value: {{pascalCase}}Attributes,
14
- ) => {{pascalCase}}Attributes,
15
- is: typia.createIs< {{pascalCase}}Attributes >(),
16
- manifest: currentManifest,
17
- prune: typia.misc.createPrune< {{pascalCase}}Attributes >(),
18
- random: typia.createRandom< {{pascalCase}}Attributes >() as (
19
- ...args: unknown[]
20
- ) => {{pascalCase}}Attributes,
21
- finalize: ( normalized ) => ( {
22
- ...normalized,
23
- resourceKey:
24
- normalized.resourceKey && normalized.resourceKey.length > 0
25
- ? normalized.resourceKey
26
- : generateResourceKey( '{{slugKebabCase}}' ),
27
- } ),
28
- validate: typia.createValidate< {{pascalCase}}Attributes >(),
29
- } );
30
-
31
- export const validators = scaffoldValidators.validators;
32
-
33
- export const validate{{pascalCase}}Attributes =
34
- scaffoldValidators.validateAttributes as (
35
- attributes: unknown
36
- ) => {{pascalCase}}ValidationResult;
37
-
38
- export const sanitize{{pascalCase}}Attributes =
39
- scaffoldValidators.sanitizeAttributes as (
40
- attributes: Partial< {{pascalCase}}Attributes >
41
- ) => {{pascalCase}}Attributes;
42
-
43
- export const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;
@@ -1,51 +0,0 @@
1
- {
2
- "$schema": "https://schemas.wp.org/trunk/block.json",
3
- "apiVersion": 3,
4
- "name": "{{namespace}}/{{slug}}",
5
- "version": "{{blockMetadataVersion}}",
6
- "title": "{{title}}",
7
- "category": "{{category}}",
8
- "icon": "{{icon}}",
9
- "description": "{{description}}",
10
- "keywords": ["{{keyword}}", "typia", "block"],
11
- "example": {
12
- "attributes": {
13
- "content": "Example content",
14
- "alignment": "center",
15
- "isVisible": true
16
- }
17
- },
18
- "supports": {
19
- "html": false
20
- },
21
- "textdomain": "{{textDomain}}",
22
- "editorScript": "file:./index.js",
23
- "editorStyle": "file:./index.css",
24
- "style": "file:./style-index.css",
25
- "attributes": {
26
- "content": {
27
- "type": "string",
28
- "default": ""
29
- },
30
- "alignment": {
31
- "type": "string",
32
- "enum": ["left", "center", "right", "justify"],
33
- "default": "left"
34
- },
35
- "className": {
36
- "type": "string",
37
- "default": ""
38
- },
39
- "isVisible": {
40
- "type": "boolean",
41
- "default": true
42
- },
43
- "id": {
44
- "type": "string"
45
- },
46
- "schemaVersion": {
47
- "type": "number",
48
- "default": 1
49
- }
50
- }
51
- }
@@ -1,128 +0,0 @@
1
- /**
2
- * Editor component for {{title}} Block
3
- */
4
-
5
- import { BlockEditProps } from '@wordpress/blocks';
6
- import {
7
- InspectorControls,
8
- RichText,
9
- useBlockProps,
10
- } from '@wordpress/block-editor';
11
- import { Notice, PanelBody, TextControl } from '@wordpress/components';
12
- import { __ } from '@wordpress/i18n';
13
- import currentManifest from './typia.manifest.json';
14
- import {
15
- InspectorFromManifest,
16
- type ManifestDocument,
17
- useEditorFields,
18
- useTypedAttributeUpdater,
19
- } from '@wp-typia/block-runtime/inspector';
20
- import { {{pascalCase}}Attributes } from './types';
21
- import {
22
- sanitize{{pascalCase}}Attributes,
23
- validate{{pascalCase}}Attributes,
24
- } from './validators';
25
- import { useTypiaValidation } from './hooks';
26
-
27
- type EditProps = BlockEditProps<{{pascalCase}}Attributes>;
28
-
29
- function Edit({ attributes, setAttributes }: EditProps) {
30
- const isVisible = attributes.isVisible !== false;
31
- const blockProps = useBlockProps({
32
- className: `{{cssClassName}}${isVisible ? '' : ' is-hidden'}`,
33
- });
34
- const editorFields = useEditorFields(currentManifest as ManifestDocument, {
35
- hidden: ['id', 'schemaVersion'],
36
- manual: ['content'],
37
- labels: {
38
- alignment: __('Alignment', '{{textDomain}}'),
39
- className: __('CSS Class', '{{textDomain}}'),
40
- content: __('Content', '{{textDomain}}'),
41
- isVisible: __('Visible', '{{textDomain}}'),
42
- },
43
- });
44
- const classNameField = editorFields.getField('className');
45
- const { errorMessages, isValid } = useTypiaValidation(
46
- attributes,
47
- validate{{pascalCase}}Attributes
48
- );
49
- const validateEditorUpdate = (nextAttributes: {{pascalCase}}Attributes) => {
50
- try {
51
- return {
52
- data: sanitize{{pascalCase}}Attributes(nextAttributes),
53
- errors: [],
54
- isValid: true as const,
55
- };
56
- } catch {
57
- return validate{{pascalCase}}Attributes(nextAttributes);
58
- }
59
- };
60
- const { updateField } = useTypedAttributeUpdater(
61
- attributes,
62
- setAttributes,
63
- validateEditorUpdate
64
- );
65
-
66
- return (
67
- <>
68
- <InspectorControls>
69
- <InspectorFromManifest
70
- attributes={attributes}
71
- fieldLookup={editorFields}
72
- onChange={updateField}
73
- paths={['alignment', 'isVisible']}
74
- title={__('Settings', '{{textDomain}}')}
75
- >
76
- <TextControl
77
- label={__('Content', '{{textDomain}}')}
78
- value={attributes.content || ''}
79
- onChange={(value) => updateField('content', value)}
80
- help={__('Mirrors the main block content.', '{{textDomain}}')}
81
- />
82
-
83
- <TextControl
84
- label={classNameField?.label || __('CSS Class', '{{textDomain}}')}
85
- value={attributes.className || ''}
86
- onChange={(value) => updateField('className', value)}
87
- help={__('Add an optional CSS class name.', '{{textDomain}}')}
88
- />
89
- </InspectorFromManifest>
90
-
91
- {!isValid && (
92
- <PanelBody title={__('Validation Errors', '{{textDomain}}')} initialOpen>
93
- {errorMessages.map((error, index) => (
94
- <div key={index} style={{ color: '#cc1818', fontSize: '12px' }}>
95
- • {error}
96
- </div>
97
- ))}
98
- </PanelBody>
99
- )}
100
- </InspectorControls>
101
-
102
- <div {...blockProps}>
103
- <div className="{{cssClassName}}__content">
104
- <RichText
105
- tagName="p"
106
- value={attributes.content || ''}
107
- onChange={(value) => updateField('content', value)}
108
- placeholder={__('Add your content...', '{{textDomain}}')}
109
- />
110
- </div>
111
- {!isValid && (
112
- <Notice status="error" isDismissible={false}>
113
- <p>
114
- <strong>{__('Validation Errors', '{{textDomain}}')}</strong>
115
- </p>
116
- <ul style={{ margin: 0, paddingLeft: '1em' }}>
117
- {errorMessages.map((error, index) => (
118
- <li key={index}>{error}</li>
119
- ))}
120
- </ul>
121
- </Notice>
122
- )}
123
- </div>
124
- </>
125
- );
126
- }
127
-
128
- export default Edit;
@@ -1,8 +0,0 @@
1
- /**
2
- * {{title}} Block Editor Styles
3
- */
4
-
5
- .{{cssClassName}} {
6
- outline: 1px dashed #ddd;
7
- outline-offset: -1px;
8
- }
@@ -1,18 +0,0 @@
1
- import { useMemo } from '@wordpress/element';
2
- import {
3
- createUseTypiaValidationHook,
4
- formatValidationError,
5
- formatValidationErrors,
6
- } from '@wp-typia/block-runtime/validation';
7
-
8
- export {
9
- formatValidationError,
10
- formatValidationErrors,
11
- type TypiaValidationError,
12
- type ValidationResult,
13
- type ValidationState,
14
- } from '@wp-typia/block-runtime/validation';
15
-
16
- export const useTypiaValidation = createUseTypiaValidationHook( {
17
- useMemo,
18
- } );
@@ -1,45 +0,0 @@
1
- /**
2
- * WordPress {{title}} Block
3
- *
4
- * Typia-powered type-safe block
5
- */
6
-
7
- import { registerBlockType } from '@wordpress/blocks';
8
- import type { BlockConfiguration } from '@wordpress/blocks';
9
- import type { BlockSupports } from '@wp-typia/block-types/blocks/supports';
10
- import { __ } from '@wordpress/i18n';
11
- import {
12
- buildScaffoldBlockRegistration,
13
- type ScaffoldBlockMetadata,
14
- } from '@wp-typia/block-runtime/blocks';
15
-
16
- // Import components
17
- import Edit from './edit';
18
- import Save from './save';
19
- import metadata from './block.json';
20
- import './editor.scss';
21
- import './style.scss';
22
-
23
- // Import types
24
- import { {{pascalCase}}Attributes } from './types';
25
- import { validators } from './validators';
26
-
27
- const scaffoldSupports = {
28
- html: false,
29
- multiple: true,
30
- align: ['wide', 'full'],
31
- } satisfies BlockSupports;
32
-
33
- // Register the block
34
- const registration = buildScaffoldBlockRegistration<
35
- BlockConfiguration<{{pascalCase}}Attributes>
36
- >(metadata as ScaffoldBlockMetadata, {
37
- supports: scaffoldSupports,
38
- example: {
39
- attributes: validators.random(),
40
- },
41
- edit: Edit,
42
- save: Save,
43
- });
44
-
45
- registerBlockType<{{pascalCase}}Attributes>(registration.name, registration.settings);
@@ -1,19 +0,0 @@
1
- <?php
2
- /**
3
- * Optional server render placeholder for {{title}}.
4
- *
5
- * The basic scaffold stays static by default. Keep `src/save.tsx` as the
6
- * canonical frontend output unless you intentionally convert this block into a
7
- * dynamic render path and add `render` to `block.json`.
8
- *
9
- * @package {{slug}}
10
- */
11
-
12
- if ( ! defined( 'ABSPATH' ) ) {
13
- exit;
14
- }
15
-
16
- ?>
17
- <div class="{{cssClassName}}__server-placeholder" hidden>
18
- <?php esc_html_e( 'Server render placeholder.', '{{textDomain}}' ); ?>
19
- </div>
@@ -1,30 +0,0 @@
1
- /**
2
- * Save/Frontend component for {{title}} Block
3
- */
4
-
5
- import { RichText, useBlockProps } from '@wordpress/block-editor';
6
- import { {{pascalCase}}Attributes } from './types';
7
-
8
- interface SaveProps {
9
- attributes: {{pascalCase}}Attributes;
10
- }
11
-
12
- export default function Save({ attributes }: SaveProps) {
13
- const isVisible = attributes.isVisible !== false;
14
- const blockProps = useBlockProps.save({
15
- className: `{{cssClassName}}${isVisible ? '' : ' is-hidden'}`,
16
- hidden: isVisible ? undefined : true,
17
- 'aria-hidden': isVisible ? undefined : 'true',
18
- });
19
-
20
- return (
21
- <div {...blockProps}>
22
- <div
23
- className="{{cssClassName}}__content"
24
- data-align={attributes.alignment || 'left'}
25
- >
26
- <RichText.Content tagName="p" value={attributes.content} />
27
- </div>
28
- </div>
29
- );
30
- }