@times-design-system/components-wordpress 0.4.0 → 0.7.2-alpha.2

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 (189) hide show
  1. package/BLOCK_CREATION_CHECKLIST.md +160 -0
  2. package/BUILD.md +411 -0
  3. package/CHANGELOG.md +22 -0
  4. package/LICENSE +29 -0
  5. package/README.md +972 -5
  6. package/TRANSFORMATION_GUIDE.md +635 -0
  7. package/block.json +10 -0
  8. package/dist/block.json +10 -0
  9. package/dist/blocks/ad-container/block.json +28 -0
  10. package/dist/blocks/ad-container/edit.js +42 -0
  11. package/dist/blocks/ad-container/index.js +10 -0
  12. package/dist/blocks/ad-container/save.js +16 -0
  13. package/dist/blocks/ad-container/style-editor.css +4 -0
  14. package/dist/blocks/ad-container/style.css +27 -0
  15. package/dist/blocks/button/block.json +89 -0
  16. package/dist/blocks/button/edit.js +187 -0
  17. package/dist/blocks/button/index.js +11 -0
  18. package/dist/blocks/button/save.js +52 -0
  19. package/dist/blocks/button/style-editor.css +15 -0
  20. package/dist/blocks/button/style.css +37 -0
  21. package/dist/blocks/chip/block.json +57 -0
  22. package/dist/blocks/chip/edit.js +113 -0
  23. package/dist/blocks/chip/index.js +10 -0
  24. package/dist/blocks/chip/save.js +36 -0
  25. package/dist/blocks/chip/style-editor.css +5 -0
  26. package/dist/blocks/chip/style.css +48 -0
  27. package/dist/blocks/divider/block.json +31 -0
  28. package/dist/blocks/divider/edit.js +42 -0
  29. package/dist/blocks/divider/index.js +10 -0
  30. package/dist/blocks/divider/save.js +18 -0
  31. package/dist/blocks/divider/style-editor.css +4 -0
  32. package/dist/blocks/divider/style.css +25 -0
  33. package/dist/blocks/flag/block.json +48 -0
  34. package/dist/blocks/flag/edit.js +82 -0
  35. package/dist/blocks/flag/index.js +10 -0
  36. package/dist/blocks/flag/save.js +25 -0
  37. package/dist/blocks/flag/style-editor.css +5 -0
  38. package/dist/blocks/flag/style.css +45 -0
  39. package/dist/blocks/icon-button/block.json +43 -0
  40. package/dist/blocks/icon-button/edit.js +82 -0
  41. package/dist/blocks/icon-button/index.js +10 -0
  42. package/dist/blocks/icon-button/save.js +29 -0
  43. package/dist/blocks/icon-button/style-editor.css +5 -0
  44. package/dist/blocks/icon-button/style.css +32 -0
  45. package/dist/blocks/input/block.json +47 -0
  46. package/dist/blocks/input/edit.js +78 -0
  47. package/dist/blocks/input/index.js +10 -0
  48. package/dist/blocks/input/save.js +27 -0
  49. package/dist/blocks/input/style-editor.css +8 -0
  50. package/dist/blocks/input/style.css +30 -0
  51. package/dist/blocks/link/block.json +71 -0
  52. package/dist/blocks/link/edit.js +151 -0
  53. package/dist/blocks/link/index.js +10 -0
  54. package/dist/blocks/link/save.js +46 -0
  55. package/dist/blocks/link/style-editor.css +5 -0
  56. package/dist/blocks/link/style.css +66 -0
  57. package/dist/blocks/text/block.json +32 -0
  58. package/dist/blocks/text/edit.js +56 -0
  59. package/dist/blocks/text/index.js +10 -0
  60. package/dist/blocks/text/save.js +18 -0
  61. package/dist/blocks/text/style-editor.css +4 -0
  62. package/dist/blocks/text/style.css +20 -0
  63. package/dist/blocks/toast/block.json +39 -0
  64. package/dist/blocks/toast/edit.js +85 -0
  65. package/dist/blocks/toast/index.js +10 -0
  66. package/dist/blocks/toast/save.js +29 -0
  67. package/dist/blocks/toast/style-editor.css +4 -0
  68. package/dist/blocks/toast/style.css +51 -0
  69. package/dist/index.cjs +2232 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.css +2 -0
  72. package/dist/index.css.map +1 -0
  73. package/dist/index.js +2196 -255
  74. package/dist/index.js.map +1 -1
  75. package/dist/plugin.php +79 -0
  76. package/dist/utils/classBuilder.js +53 -0
  77. package/package.json +39 -7
  78. package/plugin.php +79 -0
  79. package/rollup.config.js +39 -22
  80. package/scripts/build-plugin.cjs +121 -0
  81. package/scripts/create-block.sh +141 -0
  82. package/src/blocks/ad-container/block.json +28 -0
  83. package/src/blocks/ad-container/edit.js +42 -0
  84. package/src/blocks/ad-container/index.js +10 -0
  85. package/src/blocks/ad-container/save.js +16 -0
  86. package/src/blocks/ad-container/style-editor.css +4 -0
  87. package/src/blocks/ad-container/style.css +27 -0
  88. package/src/blocks/button/block.json +89 -0
  89. package/src/blocks/button/edit.js +187 -0
  90. package/src/blocks/button/index.js +11 -0
  91. package/src/blocks/button/save.js +52 -0
  92. package/src/blocks/button/style-editor.css +15 -0
  93. package/src/blocks/button/style.css +37 -0
  94. package/src/blocks/chip/block.json +57 -0
  95. package/src/blocks/chip/edit.js +113 -0
  96. package/src/blocks/chip/index.js +10 -0
  97. package/src/blocks/chip/save.js +36 -0
  98. package/src/blocks/chip/style-editor.css +5 -0
  99. package/src/blocks/chip/style.css +48 -0
  100. package/src/blocks/divider/block.json +31 -0
  101. package/src/blocks/divider/edit.js +42 -0
  102. package/src/blocks/divider/index.js +10 -0
  103. package/src/blocks/divider/save.js +18 -0
  104. package/src/blocks/divider/style-editor.css +4 -0
  105. package/src/blocks/divider/style.css +25 -0
  106. package/src/blocks/flag/block.json +48 -0
  107. package/src/blocks/flag/edit.js +82 -0
  108. package/src/blocks/flag/index.js +10 -0
  109. package/src/blocks/flag/save.js +25 -0
  110. package/src/blocks/flag/style-editor.css +5 -0
  111. package/src/blocks/flag/style.css +45 -0
  112. package/src/blocks/icon-button/block.json +43 -0
  113. package/src/blocks/icon-button/edit.js +82 -0
  114. package/src/blocks/icon-button/index.js +10 -0
  115. package/src/blocks/icon-button/save.js +29 -0
  116. package/src/blocks/icon-button/style-editor.css +5 -0
  117. package/src/blocks/icon-button/style.css +32 -0
  118. package/src/blocks/input/block.json +47 -0
  119. package/src/blocks/input/edit.js +78 -0
  120. package/src/blocks/input/index.js +10 -0
  121. package/src/blocks/input/save.js +27 -0
  122. package/src/blocks/input/style-editor.css +8 -0
  123. package/src/blocks/input/style.css +30 -0
  124. package/src/blocks/link/block.json +71 -0
  125. package/src/blocks/link/edit.js +151 -0
  126. package/src/blocks/link/index.js +10 -0
  127. package/src/blocks/link/save.js +46 -0
  128. package/src/blocks/link/style-editor.css +5 -0
  129. package/src/blocks/link/style.css +66 -0
  130. package/src/blocks/text/block.json +32 -0
  131. package/src/blocks/text/edit.js +56 -0
  132. package/src/blocks/text/index.js +10 -0
  133. package/src/blocks/text/save.js +18 -0
  134. package/src/blocks/text/style-editor.css +4 -0
  135. package/src/blocks/text/style.css +20 -0
  136. package/src/blocks/toast/block.json +39 -0
  137. package/src/blocks/toast/edit.js +85 -0
  138. package/src/blocks/toast/index.js +10 -0
  139. package/src/blocks/toast/save.js +29 -0
  140. package/src/blocks/toast/style-editor.css +4 -0
  141. package/src/blocks/toast/style.css +51 -0
  142. package/src/index.js +15 -12
  143. package/src/utils/classBuilder.js +53 -0
  144. package/tsconfig.json +4 -4
  145. package/__tests__/wordpress.test.js +0 -0
  146. package/dist/AdContainer/AdContainer.d.ts +0 -9
  147. package/dist/Article/ArticleMetaContainer/ArticleMetaContainer.d.ts +0 -8
  148. package/dist/Article/UpNextArticles/UpNextArticles.d.ts +0 -13
  149. package/dist/Button/Button.d.ts +0 -15
  150. package/dist/CommentsDisabled/CommentsDisabled.d.ts +0 -10
  151. package/dist/CommentsDisabled/CommentsDisabled.stories.d.ts +0 -44
  152. package/dist/CommentsDisabled/index.d.ts +0 -2
  153. package/dist/Divider/Divider.d.ts +0 -15
  154. package/dist/Input/Input.d.ts +0 -25
  155. package/dist/Link/Link.d.ts +0 -18
  156. package/dist/Text/Text.d.ts +0 -14
  157. package/dist/index.cjs.js +0 -299
  158. package/dist/index.cjs.js.map +0 -1
  159. package/dist/styles.css +0 -151
  160. package/dist/typographyStyles.css +0 -30
  161. package/dist/utils/cn.d.ts +0 -1
  162. package/dist/utils/hooks.d.ts +0 -8
  163. package/src/AdContainer/AdContainer.tsx +0 -31
  164. package/src/AdContainer/styles.css +0 -58
  165. package/src/Article/ArticleMetaContainer/ArticleMetaContainer.tsx +0 -14
  166. package/src/Article/ArticleMetaContainer/styles.css +0 -151
  167. package/src/Article/UpNextArticles/UpNextArticles.tsx +0 -69
  168. package/src/Article/UpNextArticles/styles.css +0 -151
  169. package/src/Button/Button.tsx +0 -36
  170. package/src/Button/styles.css +0 -30
  171. package/src/CommentsDisabled/CommentsDisabled.stories.tsx +0 -178
  172. package/src/CommentsDisabled/CommentsDisabled.tsx +0 -63
  173. package/src/CommentsDisabled/IMPLEMENTATION_SUMMARY.md +0 -305
  174. package/src/CommentsDisabled/README.md +0 -284
  175. package/src/CommentsDisabled/TOKEN_MAPPING.md +0 -269
  176. package/src/CommentsDisabled/index.ts +0 -2
  177. package/src/CommentsDisabled/styles.css +0 -82
  178. package/src/Divider/Divider.tsx +0 -41
  179. package/src/Divider/styles.css +0 -80
  180. package/src/Input/Input.tsx +0 -62
  181. package/src/Input/styles.css +0 -69
  182. package/src/Link/Link.tsx +0 -49
  183. package/src/Link/styles.css +0 -111
  184. package/src/Text/Text.tsx +0 -38
  185. package/src/Text/styles.css +0 -30
  186. package/src/Text/typographyStyles.css +0 -30
  187. package/src/utils/cn.js +0 -3
  188. package/src/utils/cn.tsx +0 -3
  189. package/src/utils/hooks.ts +0 -34
