@webikon/webentor-core 0.9.14 → 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.
Files changed (126) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +41 -0
  3. package/core-js/_alpine.ts +6 -0
  4. package/core-js/_slider.ts +22 -11
  5. package/core-js/blocks-components/button.tsx +17 -2
  6. package/core-js/blocks-components/custom-image-sizes-panel.tsx +3 -1
  7. package/core-js/blocks-components/typography-picker-select.tsx +16 -1
  8. package/core-js/blocks-filters/_filter-core-typography.tsx +11 -1
  9. package/core-js/blocks-filters/_slider-settings.tsx +1 -1
  10. package/core-js/blocks-filters/_wrap-with-container.tsx +104 -0
  11. package/core-js/blocks-filters/responsive-settings/AGENTS.md +255 -0
  12. package/core-js/blocks-filters/responsive-settings/components/AppliedClassesViewer.tsx +189 -0
  13. package/core-js/blocks-filters/responsive-settings/components/BoxModelControl.tsx +346 -0
  14. package/core-js/blocks-filters/responsive-settings/components/BreakpointResetButton.tsx +94 -0
  15. package/core-js/blocks-filters/responsive-settings/components/DebugPanel.tsx +67 -0
  16. package/core-js/blocks-filters/responsive-settings/components/InheritedIndicator.tsx +32 -0
  17. package/core-js/blocks-filters/responsive-settings/components/LinkedValuesControl.tsx +55 -0
  18. package/core-js/blocks-filters/responsive-settings/components/ResponsiveSelectGroup.tsx +185 -0
  19. package/core-js/blocks-filters/responsive-settings/components/ResponsiveTabPanel.tsx +106 -0
  20. package/core-js/blocks-filters/responsive-settings/index.tsx +97 -148
  21. package/core-js/blocks-filters/responsive-settings/migration.ts +86 -0
  22. package/core-js/blocks-filters/responsive-settings/panels/BlockLinkPanel.tsx +38 -0
  23. package/core-js/blocks-filters/responsive-settings/panels/BorderPanel.tsx +61 -0
  24. package/core-js/blocks-filters/responsive-settings/panels/DisplayLayoutPanel.tsx +92 -0
  25. package/core-js/blocks-filters/responsive-settings/panels/SpacingPanel.tsx +63 -0
  26. package/core-js/blocks-filters/responsive-settings/panels/index.ts +4 -0
  27. package/core-js/blocks-filters/responsive-settings/registry.ts +88 -0
  28. package/core-js/blocks-filters/responsive-settings/settings/block-link/index.ts +3 -0
  29. package/core-js/blocks-filters/responsive-settings/settings/block-link/panel.tsx +6 -6
  30. package/core-js/blocks-filters/responsive-settings/settings/block-link/registration.ts +35 -0
  31. package/core-js/blocks-filters/responsive-settings/settings/border/border/properties.ts +1 -2
  32. package/core-js/blocks-filters/responsive-settings/settings/border/border/settings.tsx +21 -3
  33. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/index.tsx +2 -1
  34. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/properties.ts +6 -29
  35. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/settings.tsx +79 -6
  36. package/core-js/blocks-filters/responsive-settings/settings/border/index.ts +5 -1
  37. package/core-js/blocks-filters/responsive-settings/settings/border/panel.tsx +5 -54
  38. package/core-js/blocks-filters/responsive-settings/settings/border/registration.ts +84 -0
  39. package/core-js/blocks-filters/responsive-settings/settings/border/settings.tsx +21 -0
  40. package/core-js/blocks-filters/responsive-settings/settings/flex-item/index.ts +4 -0
  41. package/core-js/blocks-filters/responsive-settings/settings/flex-item/properties.ts +60 -0
  42. package/core-js/blocks-filters/responsive-settings/settings/flex-item/registration.ts +78 -0
  43. package/core-js/blocks-filters/responsive-settings/settings/flex-item/settings.tsx +90 -0
  44. package/core-js/blocks-filters/responsive-settings/settings/flexbox/index.ts +4 -0
  45. package/core-js/blocks-filters/responsive-settings/settings/flexbox/properties.ts +80 -0
  46. package/core-js/blocks-filters/responsive-settings/settings/flexbox/registration.ts +66 -0
  47. package/core-js/blocks-filters/responsive-settings/settings/flexbox/settings.tsx +78 -0
  48. package/core-js/blocks-filters/responsive-settings/settings/grid/index.ts +4 -0
  49. package/core-js/blocks-filters/responsive-settings/settings/grid/properties.ts +72 -0
  50. package/core-js/blocks-filters/responsive-settings/settings/grid/registration.ts +66 -0
  51. package/core-js/blocks-filters/responsive-settings/settings/grid/settings.tsx +78 -0
  52. package/core-js/blocks-filters/responsive-settings/settings/grid-item/index.ts +4 -0
  53. package/core-js/blocks-filters/responsive-settings/settings/grid-item/properties.ts +44 -0
  54. package/core-js/blocks-filters/responsive-settings/settings/grid-item/registration.ts +74 -0
  55. package/core-js/blocks-filters/responsive-settings/settings/grid-item/settings.tsx +87 -0
  56. package/core-js/blocks-filters/responsive-settings/settings/layout/index.ts +4 -0
  57. package/core-js/blocks-filters/responsive-settings/settings/layout/properties.ts +51 -0
  58. package/core-js/blocks-filters/responsive-settings/settings/layout/registration.ts +96 -0
  59. package/core-js/blocks-filters/responsive-settings/settings/layout/settings.tsx +64 -0
  60. package/core-js/blocks-filters/responsive-settings/settings/presets/index.ts +4 -0
  61. package/core-js/blocks-filters/responsive-settings/settings/presets/presets.ts +52 -0
  62. package/core-js/blocks-filters/responsive-settings/settings/presets/registration.ts +53 -0
  63. package/core-js/blocks-filters/responsive-settings/settings/presets/settings.tsx +100 -0
  64. package/core-js/blocks-filters/responsive-settings/settings/shared/gap-values.ts +16 -0
  65. package/core-js/blocks-filters/responsive-settings/settings/shared/layout-values.ts +56 -0
  66. package/core-js/blocks-filters/responsive-settings/settings/shared/tw-values.ts +107 -0
  67. package/core-js/blocks-filters/responsive-settings/settings/sizing/index.ts +4 -0
  68. package/core-js/blocks-filters/responsive-settings/settings/sizing/properties.ts +71 -0
  69. package/core-js/blocks-filters/responsive-settings/settings/sizing/registration.ts +52 -0
  70. package/core-js/blocks-filters/responsive-settings/settings/sizing/settings.tsx +96 -0
  71. package/core-js/blocks-filters/responsive-settings/settings/spacing/index.ts +7 -2
  72. package/core-js/blocks-filters/responsive-settings/settings/spacing/panel.tsx +5 -45
  73. package/core-js/blocks-filters/responsive-settings/settings/spacing/properties.ts +51 -29
  74. package/core-js/blocks-filters/responsive-settings/settings/spacing/registration.ts +53 -0
  75. package/core-js/blocks-filters/responsive-settings/settings/spacing/settings.tsx +26 -55
  76. package/core-js/blocks-filters/responsive-settings/types/index.ts +174 -28
  77. package/core-js/blocks-filters/responsive-settings/utils.ts +247 -216
  78. package/core-js/config/index.ts +6 -0
  79. package/core-js/config/webentor-config.ts +44 -2
  80. package/core-js/index.ts +8 -10
  81. package/core-js/types/index.ts +6 -0
  82. package/package.json +116 -6
  83. package/public/build/assets/_utils-CzK6Vfiv.js +2 -0
  84. package/public/build/assets/{_utils-PDaZ1Dn1.js.map → _utils-CzK6Vfiv.js.map} +1 -1
  85. package/public/build/assets/coreAppStyles-Bvp3emQy.css +1 -0
  86. package/public/build/assets/coreEditorJs-DYd3ZopL.js +366 -0
  87. package/public/build/assets/coreEditorJs-DYd3ZopL.js.map +1 -0
  88. package/public/build/assets/coreEditorStyles-BzlB6eA_.css +1 -0
  89. package/public/build/assets/resources/blocks/e-table/{script-BIchbcPK.js → script-C_Z50hjm.js} +2 -2
  90. package/public/build/assets/resources/blocks/e-table/{script-BIchbcPK.js.map → script-C_Z50hjm.js.map} +1 -1
  91. package/public/build/assets/{sliderJs-Ch69_tVA.js → sliderJs-CyGnrv0Q.js} +3 -3
  92. package/public/build/assets/{sliderJs-Ch69_tVA.js.map → sliderJs-CyGnrv0Q.js.map} +1 -1
  93. package/public/build/manifest.json +10 -10
  94. package/resources/blocks/e-accordion-group/block.json +6 -4
  95. package/resources/blocks/e-gallery/block.json +2 -2
  96. package/resources/blocks/e-gallery/e-gallery.block.tsx +4 -0
  97. package/resources/blocks/e-image/e-image.block.tsx +4 -0
  98. package/resources/blocks/e-slider/block.json +3 -2
  99. package/resources/blocks/e-tab-container/block.json +2 -1
  100. package/resources/blocks/e-tabs/block.json +2 -1
  101. package/resources/blocks/l-flexible-container/block.json +3 -2
  102. package/resources/blocks/l-mobile-nav/block.json +2 -1
  103. package/resources/blocks/l-nav-menu/block.json +2 -1
  104. package/resources/blocks/l-nav-menu/l-nav-menu.block.tsx +2 -0
  105. package/resources/blocks/l-section/block.json +7 -5
  106. package/resources/blocks/l-section/l-section.block.tsx +40 -31
  107. package/resources/scripts/editor.ts +2 -0
  108. package/resources/styles/common/_editor.css +22 -0
  109. package/resources/styles/common/_utilities.css +210 -0
  110. package/core-js/blocks-filters/responsive-settings/constants.ts +0 -11
  111. package/core-js/blocks-filters/responsive-settings/settings/container/display/index.ts +0 -2
  112. package/core-js/blocks-filters/responsive-settings/settings/container/display/properties.ts +0 -167
  113. package/core-js/blocks-filters/responsive-settings/settings/container/display/settings.tsx +0 -73
  114. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/index.ts +0 -2
  115. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/properties.ts +0 -187
  116. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/settings.tsx +0 -131
  117. package/core-js/blocks-filters/responsive-settings/settings/container/grid/index.ts +0 -2
  118. package/core-js/blocks-filters/responsive-settings/settings/container/grid/properties.ts +0 -187
  119. package/core-js/blocks-filters/responsive-settings/settings/container/grid/settings.tsx +0 -132
  120. package/core-js/blocks-filters/responsive-settings/settings/container/index.ts +0 -4
  121. package/core-js/blocks-filters/responsive-settings/settings/container/panel.tsx +0 -92
  122. package/public/build/assets/_utils-PDaZ1Dn1.js +0 -2
  123. package/public/build/assets/coreAppStyles-Dp0WYk4N.css +0 -1
  124. package/public/build/assets/coreEditorJs-Cyc87wTo.js +0 -366
  125. package/public/build/assets/coreEditorJs-Cyc87wTo.js.map +0 -1
  126. package/public/build/assets/coreEditorStyles-D8-nNpQG.css +0 -1
