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 / word-flip / index.js

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

166 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = React.createElement;
3 var registerBlockType = wp.blocks.registerBlockType;
4 var useBlockProps = wp.blockEditor.useBlockProps;
5
6 // Resolve the shared components lazily without defining globals for each block.
7 function _tc(label, key, attrs, setA) {
8 var Control = window.bkbgTypographyControl;
9 return Control ? el(Control, {
10 label: label,
11 value: attrs[key] || {},
12 onChange: function (value) { var update = {}; update[key] = value; setA(update); }
13 }) : null;
14 }
15 function _tvf(vars, key, attrs, prefix) {
16 var cssVars = window.bkbgTypoCssVars;
17 if (cssVars) Object.assign(vars, cssVars(attrs[key] || {}, prefix));
18 return vars;
19 }
20 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
21 function getTypoCssVars(attrs) {
22 var v = {};
23 _tvf(v, 'headingTypo', attrs, '--bkwf-hd-');
24 return v;
25 }
26 var InspectorControls = wp.blockEditor.InspectorControls;
27 var PanelBody = wp.components.PanelBody;
28 var RangeControl = wp.components.RangeControl;
29 var SelectControl = wp.components.SelectControl;
30 var TextControl = wp.components.TextControl;
31 var Button = wp.components.Button;
32 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
33 var ToggleControl = wp.components.ToggleControl;
34
35 var FLIP_MODES = [
36 { value: 'roll', label: 'Roll — slides up continuously' },
37 { value: 'flip-3d', label: 'Flip 3D — rotateX perspective' },
38 { value: 'fade-up', label: 'Fade + Slide Up' },
39 { value: 'zoom', label: 'Zoom In' }
40 ];
41
42 var UNDERLINES = [
43 { value: 'none', label: 'None' },
44 { value: 'solid', label: 'Solid Line' },
45 { value: 'wavy', label: 'Wavy' },
46 { value: 'dashed', label: 'Dashed' },
47 { value: 'highlight', label: 'Highlight Block' }
48 ];
49
50 var TAGS = ['h1','h2','h3','h4','h5','h6','p'].map(function(t){ return { value: t, label: t.toUpperCase() }; });
51
52 function WordFlipPreview(props) {
53 var attr = props.attr;
54 var words = (attr.words && attr.words.length) ? attr.words : ['designers'];
55 var _s = React.useState(0);
56 var idx = _s[0]; var setIdx = _s[1];
57
58 React.useEffect(function () {
59 var t = setInterval(function () { setIdx(function(i){ return (i+1)%words.length; }); }, attr.interval || 2200);
60 return function(){ clearInterval(t); };
61 }, [words.length, attr.interval]);
62
63 var flipStyle = {
64 display: 'inline-block',
65 color: attr.flipColor || '#7c3aed',
66 backgroundColor: attr.flipBg || 'transparent',
67 borderRadius: (attr.flipBorderRadius || 4) + 'px',
68 padding: '0 ' + (attr.flipPaddingH || 8) + 'px',
69 marginLeft: '0.25em',
70 transition: 'all 0.35s ease',
71 textDecoration: attr.underlineStyle !== 'none' && attr.underlineStyle !== 'highlight' ? 'underline' : 'none',
72 textDecorationStyle: attr.underlineStyle !== 'none' && attr.underlineStyle !== 'highlight' ? attr.underlineStyle : undefined,
73 textDecorationColor: attr.underlineColor || '#7c3aed'
74 };
75
76 return el('div', {
77 style: {
78 padding: (attr.paddingV||32)+'px '+(attr.paddingH||24)+'px',
79 backgroundColor: attr.showBg ? (attr.bgColor||'#fff') : 'transparent',
80 borderRadius: (attr.borderRadius||0)+'px',
81 textAlign: attr.textAlign||'center'
82 }
83 },
84 el(attr.tag||'h2', {
85 className: 'bkbg-wf-heading',
86 style: { margin:0, padding:0, color:attr.staticColor||'#0f172a' }
87 },
88 attr.staticBefore && el('span', null, attr.staticBefore),
89 el('span', { style: flipStyle }, words[idx]),
90 attr.staticAfter && el('span', null, ' '+attr.staticAfter)
91 )
92 );
93 }
94
95 registerBlockType('blockenberg/word-flip', {
96 title: 'Word Flip',
97 icon: 'sort',
98 category: 'bkbg-effects',
99
100 edit: function (props) {
101 var attr = props.attributes; var setAttr = props.setAttributes;
102
103 function updateWord(i, val){ var w=attr.words.slice(); w[i]=val; setAttr({words:w}); }
104 function addWord(){ setAttr({words:attr.words.concat(['new'])}); }
105 function removeWord(i){ var w=attr.words.slice(); w.splice(i,1); setAttr({words:w}); }
106
107 return el(React.Fragment, null,
108 el(InspectorControls, null,
109 el(PanelBody, { title:'Words List', initialOpen:true },
110 el('p',{style:{fontSize:12,color:'#6b7280',margin:'0 0 8px'}},'Words that flip into the heading:'),
111 attr.words.map(function(w,i) {
112 return el('div',{key:i,style:{display:'flex',gap:6,marginBottom:6}},
113 el(TextControl,{__nextHasNoMarginBottom:true,value:w,onChange:function(v){updateWord(i,v);}}),
114 el(Button,{variant:'tertiary',isSmall:true,isDestructive:true,onClick:function(){removeWord(i);},disabled:attr.words.length<=1},'✕')
115 );
116 }),
117 el(Button,{variant:'secondary',isSmall:true,onClick:addWord,style:{marginTop:4}},'+ Add Word')
118 ),
119 el(PanelBody, { title:'Static Text', initialOpen:false },
120 el(TextControl,{__nextHasNoMarginBottom:true,label:'Before',value:attr.staticBefore,onChange:function(v){setAttr({staticBefore:v});}}),
121 el(TextControl,{__nextHasNoMarginBottom:true,label:'After',value:attr.staticAfter,onChange:function(v){setAttr({staticAfter:v});}})
122 ),
123 el(PanelBody, { title:'Animation', initialOpen:true },
124 el(SelectControl,{__nextHasNoMarginBottom:true,label:'Flip Mode',value:attr.flipMode,options:FLIP_MODES,onChange:function(v){setAttr({flipMode:v});}}),
125 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Interval (ms)',value:attr.interval,min:500,max:8000,step:100,onChange:function(v){setAttr({interval:v});}}),
126 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Flip Speed (ms)',value:attr.flipSpeed,min:100,max:1200,step:20,onChange:function(v){setAttr({flipSpeed:v});}})
127 ),
128 el(PanelBody, { title:'Typography', initialOpen:false },
129 getTypoControl('Heading', 'headingTypo', attr, setAttr),
130 el(SelectControl,{__nextHasNoMarginBottom:true,label:'HTML Tag',value:attr.tag,options:TAGS,onChange:function(v){setAttr({tag:v});}}),
131 el(SelectControl,{__nextHasNoMarginBottom:true,label:'Text Align',value:attr.textAlign,options:[{value:'left',label:'Left'},{value:'center',label:'Center'},{value:'right',label:'Right'}],onChange:function(v){setAttr({textAlign:v});}})
132 ),
133 el(PanelBody, { title:'Flip Word Style', initialOpen:false },
134 el(SelectControl,{__nextHasNoMarginBottom:true,label:'Underline / Decoration',value:attr.underlineStyle,options:UNDERLINES,onChange:function(v){setAttr({underlineStyle:v});}}),
135 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Padding Horizontal (px)',value:attr.flipPaddingH,min:0,max:40,onChange:function(v){setAttr({flipPaddingH:v});}}),
136 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Border Radius (px)',value:attr.flipBorderRadius,min:0,max:40,onChange:function(v){setAttr({flipBorderRadius:v});}})
137 ),
138 el(PanelBody, { title:'Background', initialOpen:false },
139 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Background',checked:attr.showBg,onChange:function(v){setAttr({showBg:v});}}),
140 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Padding V (px)',value:attr.paddingV,min:0,max:120,onChange:function(v){setAttr({paddingV:v});}}),
141 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Padding H (px)',value:attr.paddingH,min:0,max:120,onChange:function(v){setAttr({paddingH:v});}}),
142 el(RangeControl,{__nextHasNoMarginBottom:true,label:'Block Radius (px)',value:attr.borderRadius,min:0,max:60,onChange:function(v){setAttr({borderRadius:v});}})
143 ),
144 el(PanelColorSettings, {
145 title:'Colors', initialOpen: false,
146 colorSettings:[
147 {value:attr.staticColor,onChange:function(v){setAttr({staticColor:v||'#0f172a'});},label:'Static Text'},
148 {value:attr.flipColor, onChange:function(v){setAttr({flipColor: v||'#7c3aed'});},label:'Flip Word Color'},
149 {value:attr.flipBg, onChange:function(v){setAttr({flipBg: v||'' });},label:'Flip Word Background'},
150 {value:attr.underlineColor,onChange:function(v){setAttr({underlineColor:v||'#7c3aed'});},label:'Decoration Color'},
151 attr.showBg && {value:attr.bgColor,onChange:function(v){setAttr({bgColor:v||'#fff'});},label:'Block Background'}
152 ].filter(Boolean)
153 })
154 ),
155 el('div', useBlockProps({ style: getTypoCssVars(attr) }), el(WordFlipPreview, {attr:attr}))
156 );
157 },
158
159 save: function (props) {
160 return el('div', useBlockProps.save({ style: getTypoCssVars(props.attributes) }),
161 el('div', { className:'bkbg-wf-app', 'data-opts':JSON.stringify(props.attributes) })
162 );
163 }
164 });
165 }() );
166