@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.
- package/BLOCK_CREATION_CHECKLIST.md +160 -0
- package/BUILD.md +411 -0
- package/CHANGELOG.md +22 -0
- package/LICENSE +29 -0
- package/README.md +972 -5
- package/TRANSFORMATION_GUIDE.md +635 -0
- package/block.json +10 -0
- package/dist/block.json +10 -0
- package/dist/blocks/ad-container/block.json +28 -0
- package/dist/blocks/ad-container/edit.js +42 -0
- package/dist/blocks/ad-container/index.js +10 -0
- package/dist/blocks/ad-container/save.js +16 -0
- package/dist/blocks/ad-container/style-editor.css +4 -0
- package/dist/blocks/ad-container/style.css +27 -0
- package/dist/blocks/button/block.json +89 -0
- package/dist/blocks/button/edit.js +187 -0
- package/dist/blocks/button/index.js +11 -0
- package/dist/blocks/button/save.js +52 -0
- package/dist/blocks/button/style-editor.css +15 -0
- package/dist/blocks/button/style.css +37 -0
- package/dist/blocks/chip/block.json +57 -0
- package/dist/blocks/chip/edit.js +113 -0
- package/dist/blocks/chip/index.js +10 -0
- package/dist/blocks/chip/save.js +36 -0
- package/dist/blocks/chip/style-editor.css +5 -0
- package/dist/blocks/chip/style.css +48 -0
- package/dist/blocks/divider/block.json +31 -0
- package/dist/blocks/divider/edit.js +42 -0
- package/dist/blocks/divider/index.js +10 -0
- package/dist/blocks/divider/save.js +18 -0
- package/dist/blocks/divider/style-editor.css +4 -0
- package/dist/blocks/divider/style.css +25 -0
- package/dist/blocks/flag/block.json +48 -0
- package/dist/blocks/flag/edit.js +82 -0
- package/dist/blocks/flag/index.js +10 -0
- package/dist/blocks/flag/save.js +25 -0
- package/dist/blocks/flag/style-editor.css +5 -0
- package/dist/blocks/flag/style.css +45 -0
- package/dist/blocks/icon-button/block.json +43 -0
- package/dist/blocks/icon-button/edit.js +82 -0
- package/dist/blocks/icon-button/index.js +10 -0
- package/dist/blocks/icon-button/save.js +29 -0
- package/dist/blocks/icon-button/style-editor.css +5 -0
- package/dist/blocks/icon-button/style.css +32 -0
- package/dist/blocks/input/block.json +47 -0
- package/dist/blocks/input/edit.js +78 -0
- package/dist/blocks/input/index.js +10 -0
- package/dist/blocks/input/save.js +27 -0
- package/dist/blocks/input/style-editor.css +8 -0
- package/dist/blocks/input/style.css +30 -0
- package/dist/blocks/link/block.json +71 -0
- package/dist/blocks/link/edit.js +151 -0
- package/dist/blocks/link/index.js +10 -0
- package/dist/blocks/link/save.js +46 -0
- package/dist/blocks/link/style-editor.css +5 -0
- package/dist/blocks/link/style.css +66 -0
- package/dist/blocks/text/block.json +32 -0
- package/dist/blocks/text/edit.js +56 -0
- package/dist/blocks/text/index.js +10 -0
- package/dist/blocks/text/save.js +18 -0
- package/dist/blocks/text/style-editor.css +4 -0
- package/dist/blocks/text/style.css +20 -0
- package/dist/blocks/toast/block.json +39 -0
- package/dist/blocks/toast/edit.js +85 -0
- package/dist/blocks/toast/index.js +10 -0
- package/dist/blocks/toast/save.js +29 -0
- package/dist/blocks/toast/style-editor.css +4 -0
- package/dist/blocks/toast/style.css +51 -0
- package/dist/index.cjs +2232 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.js +2196 -255
- package/dist/index.js.map +1 -1
- package/dist/plugin.php +79 -0
- package/dist/utils/classBuilder.js +53 -0
- package/package.json +39 -7
- package/plugin.php +79 -0
- package/rollup.config.js +39 -22
- package/scripts/build-plugin.cjs +121 -0
- package/scripts/create-block.sh +141 -0
- package/src/blocks/ad-container/block.json +28 -0
- package/src/blocks/ad-container/edit.js +42 -0
- package/src/blocks/ad-container/index.js +10 -0
- package/src/blocks/ad-container/save.js +16 -0
- package/src/blocks/ad-container/style-editor.css +4 -0
- package/src/blocks/ad-container/style.css +27 -0
- package/src/blocks/button/block.json +89 -0
- package/src/blocks/button/edit.js +187 -0
- package/src/blocks/button/index.js +11 -0
- package/src/blocks/button/save.js +52 -0
- package/src/blocks/button/style-editor.css +15 -0
- package/src/blocks/button/style.css +37 -0
- package/src/blocks/chip/block.json +57 -0
- package/src/blocks/chip/edit.js +113 -0
- package/src/blocks/chip/index.js +10 -0
- package/src/blocks/chip/save.js +36 -0
- package/src/blocks/chip/style-editor.css +5 -0
- package/src/blocks/chip/style.css +48 -0
- package/src/blocks/divider/block.json +31 -0
- package/src/blocks/divider/edit.js +42 -0
- package/src/blocks/divider/index.js +10 -0
- package/src/blocks/divider/save.js +18 -0
- package/src/blocks/divider/style-editor.css +4 -0
- package/src/blocks/divider/style.css +25 -0
- package/src/blocks/flag/block.json +48 -0
- package/src/blocks/flag/edit.js +82 -0
- package/src/blocks/flag/index.js +10 -0
- package/src/blocks/flag/save.js +25 -0
- package/src/blocks/flag/style-editor.css +5 -0
- package/src/blocks/flag/style.css +45 -0
- package/src/blocks/icon-button/block.json +43 -0
- package/src/blocks/icon-button/edit.js +82 -0
- package/src/blocks/icon-button/index.js +10 -0
- package/src/blocks/icon-button/save.js +29 -0
- package/src/blocks/icon-button/style-editor.css +5 -0
- package/src/blocks/icon-button/style.css +32 -0
- package/src/blocks/input/block.json +47 -0
- package/src/blocks/input/edit.js +78 -0
- package/src/blocks/input/index.js +10 -0
- package/src/blocks/input/save.js +27 -0
- package/src/blocks/input/style-editor.css +8 -0
- package/src/blocks/input/style.css +30 -0
- package/src/blocks/link/block.json +71 -0
- package/src/blocks/link/edit.js +151 -0
- package/src/blocks/link/index.js +10 -0
- package/src/blocks/link/save.js +46 -0
- package/src/blocks/link/style-editor.css +5 -0
- package/src/blocks/link/style.css +66 -0
- package/src/blocks/text/block.json +32 -0
- package/src/blocks/text/edit.js +56 -0
- package/src/blocks/text/index.js +10 -0
- package/src/blocks/text/save.js +18 -0
- package/src/blocks/text/style-editor.css +4 -0
- package/src/blocks/text/style.css +20 -0
- package/src/blocks/toast/block.json +39 -0
- package/src/blocks/toast/edit.js +85 -0
- package/src/blocks/toast/index.js +10 -0
- package/src/blocks/toast/save.js +29 -0
- package/src/blocks/toast/style-editor.css +4 -0
- package/src/blocks/toast/style.css +51 -0
- package/src/index.js +15 -12
- package/src/utils/classBuilder.js +53 -0
- package/tsconfig.json +4 -4
- package/__tests__/wordpress.test.js +0 -0
- package/dist/AdContainer/AdContainer.d.ts +0 -9
- package/dist/Article/ArticleMetaContainer/ArticleMetaContainer.d.ts +0 -8
- package/dist/Article/UpNextArticles/UpNextArticles.d.ts +0 -13
- package/dist/Button/Button.d.ts +0 -15
- package/dist/CommentsDisabled/CommentsDisabled.d.ts +0 -10
- package/dist/CommentsDisabled/CommentsDisabled.stories.d.ts +0 -44
- package/dist/CommentsDisabled/index.d.ts +0 -2
- package/dist/Divider/Divider.d.ts +0 -15
- package/dist/Input/Input.d.ts +0 -25
- package/dist/Link/Link.d.ts +0 -18
- package/dist/Text/Text.d.ts +0 -14
- package/dist/index.cjs.js +0 -299
- package/dist/index.cjs.js.map +0 -1
- package/dist/styles.css +0 -151
- package/dist/typographyStyles.css +0 -30
- package/dist/utils/cn.d.ts +0 -1
- package/dist/utils/hooks.d.ts +0 -8
- package/src/AdContainer/AdContainer.tsx +0 -31
- package/src/AdContainer/styles.css +0 -58
- package/src/Article/ArticleMetaContainer/ArticleMetaContainer.tsx +0 -14
- package/src/Article/ArticleMetaContainer/styles.css +0 -151
- package/src/Article/UpNextArticles/UpNextArticles.tsx +0 -69
- package/src/Article/UpNextArticles/styles.css +0 -151
- package/src/Button/Button.tsx +0 -36
- package/src/Button/styles.css +0 -30
- package/src/CommentsDisabled/CommentsDisabled.stories.tsx +0 -178
- package/src/CommentsDisabled/CommentsDisabled.tsx +0 -63
- package/src/CommentsDisabled/IMPLEMENTATION_SUMMARY.md +0 -305
- package/src/CommentsDisabled/README.md +0 -284
- package/src/CommentsDisabled/TOKEN_MAPPING.md +0 -269
- package/src/CommentsDisabled/index.ts +0 -2
- package/src/CommentsDisabled/styles.css +0 -82
- package/src/Divider/Divider.tsx +0 -41
- package/src/Divider/styles.css +0 -80
- package/src/Input/Input.tsx +0 -62
- package/src/Input/styles.css +0 -69
- package/src/Link/Link.tsx +0 -49
- package/src/Link/styles.css +0 -111
- package/src/Text/Text.tsx +0 -38
- package/src/Text/styles.css +0 -30
- package/src/Text/typographyStyles.css +0 -30
- package/src/utils/cn.js +0 -3
- package/src/utils/cn.tsx +0 -3
- 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
|
+
}
|
package/dist/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,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
|
+
}
|