create-wp-typia 0.1.0
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 +33 -0
- package/dist/cli.js +87837 -0
- package/dist/highlights-eq9cgrbb.scm +604 -0
- package/dist/highlights-ghv9g403.scm +205 -0
- package/dist/highlights-hk7bwhj4.scm +284 -0
- package/dist/highlights-r812a2qc.scm +150 -0
- package/dist/highlights-x6tmsnaa.scm +115 -0
- package/dist/injections-73j83es3.scm +27 -0
- package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/lib/entry.js +29 -0
- package/lib/node-cli.js +326 -0
- package/lib/package-managers.d.ts +29 -0
- package/lib/package-managers.js +170 -0
- package/lib/scaffold.d.ts +64 -0
- package/lib/scaffold.js +565 -0
- package/lib/template-registry.d.ts +18 -0
- package/lib/template-registry.js +58 -0
- package/package.json +64 -0
- package/src/cli.ts +329 -0
- package/templates/advanced/README.md.mustache +70 -0
- package/templates/advanced/block.json.mustache +42 -0
- package/templates/advanced/index.js +21 -0
- package/templates/advanced/package.json.mustache +48 -0
- package/templates/advanced/scripts/generate-migrations.ts.mustache +267 -0
- package/templates/advanced/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/advanced/scripts/migration-cli.ts.mustache +260 -0
- package/templates/advanced/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/advanced/src/admin/migration-dashboard.tsx.mustache +450 -0
- package/templates/advanced/src/components/ErrorBoundary.tsx.mustache +47 -0
- package/templates/advanced/src/deprecated.ts.mustache +184 -0
- package/templates/advanced/src/edit.tsx.mustache +93 -0
- package/templates/advanced/src/hooks/useDebounce.ts.mustache +20 -0
- package/templates/advanced/src/hooks/useLocalStorage.ts.mustache +31 -0
- package/templates/advanced/src/hooks.ts.mustache +56 -0
- package/templates/advanced/src/index.tsx.mustache +16 -0
- package/templates/advanced/src/migration-detector.ts.mustache +417 -0
- package/templates/advanced/src/migrations/index.ts.mustache +361 -0
- package/templates/advanced/src/save.tsx.mustache +40 -0
- package/templates/advanced/src/style.scss.mustache +84 -0
- package/templates/advanced/src/types/versions.ts.mustache +108 -0
- package/templates/advanced/src/types.ts.mustache +45 -0
- package/templates/advanced/src/utils/classnames.ts.mustache +51 -0
- package/templates/advanced/src/utils/debounce.ts.mustache +37 -0
- package/templates/advanced/src/utils/index.ts.mustache +7 -0
- package/templates/advanced/src/utils/uuid.ts.mustache +17 -0
- package/templates/advanced/src/validators.ts.mustache +39 -0
- package/templates/advanced/src/view.ts.mustache +59 -0
- package/templates/advanced/tsconfig.json.mustache +9 -0
- package/templates/advanced/webpack.config.js.mustache +85 -0
- package/templates/basic/package.json.mustache +39 -0
- package/templates/basic/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/basic/scripts/sync-types-to-block-json.ts +25 -0
- package/templates/basic/src/block.json +51 -0
- package/templates/basic/src/edit.tsx +85 -0
- package/templates/basic/src/hooks.ts +75 -0
- package/templates/basic/src/index.tsx +37 -0
- package/templates/basic/src/save.tsx +27 -0
- package/templates/basic/src/style.scss +42 -0
- package/templates/basic/src/types.ts +47 -0
- package/templates/basic/src/validators.ts +39 -0
- package/templates/basic/tsconfig.json +20 -0
- package/templates/basic/webpack.config.js +85 -0
- package/templates/full/package.json.mustache +40 -0
- package/templates/full/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/full/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/full/src/block.json.mustache +121 -0
- package/templates/full/src/edit.tsx.mustache +300 -0
- package/templates/full/src/editor.scss.mustache +251 -0
- package/templates/full/src/hooks.ts.mustache +140 -0
- package/templates/full/src/index.tsx.mustache +27 -0
- package/templates/full/src/save.tsx.mustache +39 -0
- package/templates/full/src/style.scss.mustache +224 -0
- package/templates/full/src/types.ts.mustache +34 -0
- package/templates/full/src/validators.ts.mustache +84 -0
- package/templates/full/tsconfig.json.mustache +9 -0
- package/templates/full/webpack.config.js.mustache +85 -0
- package/templates/interactivity/package.json.mustache +41 -0
- package/templates/interactivity/scripts/lib/typia-metadata-core.ts +806 -0
- package/templates/interactivity/scripts/sync-types-to-block-json.ts.mustache +25 -0
- package/templates/interactivity/src/block.json.mustache +75 -0
- package/templates/interactivity/src/edit.tsx.mustache +206 -0
- package/templates/interactivity/src/interactivity.ts.mustache +183 -0
- package/templates/interactivity/src/save.tsx.mustache +87 -0
- package/templates/interactivity/src/types.ts.mustache +29 -0
- package/templates/interactivity/tsconfig.json.mustache +9 -0
- package/templates/interactivity/webpack.config.js.mustache +85 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import typia from "typia";
|
|
2
|
+
import {
|
|
3
|
+
{{titleCase}}AttributesV1,
|
|
4
|
+
{{titleCase}}AttributesV2,
|
|
5
|
+
{{titleCase}}AttributesV3,
|
|
6
|
+
{{titleCase}}Attributes,
|
|
7
|
+
BLOCK_VERSIONS
|
|
8
|
+
} from '../types/versions';
|
|
9
|
+
import { generateUUID } from '../utils';
|
|
10
|
+
|
|
11
|
+
export interface MigrationContext {
|
|
12
|
+
originalAttributes: any;
|
|
13
|
+
timestamp: string;
|
|
14
|
+
migrationPath: string[];
|
|
15
|
+
rollbackPossible: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MigrationResult<T> {
|
|
19
|
+
data: T;
|
|
20
|
+
context: MigrationContext;
|
|
21
|
+
rollback: () => any;
|
|
22
|
+
success: boolean;
|
|
23
|
+
error?: Error;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Migration functions for {{title}} block versions
|
|
28
|
+
*/
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Migration functions for {{title}} block versions
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// V1 → V2 Migration
|
|
35
|
+
export function migrateV1ToV2(v1Attrs: {{titleCase}}AttributesV1): MigrationResult<{{titleCase}}AttributesV2> {
|
|
36
|
+
console.log('🔄 Migrating {{title}} from v1 to v2');
|
|
37
|
+
console.log('📄 V1 attributes:', JSON.stringify(v1Attrs, null, 2));
|
|
38
|
+
|
|
39
|
+
const migrated: {{titleCase}}AttributesV2 = {
|
|
40
|
+
content: v1Attrs.content || "",
|
|
41
|
+
alignment: v1Attrs.alignment || "left",
|
|
42
|
+
// New fields with defaults
|
|
43
|
+
isVisible: true,
|
|
44
|
+
className: undefined
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
console.log('🔧 Adding new fields: isVisible=true, className=undefined');
|
|
48
|
+
|
|
49
|
+
// Validate migrated data
|
|
50
|
+
const validation = typia.validate<{{titleCase}}AttributesV2>(migrated);
|
|
51
|
+
if (!validation.success) {
|
|
52
|
+
const error = new Error('V1→V2 migration validation failed');
|
|
53
|
+
console.error('❌ V1→V2 migration validation failed:', validation.errors);
|
|
54
|
+
return {
|
|
55
|
+
data: null,
|
|
56
|
+
context: {
|
|
57
|
+
originalAttributes: v1Attrs,
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
migrationPath: ['V1', 'V2'],
|
|
60
|
+
rollbackPossible: false
|
|
61
|
+
},
|
|
62
|
+
rollback: () => v1Attrs,
|
|
63
|
+
success: false,
|
|
64
|
+
error
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log('✅ V1→V2 migration successful');
|
|
69
|
+
console.log('📄 V2 attributes:', JSON.stringify(migrated, null, 2));
|
|
70
|
+
|
|
71
|
+
// Create rollback function
|
|
72
|
+
const rollback = (): {{titleCase}}AttributesV1 => {
|
|
73
|
+
return {
|
|
74
|
+
content: migrated.content,
|
|
75
|
+
alignment: migrated.alignment
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
data: migrated,
|
|
81
|
+
context: {
|
|
82
|
+
originalAttributes: v1Attrs,
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
migrationPath: ['V1', 'V2'],
|
|
85
|
+
rollbackPossible: true
|
|
86
|
+
},
|
|
87
|
+
rollback,
|
|
88
|
+
success: true
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// V2 → V3 Migration
|
|
93
|
+
export function migrateV2ToV3(v2Attrs: {{titleCase}}AttributesV2): MigrationResult<{{titleCase}}AttributesV3> {
|
|
94
|
+
console.log('🔄 Migrating {{title}} from v2 to v3');
|
|
95
|
+
console.log('📄 V2 attributes:', JSON.stringify(v2Attrs, null, 2));
|
|
96
|
+
|
|
97
|
+
const migrated: {{titleCase}}AttributesV3 = {
|
|
98
|
+
// New fields
|
|
99
|
+
id: generateUUID(),
|
|
100
|
+
version: 3,
|
|
101
|
+
theme: "default",
|
|
102
|
+
|
|
103
|
+
// Existing fields with potential updates
|
|
104
|
+
content: v2Attrs.content || "",
|
|
105
|
+
alignment: v2Attrs.alignment || "left",
|
|
106
|
+
isVisible: v2Attrs.isVisible ?? true,
|
|
107
|
+
|
|
108
|
+
// Handle className validation change
|
|
109
|
+
className: v2Attrs.className && /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(v2Attrs.className)
|
|
110
|
+
? v2Attrs.className.slice(0, 50) // Trim to new max length
|
|
111
|
+
: undefined
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
console.log('🔧 Adding new fields:');
|
|
115
|
+
console.log(' - id:', migrated.id);
|
|
116
|
+
console.log(' - version:', migrated.version);
|
|
117
|
+
console.log(' - theme:', migrated.theme);
|
|
118
|
+
|
|
119
|
+
if (v2Attrs.className && !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(v2Attrs.className)) {
|
|
120
|
+
console.log('⚠️ Invalid className format, setting to undefined');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (v2Attrs.className && v2Attrs.className.length > 50) {
|
|
124
|
+
console.log('✂️ Trimming className from', v2Attrs.className.length, 'to 50 characters');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Validate migrated data
|
|
128
|
+
const validation = typia.validate<{{titleCase}}AttributesV3>(migrated);
|
|
129
|
+
if (!validation.success) {
|
|
130
|
+
const error = new Error('V2→V3 migration validation failed');
|
|
131
|
+
console.error('❌ V2→V3 migration validation failed:', validation.errors);
|
|
132
|
+
return {
|
|
133
|
+
data: null,
|
|
134
|
+
context: {
|
|
135
|
+
originalAttributes: v2Attrs,
|
|
136
|
+
timestamp: new Date().toISOString(),
|
|
137
|
+
migrationPath: ['V2', 'V3'],
|
|
138
|
+
rollbackPossible: false
|
|
139
|
+
},
|
|
140
|
+
rollback: () => v2Attrs,
|
|
141
|
+
success: false,
|
|
142
|
+
error
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('✅ V2→V3 migration successful');
|
|
147
|
+
console.log('📄 V3 attributes:', JSON.stringify(migrated, null, 2));
|
|
148
|
+
|
|
149
|
+
// Create rollback function
|
|
150
|
+
const rollback = (): {{titleCase}}AttributesV2 => {
|
|
151
|
+
return {
|
|
152
|
+
content: migrated.content,
|
|
153
|
+
alignment: migrated.alignment,
|
|
154
|
+
isVisible: migrated.isVisible,
|
|
155
|
+
className: migrated.className
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
data: migrated,
|
|
161
|
+
context: {
|
|
162
|
+
originalAttributes: v2Attrs,
|
|
163
|
+
timestamp: new Date().toISOString(),
|
|
164
|
+
migrationPath: ['V2', 'V3'],
|
|
165
|
+
rollbackPossible: true
|
|
166
|
+
},
|
|
167
|
+
rollback,
|
|
168
|
+
success: true
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Auto-detect version and migrate to current
|
|
174
|
+
*/
|
|
175
|
+
export function autoMigrate(attributes: any): MigrationResult<{{titleCase}}Attributes> {
|
|
176
|
+
// Try to detect version
|
|
177
|
+
const detectedVersion = detectVersion(attributes);
|
|
178
|
+
console.log(`🔍 Detected {{title}} version: ${detectedVersion}`);
|
|
179
|
+
|
|
180
|
+
switch (detectedVersion) {
|
|
181
|
+
case "1.0.0": {
|
|
182
|
+
// V1 → V2 → V3
|
|
183
|
+
const v2Result = migrateV1ToV2(attributes as {{titleCase}}AttributesV1);
|
|
184
|
+
if (!v2Result.success) {
|
|
185
|
+
return v2Result;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const v3Result = migrateV2ToV3(v2Result.data);
|
|
189
|
+
if (!v3Result.success) {
|
|
190
|
+
// If V3 migration fails, we still have the V2 data
|
|
191
|
+
return {
|
|
192
|
+
...v3Result,
|
|
193
|
+
data: v2Result.data as unknown as {{titleCase}}Attributes,
|
|
194
|
+
context: {
|
|
195
|
+
...v3Result.context,
|
|
196
|
+
migrationPath: [...v2Result.context.migrationPath, ...v3Result.context.migrationPath]
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
...v3Result,
|
|
203
|
+
context: {
|
|
204
|
+
...v3Result.context,
|
|
205
|
+
migrationPath: [...v2Result.context.migrationPath, ...v3Result.context.migrationPath],
|
|
206
|
+
originalAttributes: attributes
|
|
207
|
+
},
|
|
208
|
+
rollback: () => attributes
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
case "2.0.0": {
|
|
214
|
+
// V2 → V3
|
|
215
|
+
const v3Result = migrateV2ToV3(attributes as {{titleCase}}AttributesV2);
|
|
216
|
+
if (!v3Result.success) {
|
|
217
|
+
return v3Result;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
...v3Result,
|
|
222
|
+
context: {
|
|
223
|
+
...v3Result.context,
|
|
224
|
+
migrationPath: ['V2', 'V3'],
|
|
225
|
+
originalAttributes: attributes
|
|
226
|
+
},
|
|
227
|
+
rollback: () => attributes
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
case "3.0.0": {
|
|
233
|
+
// Already current version
|
|
234
|
+
console.log('✅ {{title}} already at current version');
|
|
235
|
+
return {
|
|
236
|
+
data: attributes as {{titleCase}}AttributesV3,
|
|
237
|
+
context: {
|
|
238
|
+
originalAttributes: attributes,
|
|
239
|
+
timestamp: new Date().toISOString(),
|
|
240
|
+
migrationPath: ['V3'],
|
|
241
|
+
rollbackPossible: true
|
|
242
|
+
},
|
|
243
|
+
rollback: () => attributes,
|
|
244
|
+
success: true
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
default: {
|
|
250
|
+
console.warn('⚠️ Unknown {{title}} version, attempting best-effort migration');
|
|
251
|
+
return attemptBestEffortMigration(attributes);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Detect block version based on structure
|
|
259
|
+
*/
|
|
260
|
+
function detectVersion(attributes: any): string {
|
|
261
|
+
// Check for V3 features
|
|
262
|
+
if ('id' in attributes || 'version' in attributes || 'theme' in attributes) {
|
|
263
|
+
return "3.0.0";
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check for V2 features
|
|
267
|
+
if ('isVisible' in attributes || 'className' in attributes) {
|
|
268
|
+
return "2.0.0";
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Must be V1
|
|
272
|
+
return "1.0.0";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Best-effort migration for unknown versions
|
|
277
|
+
*/
|
|
278
|
+
function attemptBestEffortMigration(attributes: any): MigrationResult<{{titleCase}}Attributes> {
|
|
279
|
+
console.log('🔧 Attempting best-effort migration');
|
|
280
|
+
|
|
281
|
+
const migrated: {{titleCase}}Attributes = {
|
|
282
|
+
id: generateUUID(),
|
|
283
|
+
version: 3,
|
|
284
|
+
content: String(attributes.content || ""),
|
|
285
|
+
alignment: ["left", "center", "right", "justify"].includes(attributes.alignment)
|
|
286
|
+
? attributes.alignment
|
|
287
|
+
: "left",
|
|
288
|
+
isVisible: Boolean(attributes.isVisible ?? true),
|
|
289
|
+
className: typeof attributes.className === 'string'
|
|
290
|
+
? attributes.className.slice(0, 50)
|
|
291
|
+
: undefined,
|
|
292
|
+
theme: ["default", "dark", "light", "accent"].includes(attributes.theme)
|
|
293
|
+
? attributes.theme
|
|
294
|
+
: "default"
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Final validation
|
|
298
|
+
const validation = typia.validate<{{titleCase}}Attributes>(migrated);
|
|
299
|
+
if (!validation.success) {
|
|
300
|
+
const error = new Error('Best-effort migration validation failed');
|
|
301
|
+
console.error('❌ Best-effort migration failed:', validation.errors);
|
|
302
|
+
// Return minimal valid structure
|
|
303
|
+
return {
|
|
304
|
+
data: null,
|
|
305
|
+
context: {
|
|
306
|
+
originalAttributes: attributes,
|
|
307
|
+
timestamp: new Date().toISOString(),
|
|
308
|
+
migrationPath: ['BestEffort'],
|
|
309
|
+
rollbackPossible: false
|
|
310
|
+
},
|
|
311
|
+
rollback: () => attributes,
|
|
312
|
+
success: false,
|
|
313
|
+
error
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
console.log('✅ Best-effort migration successful');
|
|
318
|
+
return {
|
|
319
|
+
data: migrated,
|
|
320
|
+
context: {
|
|
321
|
+
originalAttributes: attributes,
|
|
322
|
+
timestamp: new Date().toISOString(),
|
|
323
|
+
migrationPath: ['BestEffort'],
|
|
324
|
+
rollbackPossible: true
|
|
325
|
+
},
|
|
326
|
+
rollback: () => attributes,
|
|
327
|
+
success: true
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Generate migration report
|
|
333
|
+
*/
|
|
334
|
+
export function generateMigrationReport(oldAttrs: any, newAttrs: {{titleCase}}Attributes) {
|
|
335
|
+
const report = {
|
|
336
|
+
timestamp: new Date().toISOString(),
|
|
337
|
+
fromVersion: detectVersion(oldAttrs),
|
|
338
|
+
toVersion: "3.0.0",
|
|
339
|
+
changes: [] as string[],
|
|
340
|
+
warnings: [] as string[]
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// Detect changes
|
|
344
|
+
if (!oldAttrs.id && newAttrs.id) {
|
|
345
|
+
report.changes.push('Added unique ID');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (!oldAttrs.version && newAttrs.version) {
|
|
349
|
+
report.changes.push('Added version tracking');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!oldAttrs.theme && newAttrs.theme) {
|
|
353
|
+
report.changes.push('Added theme support');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (oldAttrs.content !== newAttrs.content) {
|
|
357
|
+
report.warnings.push('Content may have been modified during migration');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return report;
|
|
361
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useBlockProps } from '@wordpress/block-editor';
|
|
2
|
+
import { {{titleCase}}Attributes } from './types';
|
|
3
|
+
|
|
4
|
+
interface SaveProps {
|
|
5
|
+
attributes: {{titleCase}}Attributes;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function Save({ attributes }: SaveProps) {
|
|
9
|
+
const blockProps = useBlockProps.save();
|
|
10
|
+
|
|
11
|
+
if (!attributes.isVisible) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
{...blockProps}
|
|
18
|
+
data-wp-interactive="{{namespace}}/{{slug}}"
|
|
19
|
+
data-wp-context={JSON.stringify({
|
|
20
|
+
content: attributes.content,
|
|
21
|
+
alignment: attributes.alignment
|
|
22
|
+
})}
|
|
23
|
+
>
|
|
24
|
+
<p
|
|
25
|
+
style={{ textAlign: attributes.alignment ?? 'left' }}
|
|
26
|
+
data-wp-bind--hidden="!state.isVisible"
|
|
27
|
+
data-wp-text="context.content"
|
|
28
|
+
>
|
|
29
|
+
{attributes.content}
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
<button
|
|
33
|
+
data-wp-on--click="actions.toggle"
|
|
34
|
+
data-wp-class--active="state.isActive"
|
|
35
|
+
>
|
|
36
|
+
Toggle
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{title}} Block Styles
|
|
3
|
+
* Generated with Typia validation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.wp-block-{{slugKebabCase}} {
|
|
7
|
+
/* Default block styles */
|
|
8
|
+
padding: 1rem;
|
|
9
|
+
margin: 1rem 0;
|
|
10
|
+
|
|
11
|
+
/* Alignment support */
|
|
12
|
+
&.has-text-align-left {
|
|
13
|
+
text-align: left;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&.has-text-align-center {
|
|
17
|
+
text-align: center;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.has-text-align-right {
|
|
21
|
+
text-align: right;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.has-text-align-justify {
|
|
25
|
+
text-align: justify;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Interactive states */
|
|
29
|
+
button {
|
|
30
|
+
background: #0073aa;
|
|
31
|
+
color: white;
|
|
32
|
+
border: none;
|
|
33
|
+
padding: 0.5rem 1rem;
|
|
34
|
+
border-radius: 4px;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: all 0.2s ease;
|
|
37
|
+
|
|
38
|
+
&:hover {
|
|
39
|
+
background: #005a87;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&.active {
|
|
43
|
+
background: #00a32a;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Validation error display */
|
|
48
|
+
.block-error {
|
|
49
|
+
background: #f8d7da;
|
|
50
|
+
color: #721c24;
|
|
51
|
+
padding: 0.75rem;
|
|
52
|
+
border-radius: 4px;
|
|
53
|
+
margin-bottom: 1rem;
|
|
54
|
+
border: 1px solid #f5c6cb;
|
|
55
|
+
|
|
56
|
+
pre {
|
|
57
|
+
background: rgba(0, 0, 0, 0.05);
|
|
58
|
+
padding: 0.5rem;
|
|
59
|
+
border-radius: 2px;
|
|
60
|
+
font-size: 0.8rem;
|
|
61
|
+
margin: 0.5rem 0 0 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Block info */
|
|
66
|
+
.block-info {
|
|
67
|
+
font-size: 0.9rem;
|
|
68
|
+
color: #666;
|
|
69
|
+
font-style: italic;
|
|
70
|
+
margin-top: 0.5rem;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Editor-specific styles */
|
|
75
|
+
.wp-block[data-type="{{namespace}}/{{slug}}"] {
|
|
76
|
+
.wp-block-{{slugKebabCase}} {
|
|
77
|
+
border: 1px dashed #ddd;
|
|
78
|
+
border-radius: 4px;
|
|
79
|
+
|
|
80
|
+
&:hover {
|
|
81
|
+
border-color: #0073aa;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { tags } from "typia";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Versioned {{title}} attributes with migration support
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Version 1.0.0 - Initial version
|
|
8
|
+
export interface {{titleCase}}AttributesV1 {
|
|
9
|
+
/**
|
|
10
|
+
* Simple content field
|
|
11
|
+
*/
|
|
12
|
+
content: string & tags.Default<"">;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Basic alignment
|
|
16
|
+
*/
|
|
17
|
+
alignment?: ("left" | "center" | "right") & tags.Default<"left">;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Version 2.0.0 - Added visibility and className
|
|
21
|
+
export interface {{titleCase}}AttributesV2 {
|
|
22
|
+
/**
|
|
23
|
+
* Enhanced content with length validation
|
|
24
|
+
*/
|
|
25
|
+
content: string & tags.MinLength<0> & tags.MaxLength<1000> & tags.Default<"">;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extended alignment options
|
|
29
|
+
*/
|
|
30
|
+
alignment?: ("left" | "center" | "right" | "justify") & tags.Default<"left">;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Visibility toggle - NEW in v2
|
|
34
|
+
*/
|
|
35
|
+
isVisible?: boolean & tags.Default<true>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Custom CSS class - NEW in v2
|
|
39
|
+
*/
|
|
40
|
+
className?: string & tags.MaxLength<100>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Version 3.0.0 - Current version with ID and version tracking
|
|
44
|
+
export interface {{titleCase}}AttributesV3 {
|
|
45
|
+
/**
|
|
46
|
+
* Unique identifier - NEW in v3
|
|
47
|
+
*/
|
|
48
|
+
id?: string & tags.Format<"uuid">;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Version tracking - NEW in v3
|
|
52
|
+
*/
|
|
53
|
+
version?: number & tags.Type<"uint32"> & tags.Default<3>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Enhanced content with better validation
|
|
57
|
+
*/
|
|
58
|
+
content: string & tags.MinLength<0> & tags.MaxLength<2000> & tags.Default<"">;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Extended alignment options
|
|
62
|
+
*/
|
|
63
|
+
alignment?: ("left" | "center" | "right" | "justify") & tags.Default<"left">;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Visibility toggle
|
|
67
|
+
*/
|
|
68
|
+
isVisible?: boolean & tags.Default<true>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Custom CSS class with better validation
|
|
72
|
+
*/
|
|
73
|
+
className?: string & tags.Pattern<"^[a-zA-Z][a-zA-Z0-9_-]*$"> & tags.MaxLength<50>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Theme support - NEW in v3
|
|
77
|
+
*/
|
|
78
|
+
theme?: ("default" | "dark" | "light" | "accent") & tags.Default<"default">;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Current version type alias
|
|
82
|
+
export type {{titleCase}}Attributes = {{titleCase}}AttributesV3;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Version history and metadata
|
|
86
|
+
*/
|
|
87
|
+
export const BLOCK_VERSIONS = {
|
|
88
|
+
"1.0.0": {
|
|
89
|
+
version: 1,
|
|
90
|
+
type: "{{titleCase}}AttributesV1",
|
|
91
|
+
deprecated: true,
|
|
92
|
+
breaking: false,
|
|
93
|
+
},
|
|
94
|
+
"2.0.0": {
|
|
95
|
+
version: 2,
|
|
96
|
+
type: "{{titleCase}}AttributesV2",
|
|
97
|
+
deprecated: true,
|
|
98
|
+
breaking: true, // Added new required structure
|
|
99
|
+
},
|
|
100
|
+
"3.0.0": {
|
|
101
|
+
version: 3,
|
|
102
|
+
type: "{{titleCase}}AttributesV3",
|
|
103
|
+
deprecated: false,
|
|
104
|
+
breaking: true, // Changed content max length
|
|
105
|
+
}
|
|
106
|
+
} as const;
|
|
107
|
+
|
|
108
|
+
export type BlockVersion = keyof typeof BLOCK_VERSIONS;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { tags } from "typia";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* {{title}} block attributes with Typia validation
|
|
5
|
+
*/
|
|
6
|
+
export interface {{titleCase}}Attributes {
|
|
7
|
+
/**
|
|
8
|
+
* Unique identifier
|
|
9
|
+
*/
|
|
10
|
+
id?: string & tags.Format<"uuid">;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Block version for migrations
|
|
14
|
+
*/
|
|
15
|
+
version?: number & tags.Type<"uint32"> & tags.Default<1>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Custom CSS class
|
|
19
|
+
*/
|
|
20
|
+
className?: string & tags.MaxLength<100>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Main content
|
|
24
|
+
*/
|
|
25
|
+
content: string & tags.MinLength<0> & tags.MaxLength<1000> & tags.Default<"">;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Text alignment
|
|
29
|
+
*/
|
|
30
|
+
alignment?: ("left" | "center" | "right" | "justify") & tags.Default<"left">;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Is the block visible
|
|
34
|
+
*/
|
|
35
|
+
isVisible?: boolean & tags.Default<true>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* {{title}} interactivity state
|
|
40
|
+
*/
|
|
41
|
+
export interface {{titleCase}}State {
|
|
42
|
+
isActive: boolean;
|
|
43
|
+
isLoading: boolean;
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional classnames utility
|
|
3
|
+
*/
|
|
4
|
+
export function classNames(...args: (string | Record<string, boolean> | undefined | null | false)[]): string {
|
|
5
|
+
const classes: string[] = [];
|
|
6
|
+
|
|
7
|
+
for (const arg of args) {
|
|
8
|
+
if (!arg) continue;
|
|
9
|
+
|
|
10
|
+
if (typeof arg === 'string') {
|
|
11
|
+
classes.push(arg);
|
|
12
|
+
} else if (typeof arg === 'object') {
|
|
13
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
14
|
+
if (value) {
|
|
15
|
+
classes.push(key);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return classes.join(' ');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generate block class with BEM methodology
|
|
26
|
+
*/
|
|
27
|
+
export function blockClass(
|
|
28
|
+
blockName: string,
|
|
29
|
+
element?: string,
|
|
30
|
+
modifier?: string | Record<string, boolean>
|
|
31
|
+
): string {
|
|
32
|
+
let className = blockName;
|
|
33
|
+
|
|
34
|
+
if (element) {
|
|
35
|
+
className += `__${element}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (modifier) {
|
|
39
|
+
if (typeof modifier === 'string') {
|
|
40
|
+
className += `--${modifier}`;
|
|
41
|
+
} else {
|
|
42
|
+
for (const [mod, enabled] of Object.entries(modifier)) {
|
|
43
|
+
if (enabled) {
|
|
44
|
+
className += `--${mod}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return className;
|
|
51
|
+
}
|