@wp-typia/project-tools 0.16.2 → 0.16.4

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 (64) hide show
  1. package/README.md +11 -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 +30 -0
  7. package/dist/runtime/built-in-block-code-artifacts.js +122 -0
  8. package/dist/runtime/index.d.ts +2 -0
  9. package/dist/runtime/index.js +1 -0
  10. package/dist/runtime/scaffold-apply-utils.d.ts +47 -0
  11. package/dist/runtime/scaffold-apply-utils.js +405 -0
  12. package/dist/runtime/scaffold-identifiers.d.ts +34 -0
  13. package/dist/runtime/scaffold-identifiers.js +82 -0
  14. package/dist/runtime/scaffold.js +33 -0
  15. package/dist/runtime/starter-manifests.d.ts +3 -2
  16. package/dist/runtime/starter-manifests.js +15 -365
  17. package/dist/runtime/template-render.d.ts +5 -0
  18. package/dist/runtime/template-render.js +13 -3
  19. package/package.json +2 -2
  20. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +4 -4
  21. package/templates/_shared/persistence/core/scripts/sync-rest-contracts.ts.mustache +4 -4
  22. package/templates/_shared/base/src/hooks.ts.mustache +0 -19
  23. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -52
  24. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -123
  25. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
  26. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/interactivity.ts.mustache +0 -305
  27. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -3
  28. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -61
  29. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -43
  30. package/templates/_shared/persistence/core/src/index.tsx.mustache +0 -25
  31. package/templates/_shared/persistence/core/src/interactivity.ts.mustache +0 -308
  32. package/templates/_shared/persistence/core/src/save.tsx.mustache +0 -5
  33. package/templates/_shared/persistence/core/src/validators.ts.mustache +0 -43
  34. package/templates/basic/src/block.json.mustache +0 -51
  35. package/templates/basic/src/edit.tsx.mustache +0 -128
  36. package/templates/basic/src/index.tsx.mustache +0 -45
  37. package/templates/basic/src/save.tsx.mustache +0 -30
  38. package/templates/basic/src/types.ts.mustache +0 -56
  39. package/templates/basic/src/validators.ts.mustache +0 -37
  40. package/templates/compound/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -37
  41. package/templates/compound/src/blocks/{{slugKebabCase}}/children.ts.mustache +0 -25
  42. package/templates/compound/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -93
  43. package/templates/compound/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
  44. package/templates/compound/src/blocks/{{slugKebabCase}}/index.tsx.mustache +0 -25
  45. package/templates/compound/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -32
  46. package/templates/compound/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -18
  47. package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -35
  48. package/templates/compound/src/blocks/{{slugKebabCase}}-item/block.json.mustache +0 -35
  49. package/templates/compound/src/blocks/{{slugKebabCase}}-item/edit.tsx.mustache +0 -50
  50. package/templates/compound/src/blocks/{{slugKebabCase}}-item/hooks.ts.mustache +0 -11
  51. package/templates/compound/src/blocks/{{slugKebabCase}}-item/index.tsx.mustache +0 -25
  52. package/templates/compound/src/blocks/{{slugKebabCase}}-item/save.tsx.mustache +0 -24
  53. package/templates/compound/src/blocks/{{slugKebabCase}}-item/types.ts.mustache +0 -17
  54. package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +0 -35
  55. package/templates/interactivity/src/block.json.mustache +0 -74
  56. package/templates/interactivity/src/edit.tsx.mustache +0 -270
  57. package/templates/interactivity/src/index.tsx.mustache +0 -33
  58. package/templates/interactivity/src/interactivity.ts.mustache +0 -152
  59. package/templates/interactivity/src/save.tsx.mustache +0 -101
  60. package/templates/interactivity/src/types.ts.mustache +0 -32
  61. package/templates/interactivity/src/validators.ts.mustache +0 -47
  62. package/templates/persistence/src/block.json.mustache +0 -52
  63. package/templates/persistence/src/edit.tsx.mustache +0 -165
  64. package/templates/persistence/src/types.ts.mustache +0 -59
@@ -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,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,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
- }
@@ -1,56 +0,0 @@
1
- import type { TextAlignment } from "@wp-typia/block-types/block-editor/alignment";
2
- import type {
3
- TypiaValidationError,
4
- ValidationResult,
5
- } from "@wp-typia/block-runtime/validation";
6
- import { tags } from "typia";
7
-
8
- export type { TypiaValidationError, ValidationResult } from "@wp-typia/block-runtime/validation";
9
-
10
- /**
11
- * Block attributes interface
12
- * Typia tags define runtime validation rules
13
- */
14
- export interface {{pascalCase}}Attributes {
15
- /**
16
- * Main block content
17
- */
18
- content: string &
19
- tags.MinLength<1> &
20
- tags.MaxLength<1000> &
21
- tags.Default<"">;
22
-
23
- /**
24
- * Alignment
25
- */
26
- alignment?: TextAlignment &
27
- tags.Default<"left">;
28
-
29
- /**
30
- * Visibility toggle
31
- */
32
- isVisible?: boolean &
33
- tags.Default<true>;
34
-
35
- /**
36
- * Custom CSS class
37
- */
38
- className?: string &
39
- tags.MaxLength<100> &
40
- tags.Default<"">;
41
-
42
- /**
43
- * Generated runtime ID
44
- */
45
- id?: string &
46
- tags.Format<"uuid">;
47
-
48
- /**
49
- * Block version for migrations
50
- */
51
- schemaVersion?: number &
52
- tags.Type<"uint32"> &
53
- tags.Default<1>;
54
- }
55
-
56
- export type {{pascalCase}}ValidationResult = ValidationResult<{{pascalCase}}Attributes>;