@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.
Files changed (126) hide show
  1. package/CHANGELOG.md +24 -1
  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 +50 -33
  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,54 +1,5 @@
1
- import { PanelBody, TabPanel } from '@wordpress/components';
2
- import { __ } from '@wordpress/i18n';
3
-
4
- import { isEmpty } from '@webentorCore/_utils';
5
- import { BlockPanelProps } from '@webentorCore/block-filters/responsive-settings/types';
6
-
7
- import { BorderRadiusSettings } from './border-radius/settings';
8
- import { BorderSettings } from './border/settings';
9
-
10
- export const BorderPanel = (props: BlockPanelProps) => {
11
- const { attributes, breakpoints, twTheme } = props;
12
-
13
- if (!attributes?.border) {
14
- return null;
15
- }
16
-
17
- const checkIfHasAnyBorderSettings = (breakpoint: string): boolean => {
18
- const properties = ['border', 'borderRadius'];
19
-
20
- return properties.some((property) => {
21
- return !isEmpty(attributes?.border?.[property]?.value?.[breakpoint]);
22
- });
23
- };
24
-
25
- return (
26
- <PanelBody title={__('Border Settings', 'webentor')} initialOpen={false}>
27
- <TabPanel
28
- activeClass="is-active"
29
- className="w-responsive-settings-tabs"
30
- initialTabName={breakpoints[0]}
31
- tabs={breakpoints.map((breakpoint) => ({
32
- name: breakpoint,
33
- title: `${breakpoint}${checkIfHasAnyBorderSettings(breakpoint) ? '*' : ''}`,
34
- }))}
35
- >
36
- {(tab) => (
37
- <>
38
- <BorderSettings
39
- {...props}
40
- breakpoint={tab.name}
41
- twTheme={twTheme}
42
- />
43
-
44
- <BorderRadiusSettings
45
- {...props}
46
- breakpoint={tab.name}
47
- twTheme={twTheme}
48
- />
49
- </>
50
- )}
51
- </TabPanel>
52
- </PanelBody>
53
- );
54
- };
1
+ /**
2
+ * @deprecated BorderPanel is now provided by panels/BorderPanel.tsx.
3
+ * This file is kept for backward compat with any external imports.
4
+ */
5
+ export { BorderPanel } from '../../panels/BorderPanel';
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Border module registration.
3
+ *
4
+ * panelGroup: border, order: 10
5
+ * Handles both border and borderRadius settings within a single module.
6
+ * Support key: ['border', 'borderRadius']
7
+ */
8
+ import { isEmpty } from '../../../../_utils';
9
+ import { registry } from '../../registry';
10
+ import { ClassGenContext } from '../../types';
11
+ import { prepareTailwindBorderClassesForSide } from '../../utils';
12
+ import { BorderAndRadiusSettings } from './settings';
13
+
14
+ const RADIUS_MAPPING: Record<string, string> = {
15
+ topLeft: 'rounded-tl',
16
+ topRight: 'rounded-tr',
17
+ bottomRight: 'rounded-br',
18
+ bottomLeft: 'rounded-bl',
19
+ };
20
+
21
+ const generateBorderClasses = (
22
+ attributes: Record<string, any>,
23
+ breakpoint: string,
24
+ _context: ClassGenContext,
25
+ ): string[] => {
26
+ const classes: string[] = [];
27
+
28
+ if (!attributes.border) return classes;
29
+
30
+ for (const [propName, prop] of Object.entries(attributes.border)) {
31
+ const propData = prop as any;
32
+ if (!propData?.value) continue;
33
+ const bpValue = propData.value[breakpoint];
34
+ if (!bpValue) continue;
35
+
36
+ const twBreakpoint = breakpoint === 'basic' ? '' : `${breakpoint}:`;
37
+
38
+ for (const [valueSide, value] of Object.entries(bpValue)) {
39
+ if (valueSide === 'linked') continue;
40
+ if (!value) continue;
41
+
42
+ if (propName === 'border') {
43
+ classes.push(
44
+ ...prepareTailwindBorderClassesForSide(
45
+ value,
46
+ valueSide,
47
+ twBreakpoint,
48
+ ),
49
+ );
50
+ } else if (propName === 'borderRadius') {
51
+ const prefix = RADIUS_MAPPING[valueSide];
52
+ if (prefix) {
53
+ classes.push(`${twBreakpoint}${prefix}-${value}`);
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ return classes;
60
+ };
61
+
62
+ const hasBorderActiveSettings = (
63
+ attributes: Record<string, any>,
64
+ breakpoint: string,
65
+ ): boolean => {
66
+ const properties = ['border', 'borderRadius'];
67
+ return properties.some((property) => {
68
+ return !isEmpty(attributes?.border?.[property]?.value?.[breakpoint]);
69
+ });
70
+ };
71
+
72
+ registry.register({
73
+ name: 'border',
74
+ panelGroup: 'border',
75
+ order: 10,
76
+ attributeKey: 'border',
77
+ supportKey: ['border', 'borderRadius'],
78
+ attributeSchema: {
79
+ border: { type: 'object', default: {} },
80
+ },
81
+ SettingsComponent: BorderAndRadiusSettings,
82
+ generateClasses: generateBorderClasses,
83
+ hasActiveSettings: hasBorderActiveSettings,
84
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * BorderAndRadiusSettings — Combined inline settings component
3
+ * for both border and border-radius controls.
4
+ *
5
+ * This is the SettingsComponent for the border module, rendered
6
+ * inside the BorderPanel by the registry pattern.
7
+ */
8
+ import { SettingsComponentProps } from '../../types';
9
+ import { BorderRadiusSettings } from './border-radius/settings';
10
+ import { BorderSettings } from './border/settings';
11
+
12
+ export const BorderAndRadiusSettings = (props: SettingsComponentProps) => {
13
+ if (!props.attributes?.border) return null;
14
+
15
+ return (
16
+ <>
17
+ <BorderSettings {...props} />
18
+ <BorderRadiusSettings {...props} />
19
+ </>
20
+ );
21
+ };
@@ -0,0 +1,4 @@
1
+ import './registration';
2
+
3
+ export { FlexItemSettings } from './settings';
4
+ export { getFlexItemProperties } from './properties';
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Flex-item properties — grow, shrink, basis, order.
3
+ *
4
+ * Extracted from container/flexbox/properties.ts to be its own module.
5
+ * Re-exports getFlexboxItemProperties for backward compat.
6
+ */
7
+ import { __ } from '@wordpress/i18n';
8
+
9
+ import { WebentorConfig } from '../../../../types/_webentor-config';
10
+ import { PropertyDefinition } from '../../types';
11
+ import { getOrderValues } from '../shared/layout-values';
12
+ import { createTwThemeValues } from '../shared/tw-values';
13
+
14
+ const getFlexGrowValues = () => [
15
+ { label: __('None selected', 'webentor'), value: '' },
16
+ { label: __('Grow 0', 'webentor'), value: 'grow-0' },
17
+ { label: __('Grow 1', 'webentor'), value: 'grow' },
18
+ ];
19
+
20
+ const getFlexShrinkValues = () => [
21
+ { label: __('None selected', 'webentor'), value: '' },
22
+ { label: __('Shrink 0', 'webentor'), value: 'shrink-0' },
23
+ { label: __('Shrink 1', 'webentor'), value: 'shrink' },
24
+ ];
25
+
26
+ export const getFlexItemProperties = (
27
+ twTheme: WebentorConfig['theme'],
28
+ ): PropertyDefinition[] => [
29
+ {
30
+ label: __('Flex Grow', 'webentor'),
31
+ name: 'flex-grow',
32
+ help: __('Applicable only on Flexbox child item', 'webentor'),
33
+ values: getFlexGrowValues(),
34
+ },
35
+ {
36
+ label: __('Flex Shrink', 'webentor'),
37
+ name: 'flex-shrink',
38
+ help: __('Applicable only on Flexbox child item', 'webentor'),
39
+ values: getFlexShrinkValues(),
40
+ },
41
+ {
42
+ label: __('Flex Basis', 'webentor'),
43
+ name: 'flex-basis',
44
+ help: __('Applicable only on Flexbox child item', 'webentor'),
45
+ values: createTwThemeValues(twTheme, 'flexBasis', 'basis'),
46
+ },
47
+ {
48
+ label: __('Order', 'webentor'),
49
+ name: 'order',
50
+ help: __('Applicable only on Flexbox child item', 'webentor'),
51
+ values: getOrderValues(),
52
+ },
53
+ ];
54
+
55
+ export const FLEX_ITEM_PROPERTY_NAMES = [
56
+ 'flex-grow',
57
+ 'flex-shrink',
58
+ 'flex-basis',
59
+ 'order',
60
+ ];
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Flex-item module registration.
3
+ *
4
+ * panelGroup: displayLayout, order: 50
5
+ * Contextual: only shows when parent block display=flex.
6
+ * Support key: 'flexItem'
7
+ */
8
+ import { getEffectiveParentDisplayValue } from '../../migration';
9
+ import { registry } from '../../registry';
10
+ import { ClassGenContext } from '../../types';
11
+ import { FLEX_ITEM_PROPERTY_NAMES } from './properties';
12
+ import { FlexItemSettings } from './settings';
13
+
14
+ export const generateFlexItemClasses = (
15
+ attributes: Record<string, any>,
16
+ breakpoint: string,
17
+ context: ClassGenContext,
18
+ ): string[] => {
19
+ const classes: string[] = [];
20
+
21
+ const flexItemAttr = attributes?.flexItem;
22
+ if (!flexItemAttr) return classes;
23
+
24
+ // Cascaded parent display check
25
+ const effectiveParentDisplay = getEffectiveParentDisplayValue(
26
+ context.parentBlockAttributes,
27
+ breakpoint,
28
+ context.breakpoints,
29
+ );
30
+ if (effectiveParentDisplay !== 'flex') return classes;
31
+
32
+ for (const [, prop] of Object.entries(flexItemAttr)) {
33
+ const propData = prop as any;
34
+ if (!propData?.value) continue;
35
+ const bpValue = propData.value[breakpoint];
36
+ if (!bpValue) continue;
37
+ if (attributes?.slider?.enabled?.value?.[breakpoint]) continue;
38
+
39
+ const twBreakpoint = breakpoint === 'basic' ? '' : `${breakpoint}:`;
40
+ classes.push(`${twBreakpoint}${bpValue}`);
41
+ }
42
+
43
+ return classes;
44
+ };
45
+
46
+ const hasFlexItemActiveSettings = (
47
+ attributes: Record<string, any>,
48
+ breakpoint: string,
49
+ context?: ClassGenContext,
50
+ ): boolean => {
51
+ const effectiveParentDisplay = getEffectiveParentDisplayValue(
52
+ context?.parentBlockAttributes,
53
+ breakpoint,
54
+ context?.breakpoints ?? [],
55
+ );
56
+ if (effectiveParentDisplay !== 'flex') return false;
57
+
58
+ const flexItemAttr = attributes?.flexItem;
59
+ if (!flexItemAttr) return false;
60
+
61
+ return FLEX_ITEM_PROPERTY_NAMES.some(
62
+ (prop) => !!flexItemAttr[prop]?.value?.[breakpoint],
63
+ );
64
+ };
65
+
66
+ registry.register({
67
+ name: 'flexItem',
68
+ panelGroup: 'displayLayout',
69
+ order: 50,
70
+ attributeKey: 'flexItem',
71
+ supportKey: 'flexItem',
72
+ attributeSchema: {
73
+ flexItem: { type: 'object', default: {} },
74
+ },
75
+ SettingsComponent: FlexItemSettings,
76
+ generateClasses: generateFlexItemClasses,
77
+ hasActiveSettings: hasFlexItemActiveSettings,
78
+ });
@@ -0,0 +1,90 @@
1
+ /**
2
+ * FlexItemSettings — flex child controls (grow, shrink, basis, order).
3
+ *
4
+ * Contextual: only shows when the parent block's display is 'flex'.
5
+ */
6
+ import { Fragment } from '@wordpress/element';
7
+ import { __ } from '@wordpress/i18n';
8
+
9
+ import { useBlockParent } from '../../../../blocks-utils/_use-block-parent';
10
+ import { DisabledSliderInfo } from '../../components/DisabledSliderInfo';
11
+ import { InheritedIndicator } from '../../components/InheritedIndicator';
12
+ import { ResponsiveSelectGroup } from '../../components/ResponsiveSelectGroup';
13
+ import {
14
+ getDisplayInheritedFromBreakpoint,
15
+ getEffectiveParentDisplayValue,
16
+ } from '../../migration';
17
+ import { SettingsComponentProps } from '../../types';
18
+ import { isSliderEnabledForBreakpoint } from '../../utils';
19
+ import { getFlexItemProperties } from './properties';
20
+
21
+ const SECTION_STYLE = {
22
+ marginTop: '16px',
23
+ border: '1px solid #e0e0e0',
24
+ padding: '8px',
25
+ };
26
+
27
+ export const FlexItemSettings = ({
28
+ attributes,
29
+ setAttributes,
30
+ name,
31
+ breakpoint,
32
+ breakpoints,
33
+ twTheme,
34
+ }: SettingsComponentProps) => {
35
+ const parentBlock = useBlockParent();
36
+ const effectiveParentDisplay = getEffectiveParentDisplayValue(
37
+ parentBlock?.attributes,
38
+ breakpoint,
39
+ breakpoints,
40
+ );
41
+
42
+ if (effectiveParentDisplay !== 'flex') return null;
43
+
44
+ const hasFlexItem = attributes?.flexItem;
45
+ if (!hasFlexItem) return null;
46
+
47
+ const attributeKey = 'flexItem';
48
+ const isSliderEnabled = isSliderEnabledForBreakpoint(
49
+ name,
50
+ attributes,
51
+ breakpoint,
52
+ );
53
+
54
+ const parentInheritedFrom = parentBlock?.attributes
55
+ ? getDisplayInheritedFromBreakpoint(
56
+ parentBlock.attributes,
57
+ breakpoint,
58
+ breakpoints,
59
+ )
60
+ : null;
61
+
62
+ return (
63
+ <Fragment>
64
+ <div style={SECTION_STYLE}>
65
+ <h3 style={{ marginBottom: '8px' }}>
66
+ {__('Flex Item settings', 'webentor')}
67
+ </h3>
68
+ {parentInheritedFrom && (
69
+ <InheritedIndicator fromBreakpoint={parentInheritedFrom} />
70
+ )}
71
+ <div style={{ marginBottom: '8px', fontSize: '12px' }}>
72
+ {__(
73
+ 'Parent block display setting is set to `Flex`, so current block also acts as flex item.',
74
+ 'webentor',
75
+ )}
76
+ </div>
77
+ {isSliderEnabled && <DisabledSliderInfo />}
78
+ <ResponsiveSelectGroup
79
+ attributeKey={attributeKey}
80
+ properties={getFlexItemProperties(twTheme)}
81
+ attributes={attributes}
82
+ setAttributes={setAttributes}
83
+ breakpoint={breakpoint}
84
+ breakpoints={breakpoints}
85
+ disabled={isSliderEnabled}
86
+ />
87
+ </div>
88
+ </Fragment>
89
+ );
90
+ };
@@ -0,0 +1,4 @@
1
+ import './registration';
2
+
3
+ export { FlexboxSettings } from './settings';
4
+ export { getFlexboxProperties } from './properties';
@@ -0,0 +1,80 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ import { WebentorConfig } from '../../../../types/_webentor-config';
4
+ import { getGapValues } from '../shared/gap-values';
5
+ import {
6
+ getAlignContentValues,
7
+ getAlignItemsValues,
8
+ getJustifyContentValues,
9
+ } from '../shared/layout-values';
10
+
11
+ const getFlexDirectionValues = () => [
12
+ { label: __('None selected', 'webentor'), value: '' },
13
+ { label: __('Row', 'webentor'), value: 'flex-row' },
14
+ { label: __('Row Reverse', 'webentor'), value: 'flex-row-reverse' },
15
+ { label: __('Column', 'webentor'), value: 'flex-col' },
16
+ { label: __('Column Reverse', 'webentor'), value: 'flex-col-reverse' },
17
+ ];
18
+
19
+ const getFlexWrapValues = () => [
20
+ { label: __('None selected', 'webentor'), value: '' },
21
+ { label: __('Wrap', 'webentor'), value: 'flex-wrap' },
22
+ { label: __('Nowrap', 'webentor'), value: 'flex-nowrap' },
23
+ { label: __('Wrap Reverse', 'webentor'), value: 'flex-wrap-reverse' },
24
+ ];
25
+
26
+ export const FLEXBOX_PROPERTY_NAMES = [
27
+ 'gap',
28
+ 'gap-x',
29
+ 'gap-y',
30
+ 'flex-direction',
31
+ 'flex-wrap',
32
+ 'justify-content',
33
+ 'align-items',
34
+ 'align-content',
35
+ ];
36
+
37
+ export const getFlexboxProperties = (twTheme: WebentorConfig['theme']) => [
38
+ {
39
+ label: __('Flex Gap', 'webentor'),
40
+ name: 'gap',
41
+ values: getGapValues('', twTheme),
42
+ },
43
+ {
44
+ label: __('Flex Gap X', 'webentor'),
45
+ name: 'gap-x',
46
+ values: getGapValues('x', twTheme),
47
+ help: __('Overrides Gap value', 'webentor'),
48
+ },
49
+ {
50
+ label: __('Flex Gap Y', 'webentor'),
51
+ name: 'gap-y',
52
+ values: getGapValues('y', twTheme),
53
+ help: __('Overrides Gap value', 'webentor'),
54
+ },
55
+ {
56
+ label: __('Flex Direction', 'webentor'),
57
+ name: 'flex-direction',
58
+ values: getFlexDirectionValues(),
59
+ },
60
+ {
61
+ label: __('Flex Wrap', 'webentor'),
62
+ name: 'flex-wrap',
63
+ values: getFlexWrapValues(),
64
+ },
65
+ {
66
+ label: __('Justify Content', 'webentor'),
67
+ name: 'justify-content',
68
+ values: getJustifyContentValues(),
69
+ },
70
+ {
71
+ label: __('Align Items', 'webentor'),
72
+ name: 'align-items',
73
+ values: getAlignItemsValues(),
74
+ },
75
+ {
76
+ label: __('Align Content', 'webentor'),
77
+ name: 'align-content',
78
+ values: getAlignContentValues(),
79
+ },
80
+ ];
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Flexbox container module registration.
3
+ *
4
+ * panelGroup: displayLayout, order: 30
5
+ * Contextual: only renders when display=flex at the active breakpoint.
6
+ * Support key: 'flexbox'
7
+ */
8
+ import { getEffectiveDisplayValue } from '../../migration';
9
+ import { registry } from '../../registry';
10
+ import { ClassGenContext } from '../../types';
11
+ import { FLEXBOX_PROPERTY_NAMES } from './properties';
12
+ import { FlexboxSettings } from './settings';
13
+
14
+ export const generateFlexboxClasses = (
15
+ attributes: Record<string, any>,
16
+ breakpoint: string,
17
+ context: ClassGenContext,
18
+ ): string[] => {
19
+ const classes: string[] = [];
20
+
21
+ if (!attributes.flexbox) return classes;
22
+
23
+ // Cascaded display check: flexbox classes apply when effective display is 'flex'
24
+ const effectiveDisplay = getEffectiveDisplayValue(
25
+ attributes,
26
+ breakpoint,
27
+ context.breakpoints,
28
+ );
29
+ if (effectiveDisplay !== 'flex') return classes;
30
+
31
+ for (const [, prop] of Object.entries(attributes.flexbox)) {
32
+ const propData = prop as any;
33
+ if (!propData?.value) continue;
34
+ const bpValue = propData.value[breakpoint];
35
+ if (!bpValue) continue;
36
+ if (attributes?.slider?.enabled?.value?.[breakpoint]) continue;
37
+
38
+ const twBreakpoint = breakpoint === 'basic' ? '' : `${breakpoint}:`;
39
+ classes.push(`${twBreakpoint}${bpValue}`);
40
+ }
41
+
42
+ return classes;
43
+ };
44
+
45
+ const hasFlexboxActiveSettings = (
46
+ attributes: Record<string, any>,
47
+ breakpoint: string,
48
+ ): boolean => {
49
+ return FLEXBOX_PROPERTY_NAMES.some(
50
+ (propName) => !!attributes?.flexbox?.[propName]?.value?.[breakpoint],
51
+ );
52
+ };
53
+
54
+ registry.register({
55
+ name: 'flexbox',
56
+ panelGroup: 'displayLayout',
57
+ order: 30,
58
+ attributeKey: 'flexbox',
59
+ supportKey: 'flexbox',
60
+ attributeSchema: {
61
+ flexbox: { type: 'object', default: {} },
62
+ },
63
+ SettingsComponent: FlexboxSettings,
64
+ generateClasses: generateFlexboxClasses,
65
+ hasActiveSettings: hasFlexboxActiveSettings,
66
+ });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * FlexboxSettings — flex container controls.
3
+ *
4
+ * Only renders when the current block's display is 'flex' at the
5
+ * active breakpoint. Flex-item controls are handled by a separate module.
6
+ */
7
+ import { Fragment } from '@wordpress/element';
8
+ import { __ } from '@wordpress/i18n';
9
+
10
+ import { DisabledSliderInfo } from '../../components/DisabledSliderInfo';
11
+ import { InheritedIndicator } from '../../components/InheritedIndicator';
12
+ import { ResponsiveSelectGroup } from '../../components/ResponsiveSelectGroup';
13
+ import {
14
+ getDisplayInheritedFromBreakpoint,
15
+ getEffectiveDisplayValue,
16
+ } from '../../migration';
17
+ import { SettingsComponentProps } from '../../types';
18
+ import { isSliderEnabledForBreakpoint } from '../../utils';
19
+ import { getFlexboxProperties } from './properties';
20
+
21
+ const SECTION_STYLE = {
22
+ marginTop: '16px',
23
+ border: '1px solid #e0e0e0',
24
+ padding: '8px',
25
+ };
26
+
27
+ export const FlexboxSettings = ({
28
+ attributes,
29
+ setAttributes,
30
+ name,
31
+ breakpoint,
32
+ breakpoints,
33
+ twTheme,
34
+ }: SettingsComponentProps) => {
35
+ const effectiveDisplay = getEffectiveDisplayValue(
36
+ attributes,
37
+ breakpoint,
38
+ breakpoints,
39
+ );
40
+ const isCurrentFlex = effectiveDisplay === 'flex';
41
+
42
+ if (!isCurrentFlex || !attributes?.flexbox) {
43
+ return null;
44
+ }
45
+
46
+ const isSliderEnabled = isSliderEnabledForBreakpoint(
47
+ name,
48
+ attributes,
49
+ breakpoint,
50
+ );
51
+
52
+ const inheritedFrom = getDisplayInheritedFromBreakpoint(
53
+ attributes,
54
+ breakpoint,
55
+ breakpoints,
56
+ );
57
+
58
+ return (
59
+ <Fragment>
60
+ <div style={SECTION_STYLE}>
61
+ <h3 style={{ marginBottom: '8px' }}>
62
+ {__('Flexbox settings', 'webentor')}
63
+ </h3>
64
+ {inheritedFrom && <InheritedIndicator fromBreakpoint={inheritedFrom} />}
65
+ {isSliderEnabled && <DisabledSliderInfo />}
66
+ <ResponsiveSelectGroup
67
+ attributeKey="flexbox"
68
+ properties={getFlexboxProperties(twTheme)}
69
+ attributes={attributes}
70
+ setAttributes={setAttributes}
71
+ breakpoint={breakpoint}
72
+ breakpoints={breakpoints}
73
+ disabled={isSliderEnabled}
74
+ />
75
+ </div>
76
+ </Fragment>
77
+ );
78
+ };
@@ -0,0 +1,4 @@
1
+ import './registration';
2
+
3
+ export { GridSettings } from './settings';
4
+ export { getGridProperties } from './properties';