PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.13
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.13
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 / split-text / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.13, at blocks/split-text/index.js

360 lines 16.6 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 registerBlockType = wp.blocks.registerBlockType;
5 var __ = wp.i18n.__;
6 var InspectorControls = wp.blockEditor.InspectorControls;
7 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
8 var useBlockProps = wp.blockEditor.useBlockProps;
9 var PanelBody = wp.components.PanelBody;
10 var TextareaControl = wp.components.TextareaControl;
11 var TextControl = wp.components.TextControl;
12 var ToggleControl = wp.components.ToggleControl;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15
16 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
17 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
18
19 function buildTypoVars(a) {
20 var s = {
21 '--bkst-tx-sz': a.fontSize + 'px',
22 '--bkst-tx-w': a.fontWeight,
23 '--bkst-tx-lh': String(a.lineHeight),
24 '--bkst-tx-tt': a.textTransform !== 'none' ? a.textTransform : '',
25 };
26 if (a.letterSpacing) s['--bkst-tx-ls'] = a.letterSpacing + 'px';
27 var fn = getTypoCssVars();
28 if (fn) Object.assign(s, fn(a.textTypo, '--bkst-tx'));
29 return s;
30 }
31
32 var SPLIT_OPTIONS = [
33 { label: __('Words', 'blockenberg'), value: 'words' },
34 { label: __('Characters', 'blockenberg'), value: 'chars' },
35 { label: __('Lines', 'blockenberg'), value: 'lines' },
36 ];
37
38 var ANIM_OPTIONS = [
39 { label: __('Fade up', 'blockenberg'), value: 'fade-up' },
40 { label: __('Fade in', 'blockenberg'), value: 'fade-in' },
41 { label: __('Slide right', 'blockenberg'), value: 'slide-right' },
42 { label: __('Zoom in', 'blockenberg'), value: 'zoom-in' },
43 { label: __('Blur in', 'blockenberg'), value: 'blur-in' },
44 { label: __('Drop down', 'blockenberg'), value: 'drop-down' },
45 ];
46
47 var TAG_OPTIONS = [
48 { label: 'h1', value: 'h1' },
49 { label: 'h2', value: 'h2' },
50 { label: 'h3', value: 'h3' },
51 { label: 'h4', value: 'h4' },
52 { label: 'p', value: 'p' },
53 { label: 'div', value: 'div' },
54 ];
55
56 var WEIGHT_OPTIONS = [
57 { label: '400 – Regular', value: '400' },
58 { label: '600 – Semi-bold', value: '600' },
59 { label: '700 – Bold', value: '700' },
60 { label: '800 – Extra-bold', value: '800' },
61 { label: '900 – Black', value: '900' },
62 ];
63
64 var TRANSFORM_OPTIONS = [
65 { label: __('None', 'blockenberg'), value: 'none' },
66 { label: __('Uppercase', 'blockenberg'), value: 'uppercase' },
67 { label: __('Lowercase', 'blockenberg'), value: 'lowercase' },
68 { label: __('Capitalize', 'blockenberg'), value: 'capitalize' },
69 ];
70
71 function buildUnits(text, splitType) {
72 var raw = text || '';
73 if (splitType === 'chars') {
74 return raw.split('').map(function (c) { return c === ' ' ? null : c; });
75 }
76 if (splitType === 'lines') {
77 return raw.split('\n');
78 }
79 return raw.split(/\s+/).filter(function (w) { return w.length > 0; });
80 }
81
82 function isHighlighted(word, highlightWords) {
83 if (!highlightWords) return false;
84 var words = highlightWords.toLowerCase().split(',').map(function (w) { return w.trim(); });
85 return words.indexOf(word.toLowerCase().replace(/[^a-z0-9]/g, '')) !== -1;
86 }
87
88 function renderEditorPreview(a) {
89 var units = buildUnits(a.text, a.splitType);
90 var isChars = a.splitType === 'chars';
91 var rawText = a.text || '';
92
93 var containerStyle = {
94 textAlign: a.textAlign,
95 color: a.textColor,
96 margin: 0,
97 padding: 0,
98 wordBreak: 'break-word',
99 };
100
101 if (a.splitType === 'lines') {
102 return el(a.tag, {
103 className: 'bkst-text',
104 style: containerStyle,
105 }, units.map(function (line, i) {
106 return el('span', {
107 key: i,
108 className: 'bkst-line bkst-revealed',
109 style: { display: 'block' }
110 }, line);
111 }));
112 }
113
114 // Words or chars — keep spaces between words
115 var content = [];
116 if (isChars) {
117 rawText.split('').forEach(function (c, i) {
118 if (c === ' ') {
119 content.push(el('span', { key: 'sp' + i, style: { display: 'inline-block', width: '0.3em' } }));
120 } else {
121 content.push(el('span', {
122 key: i,
123 className: 'bkst-char bkst-revealed',
124 style: { display: 'inline-block' }
125 }, c));
126 }
127 });
128 } else {
129 units.forEach(function (word, i) {
130 if (i > 0) content.push(el('span', { key: 'sp' + i, style: { display: 'inline-block', width: '0.3em' } }));
131 var isHL = isHighlighted(word, a.highlightWords);
132 content.push(el('span', {
133 key: i,
134 className: 'bkst-word bkst-revealed',
135 style: {
136 display: 'inline-block',
137 color: isHL ? a.highlightColor : undefined,
138 }
139 }, word));
140 });
141 }
142
143 return el(a.tag, { className: 'bkst-text', style: containerStyle }, content);
144 }
145
146 function splitForSave(a) {
147 var rawText = a.text || '';
148 var splitType = a.splitType;
149 var highlights = (a.highlightWords || '').toLowerCase().split(',').map(function (w) { return w.trim(); });
150
151 if (splitType === 'lines') {
152 var lines = rawText.split('\n');
153 return lines.map(function (line, i) {
154 return el('span', {
155 key: i,
156 className: 'bkst-line',
157 style: { '--bkst-i': i, display: 'block' },
158 'aria-hidden': 'false',
159 }, line);
160 });
161 }
162
163 var content = [];
164 if (splitType === 'chars') {
165 var idx = 0;
166 rawText.split('').forEach(function (c, pos) {
167 if (c === ' ') {
168 content.push(el('span', { key: 'sp' + pos, className: 'bkst-space', 'aria-hidden': 'true' }, '\u00a0'));
169 } else {
170 content.push(el('span', {
171 key: pos,
172 className: 'bkst-char',
173 style: { '--bkst-i': idx },
174 }, c));
175 idx++;
176 }
177 });
178 } else {
179 var words = rawText.split(/\s+/).filter(function (w) { return w.length > 0; });
180 words.forEach(function (word, i) {
181 if (i > 0) content.push(el('span', { key: 'sp' + i, className: 'bkst-space', 'aria-hidden': 'true' }, '\u00a0'));
182 var isHL = highlights.indexOf(word.toLowerCase().replace(/[^a-z0-9]/g, '')) !== -1;
183 content.push(el('span', {
184 key: i,
185 className: 'bkst-word' + (isHL ? ' bkst-highlight' : ''),
186 style: { '--bkst-i': i },
187 }, word));
188 });
189 }
190
191 return content;
192 }
193
194 registerBlockType('blockenberg/split-text', {
195 title: __('Split Text', 'blockenberg'),
196 description: __('Scroll-triggered per-word text reveal animation.', 'blockenberg'),
197 category: 'bkbg-effects',
198 icon: 'editor-break',
199
200 edit: function (props) {
201 var attributes = props.attributes;
202 var setAttributes = props.setAttributes;
203
204 var wrapStyle = Object.assign({
205 background: attributes.wrapBg || undefined,
206 paddingTop: attributes.paddingTop + 'px',
207 paddingBottom: attributes.paddingBottom + 'px',
208 textAlign: attributes.textAlign,
209 }, buildTypoVars(attributes));
210
211 var blockProps = useBlockProps({ style: wrapStyle, className: 'bkst-section' });
212
213 return el(Fragment, null,
214 el(InspectorControls, null,
215 /* ── Text ─────────────────────────────────────── */
216 el(PanelBody, { title: __('Text', 'blockenberg'), initialOpen: true },
217 el(TextareaControl, {
218 label: __('Text content', 'blockenberg'),
219 help: __('For line splits use new lines (Enter).', 'blockenberg'),
220 value: attributes.text,
221 rows: 4,
222 onChange: function (v) { setAttributes({ text: v }); },
223 }),
224 el(SelectControl, {
225 label: __('HTML tag', 'blockenberg'),
226 value: attributes.tag,
227 options: TAG_OPTIONS,
228 onChange: function (v) { setAttributes({ tag: v }); },
229 }),
230 el(TextControl, {
231 label: __('Highlight words (comma-separated)', 'blockenberg'),
232 help: __('These words will appear in the highlight colour.', 'blockenberg'),
233 value: attributes.highlightWords,
234 onChange: function (v) { setAttributes({ highlightWords: v }); },
235 })
236 ),
237 /* ── Animation ─────────────────────────────────── */
238 el(PanelBody, { title: __('Animation', 'blockenberg'), initialOpen: true },
239 el(SelectControl, {
240 label: __('Split by', 'blockenberg'),
241 value: attributes.splitType,
242 options: SPLIT_OPTIONS,
243 onChange: function (v) { setAttributes({ splitType: v }); },
244 }),
245 el(SelectControl, {
246 label: __('Animation style', 'blockenberg'),
247 value: attributes.animation,
248 options: ANIM_OPTIONS,
249 onChange: function (v) { setAttributes({ animation: v }); },
250 }),
251 el(RangeControl, {
252 label: __('Stagger delay (ms per unit)', 'blockenberg'),
253 value: attributes.stagger,
254 min: 10, max: 400,
255 onChange: function (v) { setAttributes({ stagger: v }); },
256 }),
257 el(RangeControl, {
258 label: __('Animation duration (ms)', 'blockenberg'),
259 value: attributes.duration,
260 min: 100, max: 2000, step: 50,
261 onChange: function (v) { setAttributes({ duration: v }); },
262 }),
263 el(RangeControl, {
264 label: __('Trigger threshold (0–1)', 'blockenberg'),
265 value: attributes.threshold,
266 min: 0, max: 1, step: 0.05,
267 onChange: function (v) { setAttributes({ threshold: v }); },
268 }),
269 el(ToggleControl, {
270 label: __('Repeat when re-entering viewport', 'blockenberg'),
271 checked: attributes.repeat,
272 onChange: function (v) { setAttributes({ repeat: v }); },
273 __nextHasNoMarginBottom: true,
274 })
275 ),
276 /* ── Typography ────────────────────────────────── */
277 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
278 getTypoControl() ? el(getTypoControl(), { label:__('Text','blockenberg'), value:attributes.textTypo, onChange:function(v){ setAttributes({textTypo:v}); } }) : null,
279 el(SelectControl, {
280 label: __('Text align', 'blockenberg'),
281 value: attributes.textAlign,
282 options: [
283 { label: __('Left', 'blockenberg'), value: 'left' },
284 { label: __('Center', 'blockenberg'), value: 'center' },
285 { label: __('Right', 'blockenberg'), value: 'right' },
286 ],
287 onChange: function (v) { setAttributes({ textAlign: v }); },
288 })
289 ),
290 /* ── Layout ─────────────────────────────────────── */
291 el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false },
292 el(RangeControl, {
293 label: __('Padding top (px)', 'blockenberg'),
294 value: attributes.paddingTop,
295 min: 0, max: 200,
296 onChange: function (v) { setAttributes({ paddingTop: v }); },
297 }),
298 el(RangeControl, {
299 label: __('Padding bottom (px)', 'blockenberg'),
300 value: attributes.paddingBottom,
301 min: 0, max: 200,
302 onChange: function (v) { setAttributes({ paddingBottom: v }); },
303 })
304 ),
305 /* ── Colors ──────────────────────────────────────── */
306 el(PanelColorSettings, {
307 title: __('Colors', 'blockenberg'),
308 initialOpen: false,
309 colorSettings: [
310 { value: attributes.textColor, onChange: function (v) { setAttributes({ textColor: v || '#111827' }); }, label: __('Text color', 'blockenberg') },
311 { value: attributes.highlightColor, onChange: function (v) { setAttributes({ highlightColor: v || '#6c3fb5' }); }, label: __('Highlight color', 'blockenberg') },
312 { value: attributes.wrapBg, onChange: function (v) { setAttributes({ wrapBg: v || '' }); }, label: __('Background', 'blockenberg') },
313 ],
314 })
315 ),
316 el('div', blockProps,
317 renderEditorPreview(attributes)
318 )
319 );
320 },
321
322 save: function (props) {
323 var a = props.attributes;
324
325 var wrapStyle = Object.assign({
326 background: a.wrapBg || undefined,
327 paddingTop: a.paddingTop + 'px',
328 paddingBottom: a.paddingBottom + 'px',
329 }, buildTypoVars(a));
330
331 var textStyle = {
332 textAlign: a.textAlign,
333 color: a.textColor,
334 '--bkst-dur': a.duration + 'ms',
335 '--bkst-stagger': a.stagger + 'ms',
336 '--bkst-hl-c': a.highlightColor,
337 };
338
339 return el('div', {
340 className: 'bkst-section',
341 style: wrapStyle,
342 'data-animation': a.animation,
343 'data-split': a.splitType,
344 'data-stagger': a.stagger,
345 'data-duration': a.duration,
346 'data-threshold': a.threshold,
347 'data-repeat': a.repeat ? 'true' : 'false',
348 },
349 el(a.tag, {
350 className: 'bkst-text',
351 style: textStyle,
352 'aria-label': a.text,
353 },
354 splitForSave(a)
355 )
356 );
357 },
358 });
359 }() );
360