@webikon/webentor-core 0.9.13 → 0.10.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/CHANGELOG.md +24 -1
- package/README.md +41 -0
- package/core-js/_alpine.ts +6 -0
- package/core-js/_slider.ts +22 -11
- package/core-js/blocks-components/button.tsx +50 -33
- package/core-js/blocks-components/custom-image-sizes-panel.tsx +3 -1
- package/core-js/blocks-components/typography-picker-select.tsx +16 -1
- package/core-js/blocks-filters/_filter-core-typography.tsx +11 -1
- package/core-js/blocks-filters/_slider-settings.tsx +1 -1
- package/core-js/blocks-filters/_wrap-with-container.tsx +104 -0
- package/core-js/blocks-filters/responsive-settings/AGENTS.md +255 -0
- package/core-js/blocks-filters/responsive-settings/components/AppliedClassesViewer.tsx +189 -0
- package/core-js/blocks-filters/responsive-settings/components/BoxModelControl.tsx +346 -0
- package/core-js/blocks-filters/responsive-settings/components/BreakpointResetButton.tsx +94 -0
- package/core-js/blocks-filters/responsive-settings/components/DebugPanel.tsx +67 -0
- package/core-js/blocks-filters/responsive-settings/components/InheritedIndicator.tsx +32 -0
- package/core-js/blocks-filters/responsive-settings/components/LinkedValuesControl.tsx +55 -0
- package/core-js/blocks-filters/responsive-settings/components/ResponsiveSelectGroup.tsx +185 -0
- package/core-js/blocks-filters/responsive-settings/components/ResponsiveTabPanel.tsx +106 -0
- package/core-js/blocks-filters/responsive-settings/index.tsx +97 -148
- package/core-js/blocks-filters/responsive-settings/migration.ts +86 -0
- package/core-js/blocks-filters/responsive-settings/panels/BlockLinkPanel.tsx +38 -0
- package/core-js/blocks-filters/responsive-settings/panels/BorderPanel.tsx +61 -0
- package/core-js/blocks-filters/responsive-settings/panels/DisplayLayoutPanel.tsx +92 -0
- package/core-js/blocks-filters/responsive-settings/panels/SpacingPanel.tsx +63 -0
- package/core-js/blocks-filters/responsive-settings/panels/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/registry.ts +88 -0
- package/core-js/blocks-filters/responsive-settings/settings/block-link/index.ts +3 -0
- package/core-js/blocks-filters/responsive-settings/settings/block-link/panel.tsx +6 -6
- package/core-js/blocks-filters/responsive-settings/settings/block-link/registration.ts +35 -0
- package/core-js/blocks-filters/responsive-settings/settings/border/border/properties.ts +1 -2
- package/core-js/blocks-filters/responsive-settings/settings/border/border/settings.tsx +21 -3
- package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/index.tsx +2 -1
- package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/properties.ts +6 -29
- package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/settings.tsx +79 -6
- package/core-js/blocks-filters/responsive-settings/settings/border/index.ts +5 -1
- package/core-js/blocks-filters/responsive-settings/settings/border/panel.tsx +5 -54
- package/core-js/blocks-filters/responsive-settings/settings/border/registration.ts +84 -0
- package/core-js/blocks-filters/responsive-settings/settings/border/settings.tsx +21 -0
- package/core-js/blocks-filters/responsive-settings/settings/flex-item/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/flex-item/properties.ts +60 -0
- package/core-js/blocks-filters/responsive-settings/settings/flex-item/registration.ts +78 -0
- package/core-js/blocks-filters/responsive-settings/settings/flex-item/settings.tsx +90 -0
- package/core-js/blocks-filters/responsive-settings/settings/flexbox/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/flexbox/properties.ts +80 -0
- package/core-js/blocks-filters/responsive-settings/settings/flexbox/registration.ts +66 -0
- package/core-js/blocks-filters/responsive-settings/settings/flexbox/settings.tsx +78 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid/properties.ts +72 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid/registration.ts +66 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid/settings.tsx +78 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid-item/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid-item/properties.ts +44 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid-item/registration.ts +74 -0
- package/core-js/blocks-filters/responsive-settings/settings/grid-item/settings.tsx +87 -0
- package/core-js/blocks-filters/responsive-settings/settings/layout/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/layout/properties.ts +51 -0
- package/core-js/blocks-filters/responsive-settings/settings/layout/registration.ts +96 -0
- package/core-js/blocks-filters/responsive-settings/settings/layout/settings.tsx +64 -0
- package/core-js/blocks-filters/responsive-settings/settings/presets/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/presets/presets.ts +52 -0
- package/core-js/blocks-filters/responsive-settings/settings/presets/registration.ts +53 -0
- package/core-js/blocks-filters/responsive-settings/settings/presets/settings.tsx +100 -0
- package/core-js/blocks-filters/responsive-settings/settings/shared/gap-values.ts +16 -0
- package/core-js/blocks-filters/responsive-settings/settings/shared/layout-values.ts +56 -0
- package/core-js/blocks-filters/responsive-settings/settings/shared/tw-values.ts +107 -0
- package/core-js/blocks-filters/responsive-settings/settings/sizing/index.ts +4 -0
- package/core-js/blocks-filters/responsive-settings/settings/sizing/properties.ts +71 -0
- package/core-js/blocks-filters/responsive-settings/settings/sizing/registration.ts +52 -0
- package/core-js/blocks-filters/responsive-settings/settings/sizing/settings.tsx +96 -0
- package/core-js/blocks-filters/responsive-settings/settings/spacing/index.ts +7 -2
- package/core-js/blocks-filters/responsive-settings/settings/spacing/panel.tsx +5 -45
- package/core-js/blocks-filters/responsive-settings/settings/spacing/properties.ts +51 -29
- package/core-js/blocks-filters/responsive-settings/settings/spacing/registration.ts +53 -0
- package/core-js/blocks-filters/responsive-settings/settings/spacing/settings.tsx +26 -55
- package/core-js/blocks-filters/responsive-settings/types/index.ts +174 -28
- package/core-js/blocks-filters/responsive-settings/utils.ts +247 -216
- package/core-js/config/index.ts +6 -0
- package/core-js/config/webentor-config.ts +44 -2
- package/core-js/index.ts +8 -10
- package/core-js/types/index.ts +6 -0
- package/package.json +116 -6
- package/public/build/assets/_utils-CzK6Vfiv.js +2 -0
- package/public/build/assets/{_utils-PDaZ1Dn1.js.map → _utils-CzK6Vfiv.js.map} +1 -1
- package/public/build/assets/coreAppStyles-Bvp3emQy.css +1 -0
- package/public/build/assets/coreEditorJs-DYd3ZopL.js +366 -0
- package/public/build/assets/coreEditorJs-DYd3ZopL.js.map +1 -0
- package/public/build/assets/coreEditorStyles-BzlB6eA_.css +1 -0
- package/public/build/assets/resources/blocks/e-table/{script-BIchbcPK.js → script-C_Z50hjm.js} +2 -2
- package/public/build/assets/resources/blocks/e-table/{script-BIchbcPK.js.map → script-C_Z50hjm.js.map} +1 -1
- package/public/build/assets/{sliderJs-Ch69_tVA.js → sliderJs-CyGnrv0Q.js} +3 -3
- package/public/build/assets/{sliderJs-Ch69_tVA.js.map → sliderJs-CyGnrv0Q.js.map} +1 -1
- package/public/build/manifest.json +10 -10
- package/resources/blocks/e-accordion-group/block.json +6 -4
- package/resources/blocks/e-gallery/block.json +2 -2
- package/resources/blocks/e-gallery/e-gallery.block.tsx +4 -0
- package/resources/blocks/e-image/e-image.block.tsx +4 -0
- package/resources/blocks/e-slider/block.json +3 -2
- package/resources/blocks/e-tab-container/block.json +2 -1
- package/resources/blocks/e-tabs/block.json +2 -1
- package/resources/blocks/l-flexible-container/block.json +3 -2
- package/resources/blocks/l-mobile-nav/block.json +2 -1
- package/resources/blocks/l-nav-menu/block.json +2 -1
- package/resources/blocks/l-nav-menu/l-nav-menu.block.tsx +2 -0
- package/resources/blocks/l-section/block.json +7 -5
- package/resources/blocks/l-section/l-section.block.tsx +40 -31
- package/resources/scripts/editor.ts +2 -0
- package/resources/styles/common/_editor.css +22 -0
- package/resources/styles/common/_utilities.css +210 -0
- package/core-js/blocks-filters/responsive-settings/constants.ts +0 -11
- package/core-js/blocks-filters/responsive-settings/settings/container/display/index.ts +0 -2
- package/core-js/blocks-filters/responsive-settings/settings/container/display/properties.ts +0 -167
- package/core-js/blocks-filters/responsive-settings/settings/container/display/settings.tsx +0 -73
- package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/index.ts +0 -2
- package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/properties.ts +0 -187
- package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/settings.tsx +0 -131
- package/core-js/blocks-filters/responsive-settings/settings/container/grid/index.ts +0 -2
- package/core-js/blocks-filters/responsive-settings/settings/container/grid/properties.ts +0 -187
- package/core-js/blocks-filters/responsive-settings/settings/container/grid/settings.tsx +0 -132
- package/core-js/blocks-filters/responsive-settings/settings/container/index.ts +0 -4
- package/core-js/blocks-filters/responsive-settings/settings/container/panel.tsx +0 -92
- package/public/build/assets/_utils-PDaZ1Dn1.js +0 -2
- package/public/build/assets/coreAppStyles-Dp0WYk4N.css +0 -1
- package/public/build/assets/coreEditorJs-Cyc87wTo.js +0 -366
- package/public/build/assets/coreEditorJs-Cyc87wTo.js.map +0 -1
- package/public/build/assets/coreEditorStyles-D8-nNpQG.css +0 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Responsive Settings — AI Guide
|
|
2
|
+
|
|
3
|
+
This file documents the architecture, data flow, and conventions of the
|
|
4
|
+
responsive settings system so AI agents can work on it without re-exploring.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Provides per-breakpoint (responsive) block controls in the WordPress editor
|
|
9
|
+
sidebar. Users can configure spacing, display mode, sizing, flexbox, grid,
|
|
10
|
+
flex/grid item behaviour, borders, and presets — all with breakpoint tabs
|
|
11
|
+
(`basic`, `sm`, `md`, `lg`, `xl`, `2xl`). Values are stored as Tailwind
|
|
12
|
+
class names and output as CSS classes on the block wrapper.
|
|
13
|
+
|
|
14
|
+
## File Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
responsive-settings/
|
|
18
|
+
index.tsx — Entry point: attribute filter, registerBlockExtension, BlockEdit
|
|
19
|
+
registry.ts — SettingsRegistry singleton (Map-based, panelGroup queries)
|
|
20
|
+
migration.ts — Display value helpers + display-specific cascade helpers
|
|
21
|
+
utils.ts — Class generation orchestrator + border preview helpers + generic breakpoint cascade utilities
|
|
22
|
+
constants.ts — Legacy includedBlocks map (currently empty, kept for fallback)
|
|
23
|
+
types/index.ts — All TypeScript interfaces (SettingDefinition, PanelGroup, BlockAttributes, etc.)
|
|
24
|
+
|
|
25
|
+
panels/ — Thin PanelBody wrappers, one per UI panel
|
|
26
|
+
SpacingPanel.tsx — panelGroup='spacing'
|
|
27
|
+
DisplayLayoutPanel.tsx — panelGroup='displayLayout' (presets rendered above tabs)
|
|
28
|
+
BorderPanel.tsx — panelGroup='border'
|
|
29
|
+
BlockLinkPanel.tsx — panelGroup='blockLink' (standalone, no breakpoint tabs)
|
|
30
|
+
index.ts
|
|
31
|
+
|
|
32
|
+
components/ — Shared UI components
|
|
33
|
+
ResponsiveTabPanel.tsx — Breakpoint tab wrapper with active-settings indicator
|
|
34
|
+
ResponsiveSelectGroup.tsx — Generic SelectControl list renderer (+ optgroup support)
|
|
35
|
+
BreakpointResetButton.tsx — Per-breakpoint "Reset" button inside tabs
|
|
36
|
+
DebugPanel.tsx — JSON attribute inspector (gated by window flag)
|
|
37
|
+
BoxModelControl.tsx — Margin/padding box-model layout with link modes
|
|
38
|
+
LinkedValuesControl.tsx — Link/unlink toggle + reset button
|
|
39
|
+
DisabledSliderInfo.tsx — Info message when slider overrides settings
|
|
40
|
+
InheritedIndicator.tsx — "Inherited from {breakpoint}" label for cascaded settings
|
|
41
|
+
|
|
42
|
+
settings/
|
|
43
|
+
presets/ — Quick layout presets (panelGroup: displayLayout, order: 0)
|
|
44
|
+
layout/ — Display mode: flex/grid/block/hidden (panelGroup: displayLayout, order: 10)
|
|
45
|
+
sizing/ — Width/height/min/max dimensions (panelGroup: displayLayout, order: 20)
|
|
46
|
+
flexbox/ — Flexbox container controls (panelGroup: displayLayout, order: 30)
|
|
47
|
+
grid/ — Grid container controls (panelGroup: displayLayout, order: 40)
|
|
48
|
+
flex-item/ — Flex child controls (panelGroup: displayLayout, order: 50)
|
|
49
|
+
grid-item/ — Grid child controls (panelGroup: displayLayout, order: 60)
|
|
50
|
+
spacing/ — Margin/padding (panelGroup: spacing, order: 10)
|
|
51
|
+
border/ — Border + border-radius (panelGroup: border, order: 10)
|
|
52
|
+
block-link/ — Block link (panelGroup: blockLink, order: 100)
|
|
53
|
+
shared/ — Shared value generators (gap-values, layout-values, tw-values)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Architecture
|
|
57
|
+
|
|
58
|
+
### Two-Layer Pattern: Panel Groups + Setting Modules
|
|
59
|
+
|
|
60
|
+
The UI has **4 collapsible panels** (SpacingPanel, DisplayLayoutPanel, BorderPanel, BlockLinkPanel).
|
|
61
|
+
Internally, the code is modular: each setting module is self-contained and
|
|
62
|
+
declares which `panelGroup` it belongs to.
|
|
63
|
+
|
|
64
|
+
Panel components are thin wrappers: they render a `PanelBody` with
|
|
65
|
+
`ResponsiveTabPanel` tabs, query the registry for all modules in their
|
|
66
|
+
`panelGroup` (sorted by `order`), and render each module's `SettingsComponent`.
|
|
67
|
+
|
|
68
|
+
### SettingsRegistry (`registry.ts`)
|
|
69
|
+
|
|
70
|
+
Singleton `Map<string, SettingDefinition>`. Modules self-register via
|
|
71
|
+
side-effect imports in their `registration.ts` files.
|
|
72
|
+
|
|
73
|
+
Key methods:
|
|
74
|
+
- `register(def)` — add a setting module
|
|
75
|
+
- `getAll()` — all modules sorted by order
|
|
76
|
+
- `getByPanelGroup(group)` — modules for a specific panel
|
|
77
|
+
- `isSupported(supports, def)` — check if a block supports a setting
|
|
78
|
+
|
|
79
|
+
### SettingDefinition Interface
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
{
|
|
83
|
+
name: string; // e.g. 'layout', 'sizing', 'flexbox'
|
|
84
|
+
panelGroup: PanelGroup; // 'spacing' | 'displayLayout' | 'border'
|
|
85
|
+
order: number; // render order within panel (lower = higher)
|
|
86
|
+
attributeKey: string; // WP attribute key (e.g. 'layout', 'spacing')
|
|
87
|
+
supportKey: string | string[]; // webentor.* support flag(s)
|
|
88
|
+
attributeSchema: object; // WP attribute schema
|
|
89
|
+
initAttributes?: Function; // custom attribute defaults (e.g. flex default)
|
|
90
|
+
SettingsComponent: React.FC; // renders inline within the panel
|
|
91
|
+
generateClasses: Function; // Tailwind class array per breakpoint
|
|
92
|
+
hasActiveSettings: Function; // tab indicator (breakpoint has values?)
|
|
93
|
+
migrateFromV1?: Function; // optional per-module migration
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Data Flow
|
|
98
|
+
|
|
99
|
+
1. **Attribute injection** (`blocks.registerBlockType` filter in `index.tsx`):
|
|
100
|
+
- Iterates all registered modules
|
|
101
|
+
- Checks `supports.webentor.*` against each module's `supportKey`
|
|
102
|
+
- Merges attribute schemas into the block
|
|
103
|
+
- Runs `initAttributes` for defaults (e.g. `layout.display = 'flex'`)
|
|
104
|
+
|
|
105
|
+
2. **Editor rendering** (`BlockEdit` in `index.tsx`):
|
|
106
|
+
- Renders SpacingPanel, DisplayLayoutPanel, BorderPanel, BlockLinkPanel
|
|
107
|
+
- Each panel queries registry and renders SettingsComponents
|
|
108
|
+
|
|
109
|
+
3. **Class generation** (`generateClassNames` in `utils.ts`):
|
|
110
|
+
- Called by `registerBlockExtension` classNameGenerator hook
|
|
111
|
+
- Collects breakpoints from all attribute values
|
|
112
|
+
- Calls each module's `generateClasses(attributes, breakpoint, context)` per breakpoint
|
|
113
|
+
- Concatenates results
|
|
114
|
+
|
|
115
|
+
4. **PHP class generation** (`blocks-settings.php`):
|
|
116
|
+
- `SettingsRegistry::generateClasses()` iterates registered handlers
|
|
117
|
+
- Each handler reads attribute values and generates Tailwind classes
|
|
118
|
+
- `prepareBlockClassesFromSettings()` orchestrates all handlers
|
|
119
|
+
|
|
120
|
+
## Attribute Shape
|
|
121
|
+
|
|
122
|
+
All responsive values follow the same pattern:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
attributes.{attributeKey}.{propertyName}.value.{breakpoint} = "tailwind-class"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Example:
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"layout": { "display": { "value": { "basic": "flex", "md": "grid" } } },
|
|
132
|
+
"spacing": { "margin-top": { "value": { "basic": "mt-4", "lg": "mt-8" } } },
|
|
133
|
+
"border": { "border": { "value": { "basic": { "top": { "width": "1", "style": "solid", "color": "black" }, "linked": true } } } }
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Migration
|
|
138
|
+
|
|
139
|
+
- Runtime code only reads canonical v2 keys
|
|
140
|
+
- PHP migration lives in `app/blocks-migration.php`
|
|
141
|
+
- `getDisplayValue()` / `getParentDisplayValue()` are the canonical display readers for `layout.display`
|
|
142
|
+
|
|
143
|
+
## PHP Side (`app/blocks-settings.php`)
|
|
144
|
+
|
|
145
|
+
- `SettingsRegistry` class mirrors the JS pattern
|
|
146
|
+
- `get_display_value_for_breakpoint()` helper for explicit display reads
|
|
147
|
+
- `get_effective_display_value_for_breakpoint()` cascaded display (min-width inheritance)
|
|
148
|
+
- `get_effective_parent_display_value_for_breakpoint()` cascaded parent display
|
|
149
|
+
- Handlers: `prepareLayoutBlockClassesFromSettings`, `prepareSizingBlockClassesFromSettings`,
|
|
150
|
+
`prepareFlexItemBlockClassesFromSettings` (new), plus unchanged handlers for spacing,
|
|
151
|
+
grid, gridItem, flexbox, border
|
|
152
|
+
- `prepareBlockClassesFromSettings()` also outputs `_presetClasses` directly
|
|
153
|
+
|
|
154
|
+
## Presets
|
|
155
|
+
|
|
156
|
+
Defined in `settings/presets/presets.ts` as `LayoutPreset[]`. Each preset
|
|
157
|
+
specifies `applies` (attribute values per module) and optional `customClasses`
|
|
158
|
+
for edge cases that need non-Tailwind CSS (e.g. flex-wrap + gap + equal columns).
|
|
159
|
+
|
|
160
|
+
Selecting a preset fills in the individual settings (which remain editable)
|
|
161
|
+
and stores `_preset` (ID marker) and `_presetClasses` (custom CSS classes).
|
|
162
|
+
|
|
163
|
+
Custom CSS utilities for presets live in `resources/styles/common/_utilities.css`:
|
|
164
|
+
- `.w-flex-cols` — flex container with wrapping
|
|
165
|
+
- `.w-flex-cols-{2-6}` — sets child width via `calc()` accounting for gap
|
|
166
|
+
- `.w-gap-{0-12}` — gap + `--w-col-gap` CSS var
|
|
167
|
+
|
|
168
|
+
## Block.json Support Keys
|
|
169
|
+
|
|
170
|
+
### Supported Keys
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
"webentor": {
|
|
174
|
+
"spacing": true,
|
|
175
|
+
"layout": true,
|
|
176
|
+
"sizing": true,
|
|
177
|
+
"grid": true,
|
|
178
|
+
"gridItem": true,
|
|
179
|
+
"flexbox": true,
|
|
180
|
+
"flexItem": true,
|
|
181
|
+
"border": true,
|
|
182
|
+
"borderRadius": true,
|
|
183
|
+
"blockLink": true,
|
|
184
|
+
"presets": true
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## JSON Schema
|
|
189
|
+
|
|
190
|
+
`schemas/webentor-block.json` defines the canonical support keys under `supports.webentor`.
|
|
191
|
+
|
|
192
|
+
## Contextual Rendering Rules
|
|
193
|
+
|
|
194
|
+
Display checks use **breakpoint cascading** (min-width inheritance): if `display=flex`
|
|
195
|
+
is set at `basic`, flexbox settings are visible at `sm`, `md`, etc. even without an
|
|
196
|
+
explicit value, because the effective display cascades from `basic`. An
|
|
197
|
+
`InheritedIndicator` label is shown when the value is inherited.
|
|
198
|
+
|
|
199
|
+
- **Flexbox settings**: show when **effective** `display=flex` at the active breakpoint
|
|
200
|
+
- **Grid settings**: show when **effective** `display=grid` at the active breakpoint
|
|
201
|
+
- **Flex-item settings**: show when **parent** block's **effective** `display=flex`
|
|
202
|
+
- **Grid-item settings**: show when **parent** block's **effective** `display=grid`
|
|
203
|
+
- **Slider override**: when `slider.enabled=true` at a breakpoint, display/flexbox/spacing settings are disabled
|
|
204
|
+
|
|
205
|
+
### Generic Cascade Functions (`utils.ts`)
|
|
206
|
+
|
|
207
|
+
| Function | Purpose |
|
|
208
|
+
|----------|---------|
|
|
209
|
+
| `getEffectiveValue(attrs, attrKey, prop, bp, bps)` | Generic cascade for any string attribute property |
|
|
210
|
+
| `getInheritedFromBreakpoint(attrs, attrKey, prop, bp, bps)` | Source breakpoint for inheritance (UI indicator) |
|
|
211
|
+
| `getEffectiveObjectValue(attrs, attrKey, prop, bp, bps)` | Cascade for object-typed values (borders, radius) |
|
|
212
|
+
| `getObjectInheritedFromBreakpoint(attrs, attrKey, prop, bp, bps)` | Source breakpoint for inherited object values |
|
|
213
|
+
|
|
214
|
+
### Display Cascade Functions (`migration.ts`)
|
|
215
|
+
|
|
216
|
+
| Function | Purpose |
|
|
217
|
+
|----------|---------|
|
|
218
|
+
| `getEffectiveDisplayValue(attrs, bp, bps)` | Cascaded display mode |
|
|
219
|
+
| `getEffectiveParentDisplayValue(parentAttrs, bp, bps)` | Cascaded parent display |
|
|
220
|
+
| `getDisplayInheritedFromBreakpoint(attrs, bp, bps)` | Display-specific inheritance source |
|
|
221
|
+
|
|
222
|
+
PHP equivalents in `blocks-settings.php`:
|
|
223
|
+
- `get_effective_display_value_for_breakpoint($attributes, $breakpoint)`
|
|
224
|
+
- `get_effective_parent_display_value_for_breakpoint($parent_block, $breakpoint)`
|
|
225
|
+
|
|
226
|
+
### Per-Property Cascade Indicators
|
|
227
|
+
|
|
228
|
+
Every property control shows inherited values from lower breakpoints:
|
|
229
|
+
|
|
230
|
+
- **`ResponsiveSelectGroup`** — when a select has no explicit value but an inherited
|
|
231
|
+
value exists, the placeholder changes from "None selected" to e.g. "Flex Row (from basic)"
|
|
232
|
+
and the select is styled with `.wbtr-inherited-value` (italic, muted color).
|
|
233
|
+
- **`BoxModelControl`** — same placeholder replacement per side select for spacing.
|
|
234
|
+
- **`BorderSettings` / `BorderRadiusSettings`** — section-level `InheritedIndicator`
|
|
235
|
+
label shown when border/radius objects cascade from a lower breakpoint.
|
|
236
|
+
|
|
237
|
+
The `breakpoints` prop is threaded from `SettingsComponentProps` → `ResponsiveSelectGroup` /
|
|
238
|
+
`BoxModelControl` to enable cascade lookups. CSS class `.wbtr-inherited-value` in
|
|
239
|
+
`resources/styles/common/_editor.css` provides the visual styling.
|
|
240
|
+
|
|
241
|
+
## Adding a New Setting Module
|
|
242
|
+
|
|
243
|
+
1. Create `settings/{name}/` with: `index.ts`, `properties.ts`, `settings.tsx`, `registration.ts`
|
|
244
|
+
2. In `registration.ts`, call `registry.register({ name, panelGroup, order, ... })`
|
|
245
|
+
3. Import `./settings/{name}` in `index.tsx` (side-effect import)
|
|
246
|
+
4. Add a matching PHP handler in `blocks-settings.php` and register it
|
|
247
|
+
5. Update `schemas/webentor-block.json` if adding a new support key
|
|
248
|
+
|
|
249
|
+
## Common Mistakes to Avoid
|
|
250
|
+
|
|
251
|
+
- **Don't read `attributes.layout.display` directly in contextual modules** — use `getDisplayValue()` from `migration.ts`
|
|
252
|
+
- **Don't read parent display directly** — use `getParentDisplayValue()`
|
|
253
|
+
- **Don't create a new PanelBody in a SettingsComponent** — it renders inline within an existing panel
|
|
254
|
+
- **Don't forget both JS and PHP** — class generation runs on both sides
|
|
255
|
+
- **Don't change version numbers here unless the task is an explicit release change** — follow the root `AGENTS.md` release policy for manual versioning and changelog updates
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppliedClassesViewer — Toolbar button (eye icon) that reveals a popover
|
|
3
|
+
* listing all Tailwind classes generated by responsive settings for the
|
|
4
|
+
* current block. Rendered inside BlockControls > ToolbarGroup in the
|
|
5
|
+
* block toolbar so it covers all panels (spacing, layout, borders).
|
|
6
|
+
*
|
|
7
|
+
* Classes are grouped by panel group (Spacing, Display & Layout, Border)
|
|
8
|
+
* for easier scanning.
|
|
9
|
+
*/
|
|
10
|
+
import { getBlockType } from '@wordpress/blocks';
|
|
11
|
+
import { Popover, ToolbarButton } from '@wordpress/components';
|
|
12
|
+
import { useMemo, useState } from '@wordpress/element';
|
|
13
|
+
import { __ } from '@wordpress/i18n';
|
|
14
|
+
import { postList } from '@wordpress/icons';
|
|
15
|
+
|
|
16
|
+
import { useBlockParent } from '../../../blocks-utils/_use-block-parent';
|
|
17
|
+
import { registry } from '../registry';
|
|
18
|
+
import { BlockPanelProps, ClassGenContext, PanelGroup } from '../types';
|
|
19
|
+
|
|
20
|
+
interface ClassGroup {
|
|
21
|
+
group: PanelGroup;
|
|
22
|
+
label: string;
|
|
23
|
+
classes: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const GROUP_LABELS: Record<PanelGroup, string> = {
|
|
27
|
+
spacing: 'Spacing',
|
|
28
|
+
displayLayout: 'Display & Layout',
|
|
29
|
+
border: 'Border',
|
|
30
|
+
blockLink: 'Block Link',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Panel group render order */
|
|
34
|
+
const GROUP_ORDER: PanelGroup[] = [
|
|
35
|
+
'spacing',
|
|
36
|
+
'displayLayout',
|
|
37
|
+
'border',
|
|
38
|
+
'blockLink',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Collect responsive-settings classes grouped by panel group.
|
|
43
|
+
* Same logic as generateClassNames in utils.ts but without useBlockProps.
|
|
44
|
+
*/
|
|
45
|
+
const collectGroupedClasses = (
|
|
46
|
+
attributes: Record<string, any>,
|
|
47
|
+
blockName: string,
|
|
48
|
+
parentAttributes: Record<string, any> | undefined,
|
|
49
|
+
orderedBreakpoints: string[],
|
|
50
|
+
): ClassGroup[] => {
|
|
51
|
+
const blockSettings = getBlockType(blockName);
|
|
52
|
+
const supports = blockSettings?.supports;
|
|
53
|
+
|
|
54
|
+
const context: ClassGenContext = {
|
|
55
|
+
blockName,
|
|
56
|
+
supports,
|
|
57
|
+
parentBlockAttributes: parentAttributes,
|
|
58
|
+
breakpoints: orderedBreakpoints,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const allSettings = registry.getAll();
|
|
62
|
+
|
|
63
|
+
// Collect all breakpoints present in any attribute
|
|
64
|
+
const breakpoints = new Set<string>();
|
|
65
|
+
for (const def of allSettings) {
|
|
66
|
+
if (!registry.isSupported(supports, def)) continue;
|
|
67
|
+
for (const attrKey of Object.keys(def.attributeSchema)) {
|
|
68
|
+
const attrGroup = attributes[attrKey];
|
|
69
|
+
if (!attrGroup || typeof attrGroup !== 'object') continue;
|
|
70
|
+
for (const prop of Object.values(attrGroup)) {
|
|
71
|
+
const propData = prop as any;
|
|
72
|
+
if (propData?.value) {
|
|
73
|
+
for (const bp of Object.keys(propData.value)) {
|
|
74
|
+
breakpoints.add(bp);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Group classes by panelGroup
|
|
82
|
+
const groupMap = new Map<PanelGroup, string[]>();
|
|
83
|
+
for (const bp of breakpoints) {
|
|
84
|
+
for (const def of allSettings) {
|
|
85
|
+
if (!registry.isSupported(supports, def)) continue;
|
|
86
|
+
const generated = def
|
|
87
|
+
.generateClasses(attributes, bp, context)
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
if (generated.length === 0) continue;
|
|
90
|
+
|
|
91
|
+
const existing = groupMap.get(def.panelGroup) ?? [];
|
|
92
|
+
existing.push(...generated);
|
|
93
|
+
groupMap.set(def.panelGroup, existing);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return GROUP_ORDER.filter((g) => groupMap.has(g)).map((g) => ({
|
|
98
|
+
group: g,
|
|
99
|
+
label: GROUP_LABELS[g],
|
|
100
|
+
classes: groupMap.get(g)!,
|
|
101
|
+
}));
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const AppliedClassesViewer = ({
|
|
105
|
+
attributes,
|
|
106
|
+
name,
|
|
107
|
+
breakpoints,
|
|
108
|
+
}: BlockPanelProps) => {
|
|
109
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
110
|
+
const parentBlock = useBlockParent();
|
|
111
|
+
|
|
112
|
+
const groups = useMemo(
|
|
113
|
+
() =>
|
|
114
|
+
collectGroupedClasses(
|
|
115
|
+
attributes,
|
|
116
|
+
name,
|
|
117
|
+
parentBlock?.attributes,
|
|
118
|
+
breakpoints,
|
|
119
|
+
),
|
|
120
|
+
[attributes, name, parentBlock?.attributes, breakpoints],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (groups.every((g) => g.classes.length === 0)) return null;
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<>
|
|
127
|
+
<ToolbarButton
|
|
128
|
+
icon={postList}
|
|
129
|
+
label={__('View applied classes', 'webentor')}
|
|
130
|
+
onClick={() => setIsOpen((prev) => !prev)}
|
|
131
|
+
isPressed={isOpen}
|
|
132
|
+
/>
|
|
133
|
+
{isOpen && (
|
|
134
|
+
<Popover
|
|
135
|
+
placement="bottom-start"
|
|
136
|
+
onClose={() => setIsOpen(false)}
|
|
137
|
+
shift
|
|
138
|
+
>
|
|
139
|
+
<div
|
|
140
|
+
style={{
|
|
141
|
+
padding: '12px',
|
|
142
|
+
maxWidth: '320px',
|
|
143
|
+
maxHeight: '280px',
|
|
144
|
+
overflow: 'auto',
|
|
145
|
+
}}
|
|
146
|
+
>
|
|
147
|
+
{groups.map((group, gi) => (
|
|
148
|
+
<div key={group.group} style={{ marginTop: gi > 0 ? '12px' : 0 }}>
|
|
149
|
+
<p
|
|
150
|
+
style={{
|
|
151
|
+
fontSize: '11px',
|
|
152
|
+
textTransform: 'uppercase',
|
|
153
|
+
marginTop: 0,
|
|
154
|
+
marginBottom: '6px',
|
|
155
|
+
color: '#757575',
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
{group.label}
|
|
159
|
+
</p>
|
|
160
|
+
<div
|
|
161
|
+
style={{
|
|
162
|
+
display: 'flex',
|
|
163
|
+
flexWrap: 'wrap',
|
|
164
|
+
gap: '4px',
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
{group.classes.map((cls, i) => (
|
|
168
|
+
<code
|
|
169
|
+
key={`${cls}-${i}`}
|
|
170
|
+
style={{
|
|
171
|
+
fontSize: '11px',
|
|
172
|
+
padding: '2px 6px',
|
|
173
|
+
background: '#f0f0f0',
|
|
174
|
+
borderRadius: '3px',
|
|
175
|
+
whiteSpace: 'nowrap',
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
{cls}
|
|
179
|
+
</code>
|
|
180
|
+
))}
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
))}
|
|
184
|
+
</div>
|
|
185
|
+
</Popover>
|
|
186
|
+
)}
|
|
187
|
+
</>
|
|
188
|
+
);
|
|
189
|
+
};
|