PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / tooltip / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/tooltip/index.js

325 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var RichText = wp.blockEditor.RichText;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var PanelBody = wp.components.PanelBody;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var TextControl = wp.components.TextControl;
16 var TextareaControl = wp.components.TextareaControl;
17
18 // Resolve the shared components lazily without defining globals for each block.
19 function _tc(props, key, label) {
20 var Control = window.bkbgTypographyControl;
21 return Control ? el(Control, {
22 label: label,
23 value: props.attributes[key] || {},
24 onChange: function (value) { var update = {}; update[key] = value; props.setAttributes(update); }
25 }) : null;
26 }
27 function _tvf(typo, prefix) {
28 var cssVars = window.bkbgTypoCssVars;
29 return cssVars ? cssVars(typo || {}, prefix) : {};
30 }
31 function getTypoControl(props, attrName, label) { return _tc(props, attrName, label); }
32
33 var POSITION_OPTIONS = [
34 { label: 'Top', value: 'top' },
35 { label: 'Bottom', value: 'bottom' },
36 { label: 'Left', value: 'left' },
37 { label: 'Right', value: 'right' },
38 ];
39
40 var STYLE_OPTIONS = [
41 { label: 'Dotted underline', value: 'underline-dotted' },
42 { label: 'Solid underline', value: 'underline-solid' },
43 { label: 'Dashed underline', value: 'underline-dashed' },
44 { label: 'Highlight', value: 'highlight' },
45 { label: 'Bold', value: 'bold' },
46 { label: 'Italic', value: 'italic' },
47 { label: 'None', value: 'none' },
48 ];
49
50 var ANIM_OPTIONS = [
51 { label: 'Fade', value: 'fade' },
52 { label: 'Scale up', value: 'scale' },
53 { label: 'Bounce', value: 'bounce' },
54 { label: 'Zoom out', value: 'zoom-out' },
55 { label: 'Slide down', value: 'slide-down' },
56 { label: 'Slide up', value: 'slide-up' },
57 { label: 'Slide left', value: 'slide-left' },
58 { label: 'Slide right', value: 'slide-right' },
59 { label: 'Blur', value: 'blur' },
60 { label: 'Flip', value: 'flip' },
61 { label: 'Rotate', value: 'rotate' },
62 { label: 'None', value: 'none' },
63 ];
64
65 var WEIGHT_OPTIONS = [
66 { label: 'Normal (400)', value: '400' },
67 { label: 'Medium (500)', value: '500' },
68 { label: 'Semi-bold (600)', value: '600' },
69 { label: 'Bold (700)', value: '700' },
70 ];
71
72 var ALIGN_OPTIONS = [
73 { label: 'Left', value: 'left' },
74 { label: 'Center', value: 'center' },
75 { label: 'Right', value: 'right' },
76 ];
77
78 function getTriggerStyle(a) {
79 var style = {
80 color: a.triggerColor,
81 cursor: 'help',
82 display: 'inline-block',
83 };
84 if (a.triggerStyle === 'underline-dotted') {
85 style.textDecoration = 'underline';
86 style.textDecorationStyle = 'dotted';
87 style.textDecorationColor = a.underlineColor;
88 } else if (a.triggerStyle === 'underline-solid') {
89 style.textDecoration = 'underline';
90 style.textDecorationColor = a.underlineColor;
91 } else if (a.triggerStyle === 'underline-dashed') {
92 style.textDecoration = 'underline';
93 style.textDecorationStyle = 'dashed';
94 style.textDecorationColor = a.underlineColor;
95 } else if (a.triggerStyle === 'highlight') {
96 style.background = a.highlightBg;
97 style.borderRadius = '4px';
98 style.padding = '0 4px';
99 } else if (a.triggerStyle === 'bold') {
100 style.fontWeight = '700';
101 } else if (a.triggerStyle === 'italic') {
102 style.fontStyle = 'italic';
103 }
104 return style;
105 }
106
107 registerBlockType('blockenberg/tooltip', {
108 title: __('Tooltip', 'blockenberg'),
109 icon: 'info',
110 category: 'bkbg-content',
111 description: __('Hover tooltip with trigger text and informational popup.', 'blockenberg'),
112
113 edit: function (props) {
114 var a = props.attributes;
115 var set = props.setAttributes;
116 var showPreview = useState(false);
117 var isPreviewOpen = showPreview[0];
118 var setPreviewOpen = showPreview[1];
119
120 var blockProps = (function () {
121 var s = { textAlign: a.align };
122 Object.assign(s, _tvf(a.triggerTypo, '--bkttp-tr-'), _tvf(a.tooltipTypo, '--bkttp-tp-'));
123 return useBlockProps({ style: s });
124 })();
125
126 return el(Fragment, null,
127 el(InspectorControls, null,
128 // Content
129 el(PanelBody, { title: 'Content', initialOpen: true },
130 el(TextControl, {
131 label: 'Trigger Text (visible)',
132 value: a.triggerText,
133 onChange: function (v) { set({ triggerText: v }); },
134 __nextHasNoMarginBottom: true,
135 }),
136 el('div', { style: { height: 10 } }),
137 el(TextareaControl, {
138 label: 'Tooltip Content (popup)',
139 value: a.tooltipContent,
140 rows: 4,
141 onChange: function (v) { set({ tooltipContent: v }); },
142 __nextHasNoMarginBottom: true,
143 })
144 ),
145
146 // Appearance
147 el(PanelBody, { title: 'Trigger Style', initialOpen: false },
148 el(SelectControl, { label: 'Trigger style', value: a.triggerStyle, options: STYLE_OPTIONS, onChange: function (v) { set({ triggerStyle: v }); }, __nextHasNoMarginBottom: true }),
149 el('div', { style: { height: 10 } }),
150 el(SelectControl, { label: 'Text alignment', value: a.align, options: ALIGN_OPTIONS, onChange: function (v) { set({ align: v }); }, __nextHasNoMarginBottom: true }),
151 el('div', { style: { height: 10 } }),
152 el('div', { style: { height: 10 } }),
153 ),
154
155 // Tooltip popup
156 el(PanelBody, { title: 'Tooltip Popup', initialOpen: false },
157 el(SelectControl, { label: 'Position', value: a.position, options: POSITION_OPTIONS, onChange: function (v) { set({ position: v }); }, __nextHasNoMarginBottom: true }),
158 el('div', { style: { height: 10 } }),
159 el(SelectControl, { label: 'Animation', value: a.animationType, options: ANIM_OPTIONS, onChange: function (v) { set({ animationType: v }); }, __nextHasNoMarginBottom: true }),
160 el('div', { style: { height: 10 } }),
161 el(RangeControl, { label: 'Max width (px)', value: a.maxWidth, min: 150, max: 480, onChange: function (v) { set({ maxWidth: v }); }, __nextHasNoMarginBottom: true }),
162 el('div', { style: { height: 10 } }),
163 el(RangeControl, { label: 'Padding (px)', value: a.tooltipPadding, min: 6, max: 24, onChange: function (v) { set({ tooltipPadding: v }); }, __nextHasNoMarginBottom: true }),
164 el('div', { style: { height: 10 } }),
165 el(RangeControl, { label: 'Border radius (px)', value: a.tooltipRadius, min: 0, max: 24, onChange: function (v) { set({ tooltipRadius: v }); }, __nextHasNoMarginBottom: true }),
166 el('div', { style: { height: 10 } }),
167 el('div', { style: { height: 10 } }),
168 el(ToggleControl, { label: 'Show arrow', checked: a.showArrow, onChange: function (v) { set({ showArrow: v }); }, __nextHasNoMarginBottom: true })
169 ),
170
171 // Colors
172
173 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
174 getTypoControl(props, 'triggerTypo', __('Trigger', 'blockenberg')),
175 getTypoControl(props, 'tooltipTypo', __('Tooltip', 'blockenberg'))
176 ),
177 el(PanelColorSettings, {
178 title: 'Colors',
179 initialOpen: false,
180 colorSettings: [
181 { label: 'Trigger Text Color', value: a.triggerColor, onChange: function (v) { set({ triggerColor: v || '#6366f1' }); } },
182 { label: 'Underline / Accent Color', value: a.underlineColor, onChange: function (v) { set({ underlineColor: v || '#6366f1' }); } },
183 { label: 'Highlight Background', value: a.highlightBg, onChange: function (v) { set({ highlightBg: v || '#ede9fe' }); } },
184 { label: 'Tooltip Background', value: a.tooltipBg, onChange: function (v) { set({ tooltipBg: v || '#1e293b' }); } },
185 { label: 'Tooltip Text Color', value: a.tooltipColor, onChange: function (v) { set({ tooltipColor: v || '#f8fafc' }); } },
186 ]
187 })
188 ),
189
190 // ── Editor Preview ──
191 el('div', blockProps,
192 el('div', {
193 style: { display: 'inline-block', position: 'relative' },
194 onMouseEnter: function () { setPreviewOpen(true); },
195 onMouseLeave: function () { setPreviewOpen(false); },
196 },
197 el('span', { style: getTriggerStyle(a) }, a.triggerText),
198 // Always in DOM so CSS transition works (same as frontend)
199 el('div', {
200 style: (function () {
201 var isLR = a.position === 'left' || a.position === 'right';
202 var anim = a.animationType || 'fade';
203 // Base transform (hidden state offset)
204 var hiddenTransform;
205 if (a.position === 'top') hiddenTransform = 'translateX(-50%) translateY(4px)';
206 else if (a.position === 'bottom') hiddenTransform = 'translateX(-50%) translateY(-4px)';
207 else if (a.position === 'left') hiddenTransform = 'translateY(-50%) translateX(4px)';
208 else hiddenTransform = 'translateY(-50%) translateX(-4px)';
209
210 var visibleTransform;
211 if (a.position === 'top' || a.position === 'bottom') visibleTransform = 'translateX(-50%) translateY(0)';
212 else visibleTransform = 'translateY(-50%) translateX(0)';
213
214 var customTransition = null;
215 var hiddenFilter = null;
216 var visibleFilter = null;
217
218 if (anim === 'scale') {
219 hiddenTransform = isLR ? 'translateY(-50%) scale(0.9)' : 'translateX(-50%) scale(0.9)';
220 visibleTransform = isLR ? 'translateY(-50%) scale(1)' : 'translateX(-50%) scale(1)';
221 } else if (anim === 'bounce') {
222 hiddenTransform = isLR ? 'translateY(-50%) scale(0.6)' : 'translateX(-50%) scale(0.6)';
223 visibleTransform = isLR ? 'translateY(-50%) scale(1)' : 'translateX(-50%) scale(1)';
224 customTransition = 'opacity 0.4s cubic-bezier(0.34,1.56,0.64,1), transform 0.4s cubic-bezier(0.34,1.56,0.64,1), visibility 0.4s';
225 } else if (anim === 'zoom-out') {
226 hiddenTransform = isLR ? 'translateY(-50%) scale(1.25)' : 'translateX(-50%) scale(1.25)';
227 visibleTransform = isLR ? 'translateY(-50%) scale(1)' : 'translateX(-50%) scale(1)';
228 } else if (anim === 'slide-down') {
229 hiddenTransform = isLR ? hiddenTransform : 'translateX(-50%) translateY(-8px)';
230 visibleTransform = isLR ? visibleTransform : 'translateX(-50%) translateY(0)';
231 } else if (anim === 'slide-up') {
232 hiddenTransform = isLR ? hiddenTransform : 'translateX(-50%) translateY(8px)';
233 visibleTransform = isLR ? visibleTransform : 'translateX(-50%) translateY(0)';
234 } else if (anim === 'slide-left') {
235 hiddenTransform = isLR ? hiddenTransform : 'translateX(calc(-50% + 12px))';
236 visibleTransform = isLR ? visibleTransform : 'translateX(-50%)';
237 } else if (anim === 'slide-right') {
238 hiddenTransform = isLR ? hiddenTransform : 'translateX(calc(-50% - 12px))';
239 visibleTransform = isLR ? visibleTransform : 'translateX(-50%)';
240 } else if (anim === 'blur') {
241 hiddenTransform = isLR ? 'translateY(-50%)' : 'translateX(-50%)';
242 visibleTransform = isLR ? 'translateY(-50%)' : 'translateX(-50%)';
243 hiddenFilter = 'blur(6px)';
244 visibleFilter = 'blur(0px)';
245 customTransition = 'opacity 0.25s ease, transform 0.25s ease, filter 0.25s ease, visibility 0.25s';
246 } else if (anim === 'flip') {
247 hiddenTransform = isLR ? 'translateY(-50%) perspective(400px) rotateY(-90deg)' : 'translateX(-50%) perspective(400px) rotateX(-80deg)';
248 visibleTransform = isLR ? 'translateY(-50%) perspective(400px) rotateY(0deg)' : 'translateX(-50%) perspective(400px) rotateX(0deg)';
249 customTransition = 'opacity 0.3s ease, transform 0.3s ease, visibility 0.3s';
250 } else if (anim === 'rotate') {
251 hiddenTransform = isLR ? 'translateY(-50%) rotate(-10deg) scale(0.88)' : 'translateX(-50%) rotate(-10deg) scale(0.88)';
252 visibleTransform = isLR ? 'translateY(-50%) rotate(0deg) scale(1)' : 'translateX(-50%) rotate(0deg) scale(1)';
253 } else if (anim === 'none') {
254 hiddenTransform = isLR ? 'translateY(-50%)' : 'translateX(-50%)';
255 visibleTransform = isLR ? 'translateY(-50%)' : 'translateX(-50%)';
256 }
257
258 var baseStyle = {
259 position: 'absolute',
260 bottom: a.position === 'bottom' ? 'auto' : (isLR ? 'auto' : 'calc(100% + 10px)'),
261 top: a.position === 'bottom' ? 'calc(100% + 10px)' : (isLR ? '50%' : 'auto'),
262 left: a.position === 'right' ? 'calc(100% + 10px)' : (isLR ? 'auto' : '50%'),
263 right: a.position === 'left' ? 'calc(100% + 10px)' : 'auto',
264 maxWidth: a.maxWidth + 'px',
265 minWidth: 140,
266 background: a.tooltipBg,
267 color: a.tooltipColor,
268 fontSize: undefined,
269 lineHeight: undefined,
270 padding: a.tooltipPadding + 'px',
271 borderRadius: a.tooltipRadius + 'px',
272 zIndex: 9999,
273 boxShadow: '0 8px 24px rgba(0,0,0,0.18)',
274 pointerEvents: 'none',
275 whiteSpace: 'normal',
276 opacity: isPreviewOpen ? 1 : 0,
277 visibility: isPreviewOpen ? 'visible' : 'hidden',
278 transform: isPreviewOpen ? visibleTransform : hiddenTransform,
279 transition: customTransition || (anim === 'none'
280 ? 'opacity 0s, visibility 0s'
281 : 'opacity 0.22s ease, transform 0.22s ease, visibility 0.22s'),
282 };
283 if (hiddenFilter !== null) {
284 baseStyle.filter = isPreviewOpen ? visibleFilter : hiddenFilter;
285 }
286 return baseStyle;
287 }())
288 },
289 a.tooltipContent,
290 a.showArrow && el('div', {
291 style: {
292 position: 'absolute',
293 width: 0, height: 0,
294 bottom: a.position !== 'bottom' ? -6 : 'auto',
295 top: a.position === 'bottom' ? -6 : 'auto',
296 left: (a.position === 'top' || a.position === 'bottom') ? '50%' : 'auto',
297 transform: (a.position === 'top' || a.position === 'bottom') ? 'translateX(-50%)' : undefined,
298 borderLeft: (a.position === 'top' || a.position === 'bottom') ? '6px solid transparent' : 'none',
299 borderRight: (a.position === 'top' || a.position === 'bottom') ? '6px solid transparent' : 'none',
300 borderTop: a.position === 'top' ? '6px solid ' + a.tooltipBg : 'none',
301 borderBottom: a.position === 'bottom' ? '6px solid ' + a.tooltipBg : 'none',
302 }
303 })
304 )
305 ),
306 el('p', { style: { fontSize: 11, color: '#9ca3af', margin: '8px 0 0' } },
307 '💡 Hover the text above to preview the tooltip.'
308 )
309 )
310 );
311 },
312
313 save: function (props) {
314 var bp = (function () {
315 var tv = Object.assign({}, _tvf(props.attributes.triggerTypo, '--bkttp-tr-'), _tvf(props.attributes.tooltipTypo, '--bkttp-tp-'));
316 var parts = []; Object.keys(tv).forEach(function (k) { parts.push(k + ':' + tv[k]); });
317 return useBlockProps.save(parts.length ? { style: parts.join(';') } : {});
318 })();
319 return el('div', bp,
320 el('div', { className: 'bkbg-tt-app', 'data-opts': JSON.stringify(props.attributes) })
321 );
322 }
323 });
324 }() );
325