@@ -1,7 +1,23 @@
1
+ /**
2
+ * Responsive Settings — Utility functions.
3
+ *
4
+ * Class generation delegates to the SettingsRegistry: each registered
5
+ * module's generateClasses() is called per breakpoint, and the results
6
+ * are concatenated.
7
+ *
8
+ * Also contains generic breakpoint cascade utilities (getEffectiveValue,
9
+ * getInheritedFromBreakpoint, etc.) for min-width inheritance lookups.
10
+ *
11
+ * Border helpers are kept here for backward compat (used by border
12
+ * settings panel for preview classes).
13
+ */
1
14
  import { useBlockProps } from '@wordpress/block-editor';
2
15
  import { getBlockType } from '@wordpress/blocks';
16
+ import { applyFilters } from '@wordpress/hooks';
3
17
 
4
- import { useBlockParent } from '@webentorCore/blocks-utils/_use-block-parent';
18
+ import { useBlockParent } from '../../blocks-utils/_use-block-parent';
19
+ import { registry } from './registry';
20
+ import { ClassGenContext } from './types';
5
21
 
6
22
  export const getPixelFromRemValue = (value: string): string => {
7
23
  if (value.includes('rem')) {
@@ -11,22 +27,6 @@ export const getPixelFromRemValue = (value: string): string => {
11
27
  return value;
12
28
  };
13
29
 
14
- export const hasSpacingSettingsForBreakpoint = (
15
- attributes: any,
16
- breakpoint: string,
17
- ): boolean => {
18
- return (
19
- attributes?.spacing?.['margin-top']?.value?.[breakpoint] ||
20
- attributes?.spacing?.['margin-bottom']?.value?.[breakpoint] ||
21
- attributes?.spacing?.['margin-left']?.value?.[breakpoint] ||
22
- attributes?.spacing?.['margin-right']?.value?.[breakpoint] ||
23
- attributes?.spacing?.['padding-top']?.value?.[breakpoint] ||
24
- attributes?.spacing?.['padding-bottom']?.value?.[breakpoint] ||
25
- attributes?.spacing?.['padding-left']?.value?.[breakpoint] ||
26
- attributes?.spacing?.['padding-right']?.value?.[breakpoint]
27
- );
28
- };
29
-
30
30
  export const isSliderEnabledForBreakpoint = (
31
31
  blockName: string,
32
32
  attributes: any,
@@ -38,78 +38,41 @@ export const isSliderEnabledForBreakpoint = (
38
38
  );
39
39
  };
40
40
 
41
- export const prepareTailwindClassesFromSettings = (
42
- settings: any,
43
- type: string,
41
+ /**
42
+ * Border class helpers — exported for border settings panel (preview).
43
+ */
44
+ export const prepareTailwindBorderClassesForSide = (
45
+ value: any,
46
+ side: string,
47
+ twBreakpoint: string,
44
48
  ): string[] => {
45
49
  const classes: string[] = [];
46
50
 
47
- const parentBlock = useBlockParent();
48
- const parentBlockAttributes = parentBlock?.attributes;
49
-
50
- if (settings[type]) {
51
- Object.entries(settings[type]).forEach(([, prop]: [string, any]) => {
52
- if (prop?.value) {
53
- Object.entries(prop?.value).forEach(
54
- ([bpName, bpPropValue]: [string, any]) => {
55
- // Skip flex related settings when display is not flex
56
- if (type === 'flex') {
57
- if (settings?.display?.display?.value?.[bpName] !== 'flex') {
58
- return;
59
- }
60
- }
61
-
62
- // Skip flex item related settings when parent display is not flex
63
- if (type === 'flexItem') {
64
- if (
65
- parentBlockAttributes?.display?.display?.value?.[bpName] !==
66
- 'flex'
67
- ) {
68
- return;
69
- }
70
- }
71
-
72
- // Skip grid related settings when display is not grid
73
- if (type === 'grid') {
74
- if (settings?.display?.display?.value?.[bpName] !== 'grid') {
75
- return;
76
- }
77
- }
78
-
79
- // Skip grid item related settings when parent display is not grid
80
- if (type === 'gridItem') {
81
- if (
82
- parentBlockAttributes?.display?.display?.value?.[bpName] !=
83
- 'grid'
84
- ) {
85
- return;
86
- }
87
- }
88
-
89
- // Skip when slider is enabled
90
- if (settings?.slider?.enabled?.value?.[bpName]) {
91
- return;
92
- }
93
-
94
- if (bpPropValue) {
95
- const twBreakpoint = bpName === 'basic' ? '' : `${bpName}:`;
51
+ const borderMapping = {
52
+ top: 'border-t',
53
+ right: 'border-r',
54
+ bottom: 'border-b',
55
+ left: 'border-l',
56
+ };
96
57
 
97
- if (bpPropValue === 'hidden') {
98
- // Hidden items should be semi-transparent to indicate that they are hidden but still present
99
- classes.push(`${twBreakpoint}opacity-30`);
100
- } else {
101
- classes.push(`${twBreakpoint}${bpPropValue}`);
102
- }
103
- }
104
- },
105
- );
106
- }
107
- });
58
+ if (value) {
59
+ if (value?.width) {
60
+ classes.push(`${twBreakpoint}${borderMapping[side]}-${value.width}`);
61
+ }
62
+ if (value?.style) {
63
+ classes.push(`${twBreakpoint}${borderMapping[side]}-${value.style}`);
64
+ }
65
+ if (value?.color) {
66
+ classes.push(`${twBreakpoint}${borderMapping[side]}-${value.color}`);
67
+ }
108
68
  }
109
69
 
110
70
  return classes;
111
71
  };
112
72
 
73
+ /**
74
+ * Border class generation for full attribute set (border settings preview).
75
+ */
113
76
  export const prepareTailwindBorderClassesFromSettings = (
114
77
  settings: any,
115
78
  type: string,
@@ -127,20 +90,13 @@ export const prepareTailwindBorderClassesFromSettings = (
127
90
 
128
91
  Object.entries(bpPropValue).forEach(
129
92
  ([valueSide, value]: [string, any]) => {
130
- if (valueSide === 'linked') {
131
- return;
132
- }
93
+ if (valueSide === 'linked') return;
133
94
 
134
95
  if (propName === 'border') {
135
- // Check if side classes should be processed as we can in some cases get only one side of the border
136
- if (Array.isArray(side) && !side.includes(valueSide)) {
96
+ if (Array.isArray(side) && !side.includes(valueSide))
137
97
  return;
138
- }
139
-
140
- if (typeof side === 'string' && side !== valueSide) {
98
+ if (typeof side === 'string' && side !== valueSide)
141
99
  return;
142
- }
143
-
144
100
  classes.push(
145
101
  ...prepareTailwindBorderClassesForSide(
146
102
  value,
@@ -149,13 +105,17 @@ export const prepareTailwindBorderClassesFromSettings = (
149
105
  ),
150
106
  );
151
107
  } else if (propName === 'borderRadius') {
152
- classes.push(
153
- ...prepareTailwindBorderRadiusClassesForCorner(
154
- value,
155
- valueSide,
156
- twBreakpoint,
157
- ),
158
- );
108
+ const radiusMapping = {
109
+ topLeft: 'rounded-tl',
110
+ topRight: 'rounded-tr',
111
+ bottomRight: 'rounded-br',
112
+ bottomLeft: 'rounded-bl',
113
+ };
114
+ if (value) {
115
+ classes.push(
116
+ `${twBreakpoint}${radiusMapping[valueSide]}-${value}`,
117
+ );
118
+ }
159
119
  }
160
120
  },
161
121
  );
@@ -166,83 +126,27 @@ export const prepareTailwindBorderClassesFromSettings = (
166
126
  },
167
127
  );
168
128
  }
169
-
170
- return classes;
171
- };
172
-
173
- const prepareTailwindBorderRadiusClassesForCorner = (
174
- value: any,
175
- corner: string,
176
- twBreakpoint: string,
177
- ): string[] => {
178
- const classes: string[] = [];
179
-
180
- const radiusMapping = {
181
- topLeft: 'rounded-tl',
182
- topRight: 'rounded-tr',
183
- bottomRight: 'rounded-br',
184
- bottomLeft: 'rounded-bl',
185
- };
186
-
187
- if (value) {
188
- classes.push(`${twBreakpoint}${radiusMapping[corner]}-${value}`);
189
- }
190
-
191
- return classes;
192
- };
193
-
194
- export const prepareTailwindBorderClassesForSide = (
195
- value: any,
196
- side: string,
197
- twBreakpoint: string,
198
- ): string[] => {
199
- const classes: string[] = [];
200
-
201
- const borderMapping = {
202
- top: 'border-t',
203
- right: 'border-r',
204
- bottom: 'border-b',
205
- left: 'border-l',
206
- };
207
-
208
- if (value) {
209
- if (value?.width) {
210
- classes.push(`${twBreakpoint}${borderMapping[side]}-${value.width}`);
211
- }
212
-
213
- if (value?.style) {
214
- classes.push(`${twBreakpoint}${borderMapping[side]}-${value.style}`);
215
- }
216
-
217
- if (value?.color) {
218
- classes.push(`${twBreakpoint}${borderMapping[side]}-${value.color}`);
219
- }
220
- }
221
-
222
129
  return classes;
223
130
  };
224
131
 
132
+ /**
133
+ * Check if any registered responsive setting attribute is present on the block.
134
+ * Used as a fast guard before running class generation.
135
+ */
225
136
  export const applyResponsiveSettings = (attributes: any): boolean => {
226
- if (
227
- !attributes?.blockLink &&
228
- !attributes?.spacing &&
229
- !attributes?.display &&
230
- !attributes?.grid &&
231
- !attributes?.gridItem &&
232
- !attributes?.flexbox &&
233
- !attributes?.flexboxItem
234
- ) {
235
- return false;
236
- }
237
-
238
- return true;
137
+ return registry
138
+ .getAll()
139
+ .some((def) =>
140
+ Object.keys(def.attributeSchema).some((key) => !!attributes?.[key]),
141
+ );
239
142
  };
240
143
 
241
144
  /**
242
- * Automatically generates the class names for the block based on the attributes if they are supported.
145
+ * Generates Tailwind class names from block attributes using the SettingsRegistry.
146
+ * Each registered setting's generateClasses() is called per breakpoint.
243
147
  *
244
- * @param attributes - The attributes of the block
245
- * @returns The class names of the block
148
+ * This function is called as a classNameGenerator hook from registerBlockExtension.
149
+ * useBlockParent/useBlockProps are called at top level to comply with Rules of Hooks.
246
150
  */
247
151
  export const generateClassNames = (attributes: any): string => {
248
152
  if (!applyResponsiveSettings(attributes)) {
@@ -250,72 +154,199 @@ export const generateClassNames = (attributes: any): string => {
250
154
  }
251
155
 
252
156
  const blockProps = useBlockProps();
253
- // const settings = useSettings();
254
157
  const blockName = blockProps['data-type'];
255
-
256
158
  const blockSettings = getBlockType(blockName);
257
159
  const supports = blockSettings?.supports;
258
160
 
259
- const classes: string[] = [];
161
+ // useBlockParent hoisted to top level (hook-safe)
162
+ const parentBlock = useBlockParent();
260
163
 
261
- // Prepare all Tailwind classes
262
- if (supports?.webentor?.spacing) {
263
- const spacingClasses = prepareTailwindClassesFromSettings(
264
- attributes,
265
- 'spacing',
266
- );
267
- classes.push(...spacingClasses);
268
- }
164
+ // Resolve ordered breakpoints for cascade logic
165
+ const orderedBreakpoints: string[] = applyFilters(
166
+ 'webentor.core.twBreakpoints',
167
+ ['basic'],
168
+ ) as string[];
169
+
170
+ const context: ClassGenContext = {
171
+ blockName,
172
+ supports,
173
+ parentBlockAttributes: parentBlock?.attributes,
174
+ breakpoints: orderedBreakpoints,
175
+ };
269
176
 
270
- if (supports?.webentor?.display) {
271
- const displayClasses = prepareTailwindClassesFromSettings(
272
- attributes,
273
- 'display',
274
- );
275
- classes.push(...displayClasses);
177
+ const classes: string[] = [];
178
+ const allSettings = registry.getAll();
179
+
180
+ // Collect all breakpoints present in any attribute
181
+ const breakpoints = new Set<string>();
182
+ for (const def of allSettings) {
183
+ if (!registry.isSupported(supports, def)) continue;
184
+
185
+ // Check all attribute keys declared by this module
186
+ for (const attrKey of Object.keys(def.attributeSchema)) {
187
+ const attrGroup = attributes[attrKey];
188
+ if (!attrGroup || typeof attrGroup !== 'object') continue;
189
+
190
+ for (const prop of Object.values(attrGroup)) {
191
+ const propData = prop as any;
192
+ if (propData?.value) {
193
+ for (const bp of Object.keys(propData.value)) {
194
+ breakpoints.add(bp);
195
+ }
196
+ }
197
+ }
198
+ }
276
199
  }
277
200
 
278
- if (supports?.webentor?.flexbox) {
279
- const flexboxClasses = prepareTailwindClassesFromSettings(
280
- attributes,
281
- 'flexbox',
282
- );
283
- classes.push(...flexboxClasses);
201
+ // Generate classes per breakpoint per registered setting
202
+ for (const bp of breakpoints) {
203
+ for (const def of allSettings) {
204
+ if (!registry.isSupported(supports, def)) continue;
205
+ classes.push(...def.generateClasses(attributes, bp, context));
206
+ }
284
207
  }
285
208
 
286
- if (supports?.webentor?.flexboxItem) {
287
- const flexboxItemClasses = prepareTailwindClassesFromSettings(
288
- attributes,
289
- 'flexboxItem',
290
- );
291
- classes.push(...flexboxItemClasses);
292
- }
209
+ return classes.join(' ') ?? '';
210
+ };
293
211
 
294
- if (supports?.webentor?.grid) {
295
- const gridClasses = prepareTailwindClassesFromSettings(attributes, 'grid');
296
- classes.push(...gridClasses);
297
- }
212
+ export const inlineStyleGenerator = (): Record<string, any> => {
213
+ return {};
214
+ };
298
215
 
299
- if (supports?.webentor?.gridItem) {
300
- const gridItemClasses = prepareTailwindClassesFromSettings(
301
- attributes,
302
- 'gridItem',
303
- );
304
- classes.push(...gridItemClasses);
216
+ // ─── Breakpoint cascade utilities ───────────────────────────────────
217
+ //
218
+ // Generic min-width inheritance helpers: walk breakpoints 0..target and
219
+ // return the last explicitly set value. These work on the standard
220
+ // attributes[attrKey][propName].value[bp] shape (no v1/v2 awareness).
221
+
222
+ /**
223
+ * Generic cascade: walk breakpoints 0..target and return the last
224
+ * explicitly set value (min-width inheritance).
225
+ */
226
+ export const getEffectiveValue = (
227
+ attributes: Record<string, any>,
228
+ attributeKey: string,
229
+ propertyName: string,
230
+ breakpoint: string,
231
+ breakpoints: string[],
232
+ ): string | undefined => {
233
+ const targetIndex = breakpoints.indexOf(breakpoint);
234
+ if (targetIndex === -1) return undefined;
235
+ let effective: string | undefined;
236
+ for (let i = 0; i <= targetIndex; i++) {
237
+ const val =
238
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoints[i]];
239
+ if (val !== undefined && val !== '') effective = val;
305
240
  }
241
+ return effective;
242
+ };
306
243
 
307
- if (supports?.webentor?.border || supports?.webentor?.borderRadius) {
308
- const borderClasses = prepareTailwindBorderClassesFromSettings(
309
- attributes,
310
- 'border',
311
- ['top', 'right', 'bottom', 'left'],
312
- );
313
- classes.push(...borderClasses);
244
+ /**
245
+ * Returns the breakpoint name a value was inherited from, or null if the
246
+ * value is explicitly set at the current breakpoint (or no value exists).
247
+ * Used by InheritedIndicator to show "Inherited from basic" etc.
248
+ */
249
+ export const getInheritedFromBreakpoint = (
250
+ attributes: Record<string, any>,
251
+ attributeKey: string,
252
+ propertyName: string,
253
+ breakpoint: string,
254
+ breakpoints: string[],
255
+ ): string | null => {
256
+ const targetIndex = breakpoints.indexOf(breakpoint);
257
+ if (targetIndex === -1) return null;
258
+
259
+ // If explicit value exists at this breakpoint, it's not inherited
260
+ const explicitVal =
261
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoint];
262
+ if (explicitVal !== undefined && explicitVal !== '') return null;
263
+
264
+ // Walk backwards from the previous breakpoint to find the source
265
+ for (let i = targetIndex - 1; i >= 0; i--) {
266
+ const val =
267
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoints[i]];
268
+ if (val !== undefined && val !== '') return breakpoints[i];
314
269
  }
270
+ return null;
271
+ };
315
272
 
316
- return classes.join(' ') ?? '';
273
+ // ─── Object value cascade (borders, border-radius) ─────────────────
274
+
275
+ /**
276
+ * Check whether an object value has meaningful content.
277
+ * Filters out metadata keys ('linked') and considers empty strings as
278
+ * non-meaningful. Handles both flat values (border-radius: { topLeft: "lg" })
279
+ * and nested values (border: { top: { width: "1" } }).
280
+ */
281
+ const hasObjectContent = (val: Record<string, any>): boolean => {
282
+ return Object.entries(val).some(([key, v]) => {
283
+ if (key === 'linked') return false;
284
+ if (v === undefined || v === null || v === '') return false;
285
+ if (typeof v === 'object') {
286
+ return Object.values(v).some(
287
+ (sv) => sv !== undefined && sv !== null && sv !== '',
288
+ );
289
+ }
290
+ return true;
291
+ });
317
292
  };
318
293
 
319
- export const inlineStyleGenerator = (): Record<string, any> => {
320
- return {};
294
+ /**
295
+ * Generic cascade for object-typed property values (e.g. border sides,
296
+ * border-radius corners). Walks breakpoints 0..target and returns the
297
+ * last non-empty object value.
298
+ */
299
+ export const getEffectiveObjectValue = <T = Record<string, any>>(
300
+ attributes: Record<string, any>,
301
+ attributeKey: string,
302
+ propertyName: string,
303
+ breakpoint: string,
304
+ breakpoints: string[],
305
+ ): T | undefined => {
306
+ const targetIndex = breakpoints.indexOf(breakpoint);
307
+ if (targetIndex === -1) return undefined;
308
+ let effective: T | undefined;
309
+ for (let i = 0; i <= targetIndex; i++) {
310
+ const val =
311
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoints[i]];
312
+ if (val !== undefined && val !== null && typeof val === 'object') {
313
+ if (hasObjectContent(val)) effective = val;
314
+ }
315
+ }
316
+ return effective;
317
+ };
318
+
319
+ /**
320
+ * Returns the source breakpoint for an inherited object value, or null
321
+ * if the value is explicitly set at the current breakpoint.
322
+ */
323
+ export const getObjectInheritedFromBreakpoint = (
324
+ attributes: Record<string, any>,
325
+ attributeKey: string,
326
+ propertyName: string,
327
+ breakpoint: string,
328
+ breakpoints: string[],
329
+ ): string | null => {
330
+ const targetIndex = breakpoints.indexOf(breakpoint);
331
+ if (targetIndex === -1) return null;
332
+
333
+ const explicitVal =
334
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoint];
335
+ if (
336
+ explicitVal !== undefined &&
337
+ explicitVal !== null &&
338
+ typeof explicitVal === 'object' &&
339
+ hasObjectContent(explicitVal)
340
+ ) {
341
+ return null;
342
+ }
343
+
344
+ for (let i = targetIndex - 1; i >= 0; i--) {
345
+ const val =
346
+ attributes?.[attributeKey]?.[propertyName]?.value?.[breakpoints[i]];
347
+ if (val !== undefined && val !== null && typeof val === 'object') {
348
+ if (hasObjectContent(val)) return breakpoints[i];
349
+ }
350
+ }
351
+ return null;
321
352
  };
@@ -0,0 +1,6 @@
1
+ export {
2
+ buildSafelist,
3
+ customTypographyKeys,
4
+ spacing,
5
+ } from './webentor-config';
6
+ export { default as webentorDefaultConfig } from './webentor-config';
@@ -1,4 +1,4 @@
1
- import type { WebentorConfig } from '@webentorCore/types/_webentor-config';
1
+ import type { WebentorConfig } from '../types/_webentor-config';
2
2
 
3
3
  // Inspired by Tailwind BlockConfiguration
4
4
  // See: https://github.com/tailwindlabs/tailwindcss/blob/v3.4.17/stubs/config.full.js
@@ -698,7 +698,10 @@ export const buildSafelist = (config: WebentorConfig) => {
698
698
  }),
699
699
 
700
700
  // Opacity for hidden block
701
- ...breakpointsPrefixes.flatMap((bp) => [`${bp}opacity-30`]),
701
+ ...breakpointsPrefixes.flatMap((bp) => [
702
+ `${bp}opacity-30`,
703
+ `${bp}opacity-100`,
704
+ ]),
702
705
 
703
706
  // Orders
704
707
  ...Object.keys(config.theme.order).flatMap((i) => {
@@ -709,6 +712,45 @@ export const buildSafelist = (config: WebentorConfig) => {
709
712
  ...Object.keys(config.theme.aspectRatio).flatMap((i) => {
710
713
  return breakpointsPrefixes.flatMap((bp) => [`${bp}aspect-${i}`]);
711
714
  }),
715
+
716
+ // Custom flexbox grid
717
+ ...[
718
+ 'w-flex-cols',
719
+ 'w-flex-cols-2',
720
+ 'w-flex-cols-3',
721
+ 'w-flex-cols-4',
722
+ 'w-flex-cols-5',
723
+ 'w-flex-cols-6',
724
+ 'w-flex-cols-7',
725
+ 'w-flex-cols-8',
726
+ 'w-flex-cols-9',
727
+ 'w-flex-cols-10',
728
+ 'w-flex-cols-11',
729
+ 'w-flex-cols-12',
730
+ 'w-gap-0',
731
+ 'w-gap-0.5',
732
+ 'w-gap-1',
733
+ 'w-gap-1.5',
734
+ 'w-gap-2',
735
+ 'w-gap-2.5',
736
+ 'w-gap-3',
737
+ 'w-gap-3.5',
738
+ 'w-gap-4',
739
+ 'w-gap-5',
740
+ 'w-gap-6',
741
+ 'w-gap-7',
742
+ 'w-gap-8',
743
+ 'w-gap-9',
744
+ 'w-gap-10',
745
+ 'w-gap-11',
746
+ 'w-gap-12',
747
+ 'w-gap-14',
748
+ 'w-gap-15',
749
+ 'w-gap-16',
750
+ 'w-gap-20',
751
+ ].flatMap((i) => {
752
+ return breakpointsPrefixes.flatMap((bp) => [`${bp}${i}`]);
753
+ }),
712
754
  ];
713
755
  };
714
756
 
package/core-js/index.ts CHANGED
@@ -1,14 +1,12 @@
1
1
  export {
2
- WebentorBlockAppender,
3
- WebentorButton,
4
- WebentorTypographyPickerSelect,
5
- } from './blocks-components';
6
- export { initCustomTypographyFilter } from './blocks-filters';
7
- export { useBlockParent, usePostTypes, useTaxonomies } from './blocks-utils';
8
-
9
- export { Alpine } from './_alpine';
10
- export { SliderComponent, Swiper } from './_slider';
11
- export { setImmutably, debounce, throttle, camelize } from './_utils';
2
+ camelize,
3
+ debounce,
4
+ getColorBySlug,
5
+ getColorSlugByColor,
6
+ isEmpty,
7
+ setImmutably,
8
+ throttle,
9
+ } from './_utils';
12
10
 
13
11
  export type { ButtonAttributes } from './types/_block-components';
14
12
  export type { WebentorConfig } from './types/_webentor-config';
@@ -0,0 +1,6 @@
1
+ export type { ButtonAttributes } from './_block-components';
2
+ export type {
3
+ ResolvableTo,
4
+ ThemeConfig,
5
+ WebentorConfig,
6
+ } from './_webentor-config';