@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.
- package/README.md +11 -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 +30 -0
- package/dist/runtime/built-in-block-code-artifacts.js +122 -0
- 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-render.d.ts +5 -0
- package/dist/runtime/template-render.js +13 -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}}/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/index.tsx.mustache +0 -45
- package/templates/basic/src/save.tsx.mustache +0 -30
- 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}}/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/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/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/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,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>;
|