Skip to content

Commit 6c841fc

Browse files
committed
refactor: add IconTab, OverlayTab, and TextTab extract into components for Infotip format
1 parent 4c81510 commit 6c841fc

File tree

9 files changed

+474
-570
lines changed

9 files changed

+474
-570
lines changed

src/infotip/components/icon-tab.js

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { PanelColorSettings } from '@wordpress/block-editor';
6+
import { useSelect } from '@wordpress/data';
7+
import {
8+
Button,
9+
ToggleControl,
10+
__experimentalToggleGroupControl as ToggleGroupControl, // eslint-disable-line
11+
__experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, // eslint-disable-line
12+
__experimentalGrid as Grid,
13+
} from '@wordpress/components';
14+
15+
/**
16+
* Internal dependencies
17+
*/
18+
import { ICONS } from '../../constant';
19+
import { justifyLeft, justifyRight } from '@wordpress/icons';
20+
21+
/**
22+
* IconTab component for the Icon tab in the Infotip format.
23+
*
24+
* @param {Object} props - The component properties.
25+
* @param {Object} props.activeAttributes - The currently active attributes.
26+
* @param {Function} props.updateAttributes - Function to update the attributes.
27+
* @param {Function} props.removeAttributes - Function to remove attributes.
28+
* @returns {JSX.Element} - The rendered IconTab component.
29+
*/
30+
function IconTab({
31+
activeAttributes,
32+
updateAttributes,
33+
removeAttributes,
34+
}) {
35+
const { selectedBlock, colors } = useSelect((select) => {
36+
const editor = select('core/block-editor');
37+
return {
38+
selectedBlock: editor.getSelectedBlock(),
39+
colors: (editor.getSettings() || {}).colors || [],
40+
};
41+
}, []);
42+
43+
const blockStyle = selectedBlock?.attributes?.style || {};
44+
const explicitTextColor = blockStyle?.color?.text;
45+
const textColorSlug = selectedBlock?.attributes?.textColor;
46+
const slugColor =
47+
textColorSlug &&
48+
colors.find((c) => c.slug === textColorSlug)?.color;
49+
const defaultIconColor = explicitTextColor || slugColor;
50+
51+
const isIconEnabled = activeAttributes['icon-enabled'] === 'true';
52+
53+
const resetIcon = () => removeAttributes(['icon-enabled', 'icon-position', 'icon-color', 'icon-type']);
54+
55+
const handleToggleIcon = () => {
56+
if (isIconEnabled) {
57+
resetIcon();
58+
} else {
59+
updateAttributes({ 'icon-enabled': 'true' });
60+
}
61+
};
62+
63+
// Show the info icon enabled as a default when no icon type is set, and icons are just enabled.
64+
if (isIconEnabled && !activeAttributes['icon-type']) {
65+
updateAttributes({ 'icon-type': 'info' });
66+
}
67+
68+
return (
69+
<>
70+
<Grid columns={2} templateColumns="3fr 7fr" alignment="center">
71+
<div className="icon-tab-label">
72+
{__('Enable', 'blablablocks-formats')}
73+
</div>
74+
<ToggleControl checked={isIconEnabled} onChange={handleToggleIcon} />
75+
76+
{isIconEnabled && (
77+
<>
78+
<div className="icon-tab-label">
79+
{__('Type', 'blablablocks-formats')}
80+
</div>
81+
<div>
82+
{ICONS.map((icon) => (
83+
<Button
84+
accessibleWhenDisabled
85+
key={icon.id}
86+
icon={icon.graphic}
87+
isPressed={
88+
activeAttributes['icon-type'] === icon.id
89+
}
90+
onClick={() => updateAttributes({ 'icon-type': icon.id })}
91+
/>
92+
))}
93+
</div>
94+
95+
<div className="icon-tab-label">
96+
{__('Position', 'blablablocks-formats')}
97+
</div>
98+
<ToggleGroupControl
99+
__nextHasNoMarginBottom
100+
__next40pxDefaultSize
101+
hideLabelFromVision
102+
label={__('Position', 'blablablocks-formats')}
103+
value={activeAttributes['icon-position'] || 'left'}
104+
onChange={(value) => updateAttributes({ 'icon-position': value })}
105+
>
106+
<ToggleGroupControlOptionIcon
107+
aria-label={__(
108+
'Left icon position',
109+
'blablablocks-formats'
110+
)}
111+
label={__('Left', 'blablablocks-formats')}
112+
icon={justifyLeft}
113+
value="left"
114+
/>
115+
<ToggleGroupControlOptionIcon
116+
aria-label={__(
117+
'Right icon position',
118+
'blablablocks-formats'
119+
)}
120+
label={__('Right', 'blablablocks-formats')}
121+
icon={justifyRight}
122+
value="right"
123+
/>
124+
</ToggleGroupControl>
125+
126+
<div className="icon-tab-label">
127+
{__('Color', 'blablablocks-formats')}
128+
</div>
129+
<PanelColorSettings
130+
label={__('Color', 'blablablocks-formats')}
131+
className="icon-color-settings"
132+
colorSettings={[
133+
{
134+
label: __('Icon', 'blablablocks-formats'),
135+
value: activeAttributes['icon-color'] || defaultIconColor,
136+
onChange: (value) => updateAttributes({ 'icon-color': value || defaultIconColor }),
137+
},
138+
]}
139+
/>
140+
</>
141+
)}
142+
</Grid>
143+
<Button
144+
accessibleWhenDisabled
145+
className="reset-button"
146+
disabled={!isIconEnabled}
147+
onClick={resetIcon}
148+
variant="tertiary"
149+
__next40pxDefaultSize
150+
>
151+
{__('Clear', 'blablablocks-formats')}
152+
</Button>
153+
</>
154+
);
155+
}
156+
157+
export default IconTab;