@@ -0,0 +1,635 @@
1
+ # React to WordPress Gutenberg Blocks Transformation Guide
2
+
3
+ This guide documents the process for transforming React components from `@times-design-system/components-react` into WordPress Gutenberg blocks in `@times-design-system/components-wordpress`.
4
+
5
+ ## Overview
6
+
7
+ - **Framework**: React-based Gutenberg blocks using `@wordpress/element`
8
+ - **Target**: WordPress 6.0+ with Full Site Editing (FSE) support
9
+ - **Styling**: SCSS from `@times-design-system/theme-scss` with CSS design tokens
10
+ - **Architecture**: Separate implementation (not wrapping React components)
11
+ - **Versioning**: Synchronized with React component package (currently v1.1.0)
12
+ - **Distribution**: NPM package + WordPress plugin
13
+
14
+ ---
15
+
16
+ ## Directory Structure
17
+
18
+ ```
19
+ packages/components-wordpress/
20
+ ├── src/
21
+ │ ├── blocks/
22
+ │ │ ├── button/ # Each block gets its own folder
23
+ │ │ │ ├── block.json # Gutenberg block manifest (REQUIRED)
24
+ │ │ │ ├── index.js # Block registration (REQUIRED)
25
+ │ │ │ ├── edit.js # Editor component (REQUIRED)
26
+ │ │ │ ├── save.js # Frontend output component (REQUIRED)
27
+ │ │ │ ├── style.css # Frontend styles
28
+ │ │ │ └── style-editor.css # Editor-only styles
29
+ │ │ ├── text/
30
+ │ │ ├── input/
31
+ │ │ └── ... (other blocks)
32
+ │ ├── utils/
33
+ │ │ └── classBuilder.js # Shared utility functions (BEM className builder)
34
+ │ └── index.js # Main entry point (imports all blocks)
35
+ ├── package.json
36
+ ├── rollup.config.js
37
+ ├── plugin.php # WordPress plugin entry point (auto-generated)
38
+ └── dist/ # Built output
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Step-by-Step Transformation Process
44
+
45
+ ### 1. **Analyze the React Component**
46
+
47
+ Before starting, examine the React component in `packages/components-react/src/<ComponentName>/`:
48
+
49
+ ```bash
50
+ cd packages/components-react/src/<ComponentName>
51
+ ls -la
52
+ ```
53
+
54
+ Note:
55
+
56
+ - **Props**: Identify all component props and their types
57
+ - **Variants**: List all variant combinations (enum values)
58
+ - **Styling**: Check CSS/SCSS dependencies
59
+ - **External deps**: Note any icon systems, hooks, or utilities used
60
+
61
+ **Example (Button component)**:
62
+
63
+ ```
64
+ Props:
65
+ - label (string): Button text
66
+ - intent (enum: primary | secondary | negative)
67
+ - size (enum: small | medium | large)
68
+ - behaviour (enum: hug | full)
69
+ - state (enum: base | hover | pressed | loading | disabled | focus)
70
+ - disabled (boolean)
71
+ - href, target, rel (link attributes)
72
+ - type (button type)
73
+ - iconLeft, iconRight (icon names)
74
+ ```
75
+
76
+ ### 2. **Create Block Directory Structure**
77
+
78
+ ```bash
79
+ mkdir -p packages/components-wordpress/src/blocks/<component-name>
80
+ ```
81
+
82
+ ### 3. **Create block.json (Block Manifest)**
83
+
84
+ `block.json` declares the block to WordPress and defines its interface. This is the most critical file.
85
+
86
+ **Template**:
87
+
88
+ ```json
89
+ {
90
+ "$schema": "https://schemas.wp.org/trunk/block.json",
91
+ "apiVersion": 3,
92
+ "name": "times/<block-name>",
93
+ "title": "Block Display Name",
94
+ "category": "common",
95
+ "description": "Brief description",
96
+ "icon": "admin-generic",
97
+ "supports": {
98
+ "html": false,
99
+ "spacing": {
100
+ "margin": true,
101
+ "padding": false
102
+ },
103
+ "align": true,
104
+ "customClassName": true
105
+ },
106
+ "textdomain": "times-design-system",
107
+ "attributes": {
108
+ "prop1": {
109
+ "type": "string|boolean|number|array|object",
110
+ "default": "default-value",
111
+ "description": "Prop description"
112
+ }
113
+ },
114
+ "editorScript": "file:./index.js",
115
+ "editorStyle": "file:./style-editor.css",
116
+ "style": "file:./style.css"
117
+ }
118
+ ```
119
+
120
+ **Conversion Rules**:
121
+
122
+ - Each React prop becomes an `attribute`
123
+ - Enum props use `"enum"` array
124
+ - Boolean props use `"type": "boolean"`
125
+ - String/number props use corresponding types
126
+ - Always provide sensible `default` values
127
+ - Add `description` for clarity in block inspector
128
+
129
+ **Example Button block.json**:
130
+
131
+ ```json
132
+ {
133
+ "apiVersion": 3,
134
+ "name": "times/button",
135
+ "title": "Button",
136
+ "attributes": {
137
+ "label": {
138
+ "type": "string",
139
+ "default": "Button label"
140
+ },
141
+ "intent": {
142
+ "type": "string",
143
+ "enum": ["primary", "secondary", "negative"],
144
+ "default": "primary"
145
+ },
146
+ "size": {
147
+ "type": "string",
148
+ "enum": ["small", "medium", "large"],
149
+ "default": "large"
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### 4. **Create index.js (Block Registration)**
156
+
157
+ This file registers the block with Gutenberg.
158
+
159
+ **Template**:
160
+
161
+ ```javascript
162
+ import { registerBlockType } from '@wordpress/blocks';
163
+ import Edit from './edit.js';
164
+ import Save from './save.js';
165
+ import metadata from './block.json';
166
+
167
+ registerBlockType(metadata.name, {
168
+ ...metadata,
169
+ edit: Edit,
170
+ save: Save
171
+ });
172
+ ```
173
+
174
+ **No customization needed** — this is boilerplate.
175
+
176
+ ### 5. **Create edit.js (Editor Component)**
177
+
178
+ The `edit.js` component renders the block in the WordPress editor (what users interact with).
179
+
180
+ **Template Structure**:
181
+
182
+ ```javascript
183
+ import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
184
+ import {
185
+ PanelBody,
186
+ SelectControl,
187
+ TextControl,
188
+ ToggleControl
189
+ } from '@wordpress/components';
190
+ import { buildButtonClass } from '../../utils/classBuilder.js';
191
+ import './style-editor.css';
192
+
193
+ export default function Edit({ attributes, setAttributes }) {
194
+ const { prop1, prop2, prop3 } = attributes;
195
+
196
+ const blockProps = useBlockProps({
197
+ className: 'tds-<component>-wrapper'
198
+ });
199
+
200
+ return (
201
+ <>
202
+ <div {...blockProps}>{/* Preview of component */}</div>
203
+
204
+ <InspectorControls>
205
+ <PanelBody title="Component Settings">
206
+ {/* Inspector controls for editing props */}
207
+ </PanelBody>
208
+ </InspectorControls>
209
+ </>
210
+ );
211
+ }
212
+ ```
213
+
214
+ **Key Points**:
215
+
216
+ - Always use `useBlockProps()` from `@wordpress/block-editor`
217
+ - Use `InspectorControls` to expose editable properties
218
+ - Use WordPress components for controls: `TextControl`, `SelectControl`, `ToggleControl`, `PanelBody`
219
+ - Call `setAttributes({ propName: newValue })` to update block state
220
+ - Import shared utilities like `classBuilder.js` for consistent styling
221
+
222
+ **Example Edit Component (Button)**:
223
+
224
+ ```javascript
225
+ <SelectControl
226
+ label="Intent (Style)"
227
+ value={intent}
228
+ options={[
229
+ { label: 'Primary', value: 'primary' },
230
+ { label: 'Secondary', value: 'secondary' },
231
+ { label: 'Negative', value: 'negative' }
232
+ ]}
233
+ onChange={(value) => setAttributes({ intent: value })}
234
+ />
235
+ ```
236
+
237
+ ### 6. **Create save.js (Frontend Output)**
238
+
239
+ The `save.js` component defines what gets stored/rendered on the website frontend.
240
+
241
+ **Template**:
242
+
243
+ ```javascript
244
+ import { useBlockProps } from '@wordpress/block-editor';
245
+ import { buildButtonClass } from '../../utils/classBuilder.js';
246
+
247
+ export default function Save({ attributes }) {
248
+ const { prop1, prop2, prop3 } = attributes;
249
+
250
+ const blockProps = useBlockProps.save({
251
+ className: 'tds-<component>-wrapper'
252
+ });
253
+
254
+ return <div {...blockProps}>{/* HTML structure rendered on frontend */}</div>;
255
+ }
256
+ ```
257
+
258
+ **Key Points**:
259
+
260
+ - Must be deterministic (same input = same output always)
261
+ - Always use `useBlockProps.save()`
262
+ - Return valid HTML that matches React component's render output
263
+ - No event handlers or dynamic behavior (it's static HTML)
264
+ - Can be PHP or JavaScript-rendered depending on config
265
+
266
+ ### 7. **Create CSS Files**
267
+
268
+ #### `style.css` (Frontend Styles)
269
+
270
+ - Imported on both editor and frontend
271
+ - Contains production CSS for the component
272
+ - References SCSS classes from `theme-scss` package
273
+ - Use CSS variables for tokens
274
+
275
+ **Template**:
276
+
277
+ ```css
278
+ .tds-<component > -wrapper {
279
+ /* Component wrapper styles */
280
+ }
281
+
282
+ .tds-<component > {
283
+ /* Component styles - mostly inherited from theme-scss */
284
+ }
285
+
286
+ .tds-<component > --full {
287
+ width: 100%;
288
+ }
289
+ ```
290
+
291
+ #### `style-editor.css` (Editor Styles)
292
+
293
+ - Only loaded in WordPress editor
294
+ - Can override styles for better editing experience
295
+ - Optional — only add if editor preview differs significantly from frontend
296
+
297
+ ### 8. **Create/Update Utility Functions**
298
+
299
+ Shared utilities go in `packages/components-wordpress/src/utils/`.
300
+
301
+ **classBuilder.js** (example):
302
+
303
+ ```javascript
304
+ export function buildButtonClass({
305
+ intent = 'primary',
306
+ size = 'large',
307
+ behaviour = 'hug',
308
+ state = 'base',
309
+ disabled = false
310
+ }) {
311
+ const classes = [
312
+ 'tds-button',
313
+ `tds-button--intent-${intent}`,
314
+ `tds-button--size-${size}`,
315
+ `tds-button--behaviour-${behaviour}`,
316
+ `tds-button--state-${state}`
317
+ ];
318
+
319
+ if (disabled) {
320
+ classes.push('tds-button--disabled');
321
+ }
322
+
323
+ return classes.join(' ');
324
+ }
325
+ ```
326
+
327
+ **When to add utilities**:
328
+
329
+ - Repeated className building logic
330
+ - Common prop validation
331
+ - Shared component behavior
332
+ - BEM convention helpers
333
+
334
+ ### 9. **Register Block in Main index.js**
335
+
336
+ Add block import to `src/index.js`:
337
+
338
+ ```javascript
339
+ // Already existing
340
+ import './blocks/button/index.js';
341
+
342
+ // Add new block
343
+ import './blocks/<new-component>/index.js';
344
+ ```
345
+
346
+ ---
347
+
348
+ ## Prop-to-Attribute Conversion Reference
349
+
350
+ | React Prop Type | Block Attribute | Example | Notes |
351
+ | ------------------- | ------------------- | ------------------- | -------------------------------------- |
352
+ | `string` | `"type": "string"` | `label: "Button"` | Simple text |
353
+ | `boolean` | `"type": "boolean"` | `disabled: true` | Toggle controls |
354
+ | `enum` (union type) | `"enum": [...]` | `intent: "primary"` | SelectControl in inspector |
355
+ | `number` | `"type": "number"` | `size: 16` | NumberControl |
356
+ | `Object` | `"type": "object"` | Complex data | Use JSON serialization |
357
+ | `Array` | `"type": "array"` | Multiple values | Use JSON serialization |
358
+ | Event handler | ❌ Not supported | `onClick` | Blocks don't support handlers directly |
359
+
360
+ ---
361
+
362
+ ## Inspector Controls Reference
363
+
364
+ Common WordPress components for the block inspector:
365
+
366
+ ```javascript
367
+ import {
368
+ TextControl, // Text input
369
+ NumberControl, // Number input
370
+ SelectControl, // Dropdown
371
+ ToggleControl, // On/Off switch
372
+ CheckboxControl, // Checkbox
373
+ PanelBody, // Collapsible panel
374
+ ColorPalette, // Color picker
375
+ RangeControl, // Slider
376
+ ButtonGroup // Button group
377
+ } from '@wordpress/components';
378
+ ```
379
+
380
+ **Example**:
381
+
382
+ ```javascript
383
+ <TextControl
384
+ label="Button Label"
385
+ value={label}
386
+ onChange={(value) => setAttributes({ label: value })}
387
+ placeholder="Enter button text"
388
+ />
389
+
390
+ <SelectControl
391
+ label="Button Size"
392
+ value={size}
393
+ options={[
394
+ { label: 'Small', value: 'small' },
395
+ { label: 'Medium', value: 'medium' },
396
+ { label: 'Large', value: 'large' },
397
+ ]}
398
+ onChange={(value) => setAttributes({ size: value })}
399
+ />
400
+
401
+ <ToggleControl
402
+ label="Disabled"
403
+ checked={disabled}
404
+ onChange={(value) => setAttributes({ disabled: value })}
405
+ />
406
+ ```
407
+
408
+ ---
409
+
410
+ ## Styling Best Practices
411
+
412
+ ### 1. **Class Naming Convention** (BEM)
413
+
414
+ Follow Block Element Modifier pattern:
415
+
416
+ - Block: `.tds-button`
417
+ - Element: `.tds-button__label`
418
+ - Modifier: `.tds-button--primary`, `.tds-button--large`
419
+
420
+ ### 2. **Reference Design Tokens**
421
+
422
+ Use CSS custom properties from `theme-scss`:
423
+
424
+ ```css
425
+ .tds-button {
426
+ color: var(--color-text-primary);
427
+ background-color: var(--color-bg-primary);
428
+ font-family: var(--typography-font-family-body);
429
+ border-radius: var(--spacing-radius-md);
430
+ }
431
+ ```
432
+
433
+ ### 3. **Avoid Inline Styles**
434
+
435
+ Don't set styles in edit.js:
436
+
437
+ ```javascript
438
+ // ❌ Don't do this
439
+ <div style={{ color: 'red' }}>...</div>
440
+
441
+ // ✅ Do this instead
442
+ <div className="tds-button--error">...</div>
443
+ ```
444
+
445
+ ### 4. **Support Block Spacing Settings**
446
+
447
+ Enable margin and padding controls in block.json:
448
+
449
+ ```json
450
+ "supports": {
451
+ "spacing": {
452
+ "margin": true,
453
+ "padding": false
454
+ }
455
+ }
456
+ ```
457
+
458
+ ---
459
+
460
+ ## Build and Plugin Generation
461
+
462
+ ### Local Development
463
+
464
+ ```bash
465
+ # Install dependencies
466
+ cd packages/components-wordpress
467
+ npm install
468
+
469
+ # Development with watch
470
+ npm run dev
471
+
472
+ # Build once
473
+ npm run build
474
+ ```
475
+
476
+ ### Plugin Distribution
477
+
478
+ The `build:plugin` script generates a WordPress plugin structure:
479
+
480
+ ```
481
+ dist/
482
+ ├── plugin.php # WordPress plugin entry point
483
+ ├── block.json # Root plugin metadata
484
+ └── blocks/
485
+ ├── button/
486
+ │ └── ... (compiled block files)
487
+ └── ... (other blocks)
488
+ ```
489
+
490
+ **Plugin Headers (generated in plugin.php)**:
491
+
492
+ ```php
493
+ <?php
494
+ /**
495
+ * Plugin Name: Times Design System Blocks
496
+ * Description: Gutenberg blocks for Times Design System
497
+ * Version: 1.1.0
498
+ * Text Domain: times-design-system
499
+ * Domain Path: /languages
500
+ * Requires at least: 6.0
501
+ * Requires PHP: 7.4
502
+ */
503
+ ```
504
+
505
+ ---
506
+
507
+ ## Common Patterns
508
+
509
+ ### Pattern 1: Conditional Rendering
510
+
511
+ ```javascript
512
+ // In edit.js
513
+ {
514
+ href ? (
515
+ <a href={href} className={className}>
516
+ {label}
517
+ </a>
518
+ ) : (
519
+ <button className={className}>{label}</button>
520
+ );
521
+ }
522
+ ```
523
+
524
+ ### Pattern 2: State Variants
525
+
526
+ Use modifier classes instead of state props:
527
+
528
+ ```javascript
529
+ const classes = buildButtonClass({
530
+ intent,
531
+ size,
532
+ disabled, // Adds .tds-button--disabled class
533
+ state // Adds .tds-button--state-{value} class
534
+ });
535
+ ```
536
+
537
+ ### Pattern 3: Icon Integration
538
+
539
+ Icons should be referenced by name (string), not imported:
540
+
541
+ ```javascript
542
+ // Instead of importing an Icon component:
543
+ // ❌ import { PlusIcon } from './icons'
544
+
545
+ // Use a string reference:
546
+ // ✅ iconName: "plus" → render via CSS or font icon system
547
+ ```
548
+
549
+ ### Pattern 4: Accessibility
550
+
551
+ Always include ARIA attributes:
552
+
553
+ ```javascript
554
+ <button aria-label={ariaLabel} disabled={disabled} type={type}>
555
+ {label}
556
+ </button>
557
+ ```
558
+
559
+ ---
560
+
561
+ ## Checklist for Each New Block
562
+
563
+ - [ ] Created `src/blocks/<component-name>/` directory
564
+ - [ ] Created `block.json` with all props as attributes
565
+ - [ ] Created `index.js` for block registration
566
+ - [ ] Created `edit.js` with inspector controls
567
+ - [ ] Created `save.js` with frontend HTML output
568
+ - [ ] Created `style.css` with component styling
569
+ - [ ] Created `style-editor.css` if needed for editor preview
570
+ - [ ] Added block import to `src/index.js`
571
+ - [ ] Tested block renders in editor
572
+ - [ ] Tested block saves and displays correctly
573
+ - [ ] Verified styling with `@times-design-system/theme-scss` tokens
574
+ - [ ] Added utility functions to `src/utils/` if needed
575
+ - [ ] Updated this guide if adding new patterns
576
+
577
+ ---
578
+
579
+ ## Component Transformation Order
580
+
581
+ Suggested order for consistent, dependency-aware transformation:
582
+
583
+ 1. **Button** (done ✓) — Foundation, no dependencies
584
+ 2. **Text** — Basic typography, minimal props
585
+ 3. **Divider** — Simple layout component
586
+ 4. **Input** — Form component
587
+ 5. **Link** — Extends button logic
588
+ 6. **IconButton** — Builds on button pattern
589
+ 7. **Chip** — Multi-prop component
590
+ 8. **Flag** — Badge/status component
591
+ 9. **Toast** — Notification component
592
+ 10. **AdContainer** — Container component
593
+
594
+ ---
595
+
596
+ ## Debugging & Troubleshooting
597
+
598
+ ### Block not appearing in Gutenberg?
599
+
600
+ 1. Check `block.json` has `name: "times/..."`
601
+ 2. Verify `edit.js` and `save.js` are exported as default
602
+ 3. Check console for JavaScript errors
603
+ 4. Rebuild: `npm run build`
604
+
605
+ ### Styles not loading?
606
+
607
+ 1. Verify CSS files in `block.json` point to correct paths
608
+ 2. Check class names match SCSS in `theme-scss`
609
+ 3. Ensure theme-scss is installed: `npm install @times-design-system/theme-scss`
610
+
611
+ ### Attributes not saving?
612
+
613
+ 1. Verify attribute names match in `block.json`, `edit.js`, and `save.js`
614
+ 2. Ensure `setAttributes({ key: value })` is called correctly
615
+ 3. Check attribute types match intended use
616
+
617
+ ---
618
+
619
+ ## References
620
+
621
+ - [WordPress Blocks Documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/)
622
+ - [Gutenberg Block API](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/)
623
+ - [WordPress Components](https://github.com/WordPress/gutenberg/tree/trunk/packages/components)
624
+ - [BEM Naming Convention](http://getbem.com/)
625
+ - [Times Design System Tokens](../../packages/tokens/README.md)
626
+
627
+ ---
628
+
629
+ ## Version History
630
+
631
+ - **v1.1.0** (May 2026): Initial WordPress block transformation guide
632
+ - Button block reference implementation
633
+ - Class builder utilities
634
+ - Inspector controls patterns
635
+ - Build and plugin generation setup
package/block.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "apiVersion": 3,
4
+ "name": "times/design-system-blocks",
5
+ "title": "Times Design System Blocks",
6
+ "category": "times-design-system",
7
+ "description": "A collection of Gutenberg blocks built with Times Design System components",
8
+ "textdomain": "times-design-system",
9
+ "version": "1.1.0"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "apiVersion": 3,
4
+ "name": "times/design-system-blocks",
5
+ "title": "Times Design System Blocks",
6
+ "category": "times-design-system",
7
+ "description": "A collection of Gutenberg blocks built with Times Design System components",
8
+ "textdomain": "times-design-system",
9
+ "version": "1.1.0"
10
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "apiVersion": 3,
4
+ "name": "times/ad-container",
5
+ "title": "Ad Container",
6
+ "category": "common",
7
+ "description": "Advertising container placeholder",
8
+ "icon": "image",
9
+ "supports": {
10
+ "html": false,
11
+ "spacing": {
12
+ "margin": true,
13
+ "padding": true
14
+ }
15
+ },
16
+ "attributes": {
17
+ "type": {
18
+ "type": "string",
19
+ "default": "inline",
20
+ "enum": ["header", "inline"]
21
+ },
22
+ "slotID": {
23
+ "type": "string",
24
+ "default": ""
25
+ }
26
+ },
27
+ "example": {}
28
+ }