@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.
- package/README.md +13 -0
- package/dist/runtime/block-generator-service.d.ts +102 -0
- package/dist/runtime/block-generator-service.js +268 -0
- package/dist/runtime/built-in-block-artifacts.d.ts +37 -0
- package/dist/runtime/built-in-block-artifacts.js +1203 -0
- package/dist/runtime/built-in-block-code-artifacts.d.ts +31 -0
- package/dist/runtime/built-in-block-code-artifacts.js +137 -0
- package/dist/runtime/built-in-block-non-ts-artifacts.d.ts +18 -0
- package/dist/runtime/built-in-block-non-ts-artifacts.js +563 -0
- package/dist/runtime/cli-doctor.js +10 -5
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/scaffold-apply-utils.d.ts +47 -0
- package/dist/runtime/scaffold-apply-utils.js +405 -0
- package/dist/runtime/scaffold-identifiers.d.ts +34 -0
- package/dist/runtime/scaffold-identifiers.js +82 -0
- package/dist/runtime/scaffold.js +33 -0
- package/dist/runtime/starter-manifests.d.ts +3 -2
- package/dist/runtime/starter-manifests.js +15 -365
- package/dist/runtime/template-builtins.d.ts +9 -0
- package/dist/runtime/template-builtins.js +31 -1
- package/dist/runtime/template-render.d.ts +5 -0
- package/dist/runtime/template-render.js +13 -3
- package/dist/runtime/template-source.js +9 -3
- package/package.json +2 -2
- package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +4 -4
- package/templates/_shared/persistence/core/scripts/sync-rest-contracts.ts.mustache +4 -4
- package/templates/_shared/base/src/hooks.ts.mustache +0 -19
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -52
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -123
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/interactivity.ts.mustache +0 -305
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/render.php.mustache +0 -152
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -3
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -61
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -43
- package/templates/_shared/persistence/core/src/index.tsx.mustache +0 -25
- package/templates/_shared/persistence/core/src/interactivity.ts.mustache +0 -308
- package/templates/_shared/persistence/core/src/save.tsx.mustache +0 -5
- package/templates/_shared/persistence/core/src/validators.ts.mustache +0 -43
- package/templates/basic/src/block.json.mustache +0 -51
- package/templates/basic/src/edit.tsx.mustache +0 -128
- package/templates/basic/src/editor.scss.mustache +0 -8
- package/templates/basic/src/hooks.ts.mustache +0 -18
- package/templates/basic/src/index.tsx.mustache +0 -45
- package/templates/basic/src/render.php.mustache +0 -19
- package/templates/basic/src/save.tsx.mustache +0 -30
- package/templates/basic/src/style.scss.mustache +0 -40
- package/templates/basic/src/types.ts.mustache +0 -56
- package/templates/basic/src/validators.ts.mustache +0 -37
- package/templates/compound/src/blocks/{{slugKebabCase}}/block.json.mustache +0 -37
- package/templates/compound/src/blocks/{{slugKebabCase}}/children.ts.mustache +0 -25
- package/templates/compound/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +0 -93
- package/templates/compound/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +0 -11
- package/templates/compound/src/blocks/{{slugKebabCase}}/index.tsx.mustache +0 -25
- package/templates/compound/src/blocks/{{slugKebabCase}}/save.tsx.mustache +0 -32
- package/templates/compound/src/blocks/{{slugKebabCase}}/style.scss.mustache +0 -31
- package/templates/compound/src/blocks/{{slugKebabCase}}/types.ts.mustache +0 -18
- package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +0 -35
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/block.json.mustache +0 -35
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/edit.tsx.mustache +0 -50
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/hooks.ts.mustache +0 -11
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/index.tsx.mustache +0 -25
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/save.tsx.mustache +0 -24
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/types.ts.mustache +0 -17
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +0 -35
- package/templates/interactivity/src/block.json.mustache +0 -74
- package/templates/interactivity/src/edit.tsx.mustache +0 -270
- package/templates/interactivity/src/editor.scss.mustache +0 -8
- package/templates/interactivity/src/index.tsx.mustache +0 -33
- package/templates/interactivity/src/interactivity.ts.mustache +0 -152
- package/templates/interactivity/src/save.tsx.mustache +0 -101
- package/templates/interactivity/src/style.scss.mustache +0 -60
- package/templates/interactivity/src/types.ts.mustache +0 -32
- package/templates/interactivity/src/validators.ts.mustache +0 -47
- package/templates/persistence/src/block.json.mustache +0 -52
- package/templates/persistence/src/edit.tsx.mustache +0 -165
- package/templates/persistence/src/render.php.mustache +0 -120
- package/templates/persistence/src/style.scss.mustache +0 -46
- 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,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,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
|
-
}
|