src/infotip/components/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* Export components
3+
*/
4+
export { default as IconTab } from './icon-tab';
5+
export { default as OverlayTab } from './overlay-tab';
6+
export { default as TextTab } from './text-tab';
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { PanelColorSettings } from '@wordpress/block-editor';
6+
import {
7+
Button,
8+
SelectControl,
9+
__experimentalNumberControl as NumberControl, // eslint-disable-line
10+
__experimentalGrid as Grid, // eslint-disable-line
11+
} from '@wordpress/components';
12+
13+
/**
14+
* Internal dependencies
15+
*/
16+
import { PLACEMENT_OPTIONS } from '../../constant';
17+
18+
/**
19+
* OverlayTab component for the Overlay tab in the Infotip format.
20+
*
21+
* @param {Object} props - The component properties.
22+
* @param {Object} props.activeAttributes - The currently active attributes.
23+
* @param {Function} props.updateAttributes - Function to update the attributes.
24+
* @param {Function} props.removeAttributes - Function to remove attributes.
25+
* @returns {JSX.Element} - The rendered OverlayTab component.
26+
*/
27+
function OverlayTab({
28+
activeAttributes,
29+
updateAttributes,
30+
removeAttributes,
31+
}) {
32+
const overLaySettingsEnabled =
33+
activeAttributes['overlay-placement'] ||
34+
activeAttributes['overlay-background-color'] ||
35+
activeAttributes['overlay-text-color'] ||
36+
activeAttributes.offset;
37+
38+
const handleColorChange = (type, newColor) => {
39+
updateAttributes({
40+
[type]:
41+
newColor ||
42+
(type === 'overlay-background-color' ? '#222222' : '#FFFFFF'),
43+
});
44+
};
45+
46+
const handleReset = () => {
47+
removeAttributes([
48+
'overlay-placement',
49+
'overlay-background-color',
50+
'overlay-text-color',
51+
'offset',
52+
]);
53+
};
54+
55+
return (
56+
<>
57+
<Grid columns={2} templateColumns="3fr 7fr" alignment="center">
58+
<div className="overlay-tab-label">
59+
{__('Offset', 'blablablocks-formats')}
60+
</div>
61+
<NumberControl
62+
hideLabelFromVision
63+
label={__('Offset', 'blablablocks-formats')}
64+
value={activeAttributes.offset || 6}
65+
__next40pxDefaultSize
66+
onChange={(value) => updateAttributes({ offset: value || 6 })}
67+
style={{ width: '5rem' }}
68+
min={6}
69+
max={20}
70+
/>
71+
72+
<div className="overlay-tab-label">
73+
{__('Placement', 'blablablocks-formats')}
74+
</div>
75+
<SelectControl
76+
label={__('Placement', 'blablablocks-formats')}
77+
hideLabelFromVision
78+
__next40pxDefaultSize
79+
__nextHasNoMarginBottom
80+
value={activeAttributes['overlay-placement'] || 'top'}
81+
options={PLACEMENT_OPTIONS}
82+
onChange={(selectedOption) => updateAttributes({ 'overlay-placement': selectedOption })}
83+
onClick={(event) => event.stopPropagation()}
84+
/>
85+
86+
<div className="overlay-tab-label">
87+
{__('Color', 'blablablocks-formats')}
88+
</div>
89+
<PanelColorSettings
90+
className="overlay-color-settings"
91+
label={__('Color', 'blablablocks-formats')}
92+
colorSettings={[
93+
{
94+
label: __('Background', 'blablablocks-formats'),
95+
value:
96+
activeAttributes[
97+
'overlay-background-color'
98+
] || '#222222',
99+
onChange: (newColor) =>
100+
handleColorChange(
101+
'overlay-background-color',
102+
newColor
103+
),
104+
},
105+
{
106+
label: __('Text', 'blablablocks-formats'),
107+
value:
108+
activeAttributes['overlay-text-color'] ||
109+
'#FFFFFF',
110+
onChange: (newColor) =>
111+
handleColorChange(
112+
'overlay-text-color',
113+
newColor
114+
),
115+
},
116+
]}
117+
/>
118+
</Grid>
119+
<Button
120+
accessibleWhenDisabled
121+
className="reset-button"
122+
disabled={!overLaySettingsEnabled}
123+
onClick={handleReset}
124+
variant="tertiary"
125+
__next40pxDefaultSize
126+
>
127+
{__('Clear', 'blablablocks-formats')}
128+
</Button>
129+
</>
130+
);
131+
}
132+
133+
export default OverlayTab;

