@webikon/webentor-core 0.9.14 → 0.10.1
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 -0
- 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 +17 -2
- 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-CukxHLz7.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-I9xzOGSX.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,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InheritedIndicator — shows when a setting section is visible due to
|
|
3
|
+
* breakpoint cascading (min-width inheritance) rather than an explicit
|
|
4
|
+
* value at the current breakpoint.
|
|
5
|
+
*
|
|
6
|
+
* Displays e.g. "Inherited from basic" so the user understands why
|
|
7
|
+
* flexbox/grid controls appear even though no display value is explicitly
|
|
8
|
+
* set at the active breakpoint.
|
|
9
|
+
*/
|
|
10
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
interface InheritedIndicatorProps {
|
|
13
|
+
/** The breakpoint name the value cascades from (e.g. 'basic', 'sm') */
|
|
14
|
+
fromBreakpoint: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const INDICATOR_STYLE: React.CSSProperties = {
|
|
18
|
+
fontSize: '11px',
|
|
19
|
+
color: '#757575',
|
|
20
|
+
fontStyle: 'italic',
|
|
21
|
+
marginBottom: '8px',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const InheritedIndicator = ({
|
|
25
|
+
fromBreakpoint,
|
|
26
|
+
}: InheritedIndicatorProps) => {
|
|
27
|
+
return (
|
|
28
|
+
<div style={INDICATOR_STYLE}>
|
|
29
|
+
{sprintf(__('Inherited from %s', 'webentor'), fromBreakpoint)}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Button } from '@wordpress/components';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
import { link, linkOff } from '@wordpress/icons';
|
|
4
|
+
|
|
5
|
+
export type LinkMode = 'linked' | 'unlinked';
|
|
6
|
+
|
|
7
|
+
interface LinkedValuesControlProps {
|
|
8
|
+
mode: LinkMode;
|
|
9
|
+
onModeChange: (mode: LinkMode) => void;
|
|
10
|
+
onReset?: () => void;
|
|
11
|
+
resetDisabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Toggle button for linking/unlinking spacing sides.
|
|
16
|
+
* Linked = horizontal+vertical pairs synced; Unlinked = all 4 independent.
|
|
17
|
+
*/
|
|
18
|
+
export const LinkedValuesControl = ({
|
|
19
|
+
mode,
|
|
20
|
+
onModeChange,
|
|
21
|
+
onReset,
|
|
22
|
+
resetDisabled = false,
|
|
23
|
+
}: LinkedValuesControlProps) => {
|
|
24
|
+
const isLinked = mode === 'linked';
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="wbtr:flex wbtr:grow-1 wbtr:items-center wbtr:justify-between">
|
|
28
|
+
<Button
|
|
29
|
+
icon={isLinked ? linkOff : link}
|
|
30
|
+
isPressed={isLinked}
|
|
31
|
+
onClick={() => onModeChange(isLinked ? 'unlinked' : 'linked')}
|
|
32
|
+
label={
|
|
33
|
+
isLinked
|
|
34
|
+
? __('Unlink sides', 'webentor')
|
|
35
|
+
: __('Link sides', 'webentor')
|
|
36
|
+
}
|
|
37
|
+
showTooltip
|
|
38
|
+
size="small"
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
{onReset && (
|
|
42
|
+
<Button
|
|
43
|
+
variant="tertiary"
|
|
44
|
+
onClick={onReset}
|
|
45
|
+
disabled={resetDisabled}
|
|
46
|
+
label={__('Reset to defaults', 'webentor')}
|
|
47
|
+
showTooltip
|
|
48
|
+
size="small"
|
|
49
|
+
>
|
|
50
|
+
{__('Reset', 'webentor')}
|
|
51
|
+
</Button>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { SelectControl } from '@wordpress/components';
|
|
2
|
+
import { Fragment } from '@wordpress/element';
|
|
3
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
4
|
+
|
|
5
|
+
import { setImmutably } from '../../../_utils';
|
|
6
|
+
import { PropertyDefinition } from '../registry';
|
|
7
|
+
import { SelectOptionGroup } from '../types';
|
|
8
|
+
import { getEffectiveValue, getInheritedFromBreakpoint } from '../utils';
|
|
9
|
+
|
|
10
|
+
interface ResponsiveSelectGroupProps {
|
|
11
|
+
attributeKey: string;
|
|
12
|
+
properties: PropertyDefinition[];
|
|
13
|
+
attributes: Record<string, any>;
|
|
14
|
+
setAttributes: (attrs: Record<string, any>) => void;
|
|
15
|
+
breakpoint: string;
|
|
16
|
+
/** Ordered breakpoint names for cascade indicators */
|
|
17
|
+
breakpoints?: string[];
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Per-property visibility filter (e.g. display supports check) */
|
|
20
|
+
isPropertyVisible?: (property: PropertyDefinition) => boolean;
|
|
21
|
+
/** Map of property name → grouped options for optgroup rendering */
|
|
22
|
+
valueGroups?: Record<string, SelectOptionGroup[]>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the inherited placeholder text for a property.
|
|
27
|
+
* Returns the human-readable label of the cascaded value + source breakpoint,
|
|
28
|
+
* or the default "None selected" if nothing is inherited.
|
|
29
|
+
*/
|
|
30
|
+
const getInheritedPlaceholder = (
|
|
31
|
+
attributes: Record<string, any>,
|
|
32
|
+
attributeKey: string,
|
|
33
|
+
property: PropertyDefinition,
|
|
34
|
+
breakpoint: string,
|
|
35
|
+
breakpoints: string[] | undefined,
|
|
36
|
+
valueGroups?: Record<string, SelectOptionGroup[]>,
|
|
37
|
+
): { text: string; isInherited: boolean } => {
|
|
38
|
+
const defaultText = __('None selected', 'webentor');
|
|
39
|
+
if (!breakpoints?.length) return { text: defaultText, isInherited: false };
|
|
40
|
+
|
|
41
|
+
const inheritedFrom = getInheritedFromBreakpoint(
|
|
42
|
+
attributes,
|
|
43
|
+
attributeKey,
|
|
44
|
+
property.name,
|
|
45
|
+
breakpoint,
|
|
46
|
+
breakpoints,
|
|
47
|
+
);
|
|
48
|
+
if (!inheritedFrom) return { text: defaultText, isInherited: false };
|
|
49
|
+
|
|
50
|
+
const inheritedValue = getEffectiveValue(
|
|
51
|
+
attributes,
|
|
52
|
+
attributeKey,
|
|
53
|
+
property.name,
|
|
54
|
+
breakpoint,
|
|
55
|
+
breakpoints,
|
|
56
|
+
);
|
|
57
|
+
if (!inheritedValue) return { text: defaultText, isInherited: false };
|
|
58
|
+
|
|
59
|
+
// Resolve human-readable label from flat options or grouped options
|
|
60
|
+
let label: string | undefined;
|
|
61
|
+
const groups = property.groupedValues
|
|
62
|
+
? valueGroups?.[property.name]
|
|
63
|
+
: undefined;
|
|
64
|
+
if (groups) {
|
|
65
|
+
for (const group of groups) {
|
|
66
|
+
const match = group.options.find((o) => o.value === inheritedValue);
|
|
67
|
+
if (match) {
|
|
68
|
+
label = match.label;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!label) {
|
|
74
|
+
label =
|
|
75
|
+
property.values.find((o) => o.value === inheritedValue)?.label ??
|
|
76
|
+
inheritedValue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
text: sprintf(__('%s (from %s)', 'webentor'), label, inheritedFrom),
|
|
81
|
+
isInherited: true,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Generic SelectControl list renderer for responsive settings.
|
|
87
|
+
*
|
|
88
|
+
* Shows cascade indicators: when a property has no explicit value at the
|
|
89
|
+
* current breakpoint but inherits one from a lower breakpoint, the empty
|
|
90
|
+
* option shows the inherited value and source breakpoint.
|
|
91
|
+
*
|
|
92
|
+
* When a property has groupedValues + matching valueGroups entry,
|
|
93
|
+
* passes <optgroup> children to SelectControl instead of the options prop.
|
|
94
|
+
* WP's SelectControl renders children directly inside the native <select>.
|
|
95
|
+
*/
|
|
96
|
+
export const ResponsiveSelectGroup = ({
|
|
97
|
+
attributeKey,
|
|
98
|
+
properties,
|
|
99
|
+
attributes,
|
|
100
|
+
setAttributes,
|
|
101
|
+
breakpoint,
|
|
102
|
+
breakpoints,
|
|
103
|
+
disabled = false,
|
|
104
|
+
isPropertyVisible,
|
|
105
|
+
valueGroups,
|
|
106
|
+
}: ResponsiveSelectGroupProps) => {
|
|
107
|
+
return (
|
|
108
|
+
<>
|
|
109
|
+
{properties.map((property) => {
|
|
110
|
+
if (isPropertyVisible && !isPropertyVisible(property)) return null;
|
|
111
|
+
|
|
112
|
+
const groups = property.groupedValues
|
|
113
|
+
? valueGroups?.[property.name]
|
|
114
|
+
: undefined;
|
|
115
|
+
const handleChange = (selected: string) =>
|
|
116
|
+
setAttributes(
|
|
117
|
+
setImmutably(
|
|
118
|
+
attributes,
|
|
119
|
+
[attributeKey, property.name, 'value', breakpoint],
|
|
120
|
+
selected,
|
|
121
|
+
),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const explicitValue =
|
|
125
|
+
attributes[attributeKey]?.[property.name]?.value?.[breakpoint] ?? '';
|
|
126
|
+
const { text: placeholderText, isInherited } = getInheritedPlaceholder(
|
|
127
|
+
attributes,
|
|
128
|
+
attributeKey,
|
|
129
|
+
property,
|
|
130
|
+
breakpoint,
|
|
131
|
+
breakpoints,
|
|
132
|
+
valueGroups,
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const inheritedClassName =
|
|
136
|
+
!explicitValue && isInherited ? 'wbtr-inherited-value' : '';
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<Fragment key={property.name + breakpoint}>
|
|
140
|
+
{groups ? (
|
|
141
|
+
<SelectControl
|
|
142
|
+
label={property.label}
|
|
143
|
+
value={explicitValue}
|
|
144
|
+
help={property?.help}
|
|
145
|
+
disabled={disabled}
|
|
146
|
+
__nextHasNoMarginBottom
|
|
147
|
+
onChange={handleChange}
|
|
148
|
+
className={inheritedClassName}
|
|
149
|
+
>
|
|
150
|
+
<option value="">{placeholderText}</option>
|
|
151
|
+
{groups.map((group) => (
|
|
152
|
+
<optgroup key={group.label} label={group.label}>
|
|
153
|
+
{group.options.map((opt) => (
|
|
154
|
+
<option key={opt.value} value={opt.value}>
|
|
155
|
+
{opt.label}
|
|
156
|
+
</option>
|
|
157
|
+
))}
|
|
158
|
+
</optgroup>
|
|
159
|
+
))}
|
|
160
|
+
</SelectControl>
|
|
161
|
+
) : (
|
|
162
|
+
<SelectControl
|
|
163
|
+
label={property.label}
|
|
164
|
+
value={explicitValue}
|
|
165
|
+
help={property?.help}
|
|
166
|
+
disabled={disabled}
|
|
167
|
+
__nextHasNoMarginBottom
|
|
168
|
+
options={
|
|
169
|
+
isInherited
|
|
170
|
+
? [
|
|
171
|
+
{ label: placeholderText, value: '' },
|
|
172
|
+
...property.values.filter((o) => o.value !== ''),
|
|
173
|
+
]
|
|
174
|
+
: property.values
|
|
175
|
+
}
|
|
176
|
+
onChange={handleChange}
|
|
177
|
+
className={inheritedClassName}
|
|
178
|
+
/>
|
|
179
|
+
)}
|
|
180
|
+
</Fragment>
|
|
181
|
+
);
|
|
182
|
+
})}
|
|
183
|
+
</>
|
|
184
|
+
);
|
|
185
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { TabPanel } from '@wordpress/components';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
3
|
+
|
|
4
|
+
interface ResponsiveTabPanelProps {
|
|
5
|
+
breakpoints: string[];
|
|
6
|
+
/** Returns true when the breakpoint has at least one active value (renders `*` indicator) */
|
|
7
|
+
hasActiveSettings: (breakpoint: string) => boolean;
|
|
8
|
+
children: (breakpoint: string) => React.ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
/** Resolved twTheme.screens — used for breakpoint tooltip text */
|
|
11
|
+
screens?: Record<string, any>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extracts a human-readable min-width from a Tailwind screen value.
|
|
16
|
+
* Handles plain strings ('768px') and object configs ({ min: '768px' }).
|
|
17
|
+
*/
|
|
18
|
+
function resolveScreenValue(
|
|
19
|
+
screen: string | Record<string, string> | Record<string, string>[],
|
|
20
|
+
): string | null {
|
|
21
|
+
if (typeof screen === 'string') return screen;
|
|
22
|
+
if (Array.isArray(screen)) {
|
|
23
|
+
const entry = screen.find((s) => s.min);
|
|
24
|
+
return entry?.min ?? null;
|
|
25
|
+
}
|
|
26
|
+
if (typeof screen === 'object' && screen !== null) {
|
|
27
|
+
return screen.min ?? screen.raw ?? null;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getBreakpointTooltip(
|
|
33
|
+
bp: string,
|
|
34
|
+
screens?: Record<string, any>,
|
|
35
|
+
): string {
|
|
36
|
+
if (bp === 'basic') {
|
|
37
|
+
return __('min-width: 0px', 'webentor');
|
|
38
|
+
}
|
|
39
|
+
const raw = screens?.[bp];
|
|
40
|
+
if (!raw) return bp;
|
|
41
|
+
const value = resolveScreenValue(raw);
|
|
42
|
+
return value ? `min-width: ${value}` : bp;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Inline SVG that renders a breakpoint label as text.
|
|
47
|
+
* Used as TabPanel tab `icon` so WP's built-in tooltip activates
|
|
48
|
+
* (when icon is set, TabPanel shows `title` as the tooltip).
|
|
49
|
+
*/
|
|
50
|
+
function BreakpointIcon({ label }: { label: string }) {
|
|
51
|
+
const charWidth = 7.5;
|
|
52
|
+
const width = Math.max(20, label.length * charWidth + 6);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<svg
|
|
56
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
57
|
+
viewBox={`0 0 ${width} 20`}
|
|
58
|
+
width={width}
|
|
59
|
+
height={20}
|
|
60
|
+
>
|
|
61
|
+
<text
|
|
62
|
+
x={width / 2}
|
|
63
|
+
y={15}
|
|
64
|
+
textAnchor="middle"
|
|
65
|
+
fontSize="13"
|
|
66
|
+
fontWeight="inherit"
|
|
67
|
+
fill="currentColor"
|
|
68
|
+
>
|
|
69
|
+
{label}
|
|
70
|
+
</text>
|
|
71
|
+
</svg>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Shared responsive breakpoint tab wrapper.
|
|
77
|
+
* Uses icon-based tabs so TabPanel's built-in tooltip shows each
|
|
78
|
+
* breakpoint's min-width value on hover.
|
|
79
|
+
*/
|
|
80
|
+
export const ResponsiveTabPanel = ({
|
|
81
|
+
breakpoints,
|
|
82
|
+
hasActiveSettings,
|
|
83
|
+
children,
|
|
84
|
+
screens,
|
|
85
|
+
className = 'w-responsive-settings-tabs',
|
|
86
|
+
}: ResponsiveTabPanelProps) => {
|
|
87
|
+
return (
|
|
88
|
+
<TabPanel
|
|
89
|
+
activeClass="is-active"
|
|
90
|
+
className={className}
|
|
91
|
+
initialTabName={breakpoints[0]}
|
|
92
|
+
tabs={breakpoints.map((bp) => {
|
|
93
|
+
const active = hasActiveSettings(bp);
|
|
94
|
+
const label = `${bp}${active ? '*' : ''}`;
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
name: bp,
|
|
98
|
+
title: getBreakpointTooltip(bp, screens),
|
|
99
|
+
icon: <BreakpointIcon label={label} />,
|
|
100
|
+
};
|
|
101
|
+
})}
|
|
102
|
+
>
|
|
103
|
+
{(tab) => <>{children(tab.name)}</>}
|
|
104
|
+
</TabPanel>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
@@ -1,163 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Settings — Entry point.
|
|
3
|
+
*
|
|
4
|
+
* This module provides per-breakpoint block controls for spacing, layout,
|
|
5
|
+
* sizing, flexbox, grid, flex/grid item, border, and presets.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - Each setting module self-registers with the SettingsRegistry via side-effect imports
|
|
9
|
+
* - Panel components (SpacingPanel, DisplayLayoutPanel, BorderPanel) query the
|
|
10
|
+
* registry for their panelGroup and render each module's SettingsComponent
|
|
11
|
+
* - BlockEdit renders the panels in InspectorControls
|
|
12
|
+
*
|
|
13
|
+
* @see ./registry.ts — SettingsRegistry singleton
|
|
14
|
+
* @see ./migration.ts — display value helpers
|
|
15
|
+
*/
|
|
1
16
|
import { registerBlockExtension } from '@10up/block-components';
|
|
2
|
-
import { InspectorControls } from '@wordpress/block-editor';
|
|
17
|
+
import { BlockControls, InspectorControls } from '@wordpress/block-editor';
|
|
18
|
+
import { ToolbarGroup } from '@wordpress/components';
|
|
3
19
|
import { Fragment } from '@wordpress/element';
|
|
4
20
|
import { addFilter, applyFilters } from '@wordpress/hooks';
|
|
5
21
|
|
|
6
|
-
import { WebentorConfig } from '
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
import { WebentorConfig } from '../../types/_webentor-config';
|
|
23
|
+
import { AppliedClassesViewer } from './components/AppliedClassesViewer';
|
|
24
|
+
import { DebugPanel } from './components/DebugPanel';
|
|
25
|
+
import {
|
|
26
|
+
BlockLinkPanel,
|
|
27
|
+
BorderPanel,
|
|
28
|
+
DisplayLayoutPanel,
|
|
29
|
+
SpacingPanel,
|
|
30
|
+
} from './panels';
|
|
31
|
+
import { registry } from './registry';
|
|
13
32
|
import { generateClassNames, inlineStyleGenerator } from './utils';
|
|
14
33
|
|
|
34
|
+
// Side-effect imports: each module self-registers with the SettingsRegistry.
|
|
35
|
+
// Order doesn't matter — each module declares its own panelGroup and order.
|
|
36
|
+
import './settings/block-link';
|
|
37
|
+
import './settings/border';
|
|
38
|
+
import './settings/flex-item';
|
|
39
|
+
import './settings/flexbox';
|
|
40
|
+
import './settings/grid';
|
|
41
|
+
import './settings/grid-item';
|
|
42
|
+
import './settings/layout';
|
|
43
|
+
import './settings/presets';
|
|
44
|
+
import './settings/sizing';
|
|
45
|
+
import './settings/spacing';
|
|
46
|
+
|
|
15
47
|
const initResponsiveSettings = () => {
|
|
16
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Attribute registration filter.
|
|
50
|
+
* Iterates over all registered setting modules and merges their
|
|
51
|
+
* attribute schemas into blocks that declare support for them.
|
|
52
|
+
*/
|
|
17
53
|
addFilter(
|
|
18
54
|
'blocks.registerBlockType',
|
|
19
55
|
'webentor/addResponsiveSettingsAttributes',
|
|
20
56
|
(settings, name) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
settings?.supports?.webentor?.display
|
|
39
|
-
) {
|
|
40
|
-
const displaySupport =
|
|
41
|
-
settings?.supports?.webentor?.display === true ||
|
|
42
|
-
settings?.supports?.webentor?.display?.display === true;
|
|
43
|
-
|
|
44
|
-
settings.attributes = {
|
|
45
|
-
...settings.attributes,
|
|
46
|
-
...{
|
|
47
|
-
display: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
default: {
|
|
50
|
-
...settings?.attributes?.display?.default,
|
|
51
|
-
display: {
|
|
52
|
-
value: {
|
|
53
|
-
// Default display is FLEX
|
|
54
|
-
...(displaySupport ? { basic: 'flex' } : {}),
|
|
55
|
-
...settings?.attributes?.display?.default?.display?.value,
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
includedBlocks['spacing'].includes(name) ||
|
|
66
|
-
settings?.supports?.webentor?.spacing
|
|
67
|
-
) {
|
|
68
|
-
settings.attributes = {
|
|
69
|
-
...settings.attributes,
|
|
70
|
-
...{
|
|
71
|
-
spacing: {
|
|
72
|
-
type: 'object',
|
|
73
|
-
default: settings.attributes?.spacing?.default || {},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
includedBlocks['grid'].includes(name) ||
|
|
81
|
-
settings?.supports?.webentor?.grid
|
|
82
|
-
) {
|
|
83
|
-
settings.attributes = {
|
|
84
|
-
...settings.attributes,
|
|
85
|
-
...{
|
|
86
|
-
grid: {
|
|
87
|
-
type: 'object',
|
|
88
|
-
default: settings.attributes?.grid?.default || {},
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
includedBlocks['gridItem'].includes(name) ||
|
|
96
|
-
settings?.supports?.webentor?.gridItem
|
|
97
|
-
) {
|
|
98
|
-
settings.attributes = {
|
|
99
|
-
...settings.attributes,
|
|
100
|
-
...{
|
|
101
|
-
gridItem: {
|
|
102
|
-
type: 'object',
|
|
103
|
-
default: settings.attributes?.gridItem?.default || {},
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
includedBlocks['flexbox'].includes(name) ||
|
|
111
|
-
settings?.supports?.webentor?.flexbox
|
|
112
|
-
) {
|
|
113
|
-
settings.attributes = {
|
|
114
|
-
...settings.attributes,
|
|
115
|
-
...{
|
|
116
|
-
flexbox: {
|
|
117
|
-
type: 'object',
|
|
118
|
-
default: settings.attributes?.flexbox?.default || {},
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
includedBlocks['flexboxItem'].includes(name) ||
|
|
126
|
-
settings?.supports?.webentor?.flexboxItem
|
|
127
|
-
) {
|
|
128
|
-
settings.attributes = {
|
|
129
|
-
...settings.attributes,
|
|
130
|
-
...{
|
|
131
|
-
flexboxItem: {
|
|
132
|
-
type: 'object',
|
|
133
|
-
default: settings.attributes?.flexboxItem?.default || {},
|
|
57
|
+
const allDefs = registry.getAll();
|
|
58
|
+
|
|
59
|
+
for (const def of allDefs) {
|
|
60
|
+
const supportedByRegistry = registry.isSupported(
|
|
61
|
+
settings?.supports,
|
|
62
|
+
def,
|
|
63
|
+
);
|
|
64
|
+
if (!supportedByRegistry) continue;
|
|
65
|
+
|
|
66
|
+
// Merge attribute schemas from the module definition
|
|
67
|
+
for (const [attrKey, schema] of Object.entries(def.attributeSchema)) {
|
|
68
|
+
settings.attributes = {
|
|
69
|
+
...settings.attributes,
|
|
70
|
+
[attrKey]: {
|
|
71
|
+
...schema,
|
|
72
|
+
default:
|
|
73
|
+
settings.attributes?.[attrKey]?.default || schema.default,
|
|
134
74
|
},
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
138
77
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
settings?.supports?.webentor?.borderRadius
|
|
144
|
-
) {
|
|
145
|
-
settings.attributes = {
|
|
146
|
-
...settings.attributes,
|
|
147
|
-
...{
|
|
148
|
-
border: {
|
|
149
|
-
type: 'object',
|
|
150
|
-
default: settings.attributes?.border?.default || {},
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
};
|
|
78
|
+
// Custom attribute initialiser (e.g. display flex default)
|
|
79
|
+
if (def.initAttributes) {
|
|
80
|
+
settings = def.initAttributes(settings, name);
|
|
81
|
+
}
|
|
154
82
|
}
|
|
155
83
|
|
|
156
84
|
return settings;
|
|
157
85
|
},
|
|
158
86
|
);
|
|
159
87
|
|
|
160
|
-
// Register block extension for all blocks
|
|
161
88
|
registerBlockExtension('*', {
|
|
162
89
|
extensionName: 'webentor.core.addResponsiveSettings',
|
|
163
90
|
attributes: {},
|
|
@@ -168,26 +95,48 @@ const initResponsiveSettings = () => {
|
|
|
168
95
|
});
|
|
169
96
|
};
|
|
170
97
|
|
|
171
|
-
|
|
172
|
-
|
|
98
|
+
/**
|
|
99
|
+
* BlockEdit — renders InspectorControls panels for responsive settings.
|
|
100
|
+
*
|
|
101
|
+
* Uses panel wrappers (SpacingPanel, DisplayLayoutPanel, BorderPanel, BlockLinkPanel)
|
|
102
|
+
* which internally query the registry for their panelGroup's modules.
|
|
103
|
+
*
|
|
104
|
+
* Responsive settings migration is handled globally in PHP.
|
|
105
|
+
*/
|
|
106
|
+
const BlockEdit = (props: any) => {
|
|
107
|
+
const breakpoints = applyFilters('webentor.core.twBreakpoints', [
|
|
173
108
|
'basic',
|
|
174
|
-
]);
|
|
175
|
-
const twTheme
|
|
109
|
+
]) as string[];
|
|
110
|
+
const twTheme = applyFilters(
|
|
176
111
|
'webentor.core.twTheme',
|
|
177
112
|
{},
|
|
178
|
-
);
|
|
113
|
+
) as WebentorConfig['theme'];
|
|
179
114
|
|
|
180
115
|
return (
|
|
181
116
|
<Fragment>
|
|
117
|
+
<BlockControls>
|
|
118
|
+
<ToolbarGroup>
|
|
119
|
+
<AppliedClassesViewer
|
|
120
|
+
{...props}
|
|
121
|
+
breakpoints={breakpoints}
|
|
122
|
+
twTheme={twTheme}
|
|
123
|
+
/>
|
|
124
|
+
</ToolbarGroup>
|
|
125
|
+
</BlockControls>
|
|
182
126
|
<InspectorControls>
|
|
183
127
|
<SpacingPanel {...props} breakpoints={breakpoints} twTheme={twTheme} />
|
|
184
|
-
<
|
|
128
|
+
<DisplayLayoutPanel
|
|
185
129
|
{...props}
|
|
186
130
|
breakpoints={breakpoints}
|
|
187
131
|
twTheme={twTheme}
|
|
188
132
|
/>
|
|
189
133
|
<BorderPanel {...props} breakpoints={breakpoints} twTheme={twTheme} />
|
|
190
|
-
<BlockLinkPanel
|
|
134
|
+
<BlockLinkPanel
|
|
135
|
+
{...props}
|
|
136
|
+
breakpoints={breakpoints}
|
|
137
|
+
twTheme={twTheme}
|
|
138
|
+
/>
|
|
139
|
+
<DebugPanel {...props} breakpoints={breakpoints} twTheme={twTheme} />
|
|
191
140
|
</InspectorControls>
|
|
192
141
|
</Fragment>
|
|
193
142
|
);
|