src/infotip/components/text-tab.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import {
6+
Button,
7+
ToggleControl,
8+
TextareaControl,
9+
__experimentalVStack as VStack, // eslint-disable-line
10+
} from '@wordpress/components';
11+
import { removeFormat } from '@wordpress/rich-text';
12+
import { safeHTML } from '@wordpress/dom';
13+
14+
/**
15+
* TextTab component for the Text tab in the Infotip format.
16+
*
17+
* @param {Object} props - The component properties.
18+
* @param {Object} props.activeAttributes - The currently active attributes.
19+
* @param {string} props.name - The name of the format.
20+
* @param {Function} props.onChange - Function to handle changes in the text.
21+
* @param {Function} props.onClose - Function to call when the tab is closed.
22+
* @param {Function} props.removeAttributes - Function to remove attributes.
23+
* @param {Function} props.updateAttributes - Function to update attributes.
24+
* @param {string} props.value - The current value of the text.
25+
* @return {JSX.Element} - The rendered TextTabContent component.
26+
*/
27+
function TextTab({
28+
activeAttributes,
29+
name,
30+
onChange,
31+
onClose,
32+
removeAttributes,
33+
updateAttributes,
34+
value,
35+
}) {
36+
const handleTextChange = (newValue) => {
37+
const sanitizedValue = safeHTML(newValue);
38+
updateAttributes({ content: sanitizedValue });
39+
};
40+
41+
const handleUnderlineToggle = (enabled) => {
42+
if (enabled) {
43+
updateAttributes({ underline: value });
44+
} else {
45+
removeAttributes(['underline']);
46+
}
47+
};
48+
49+
const handleClear = () => {
50+
onChange(removeFormat(value, name));
51+
onClose?.();
52+
};
53+
54+
return (
55+
<VStack spacing={6}>
56+
<TextareaControl
57+
label={__('Text', 'blablablocks-formats')}
58+
onChange={handleTextChange}
59+
placeholder={__(
60+
'Enter the text to display, or click clear to remove the format.',
61+
'blablablocks-formats'
62+
)}
63+
value={activeAttributes.content}
64+
__nextHasNoMarginBottom
65+
/>
66+
<ToggleControl
67+
id="underline-toggle"
68+
label={__('Underline anchor text', 'blablablocks-formats')}
69+
checked={activeAttributes.underline}
70+
onChange={handleUnderlineToggle}
71+
__nextHasNoMarginBottom
72+
/>
73+
<Button
74+
accessibleWhenDisabled
75+
className="reset-button"
76+
onClick={handleClear}
77+
variant="tertiary"
78+
__next40pxDefaultSize
79+
>
80+
{__('Clear', 'blablablocks-formats')}
81+
</Button>
82+
</VStack>
83+
);
84+
}
85+
86+
export default TextTab;

0 commit comments

Comments
 (0)