| 1 |
( function () { |
| 2 |
var el = window.wp.element.createElement; |
| 3 |
var { registerBlockType } = window.wp.blocks; |
| 4 |
var { InspectorControls, PanelColorSettings } = window.wp.blockEditor; |
| 5 |
var { PanelBody, RangeControl, SelectControl, TextControl, ToggleControl, Button, ColorPicker, Popover } = window.wp.components; |
| 6 |
var { __ } = window.wp.i18n; |
| 7 |
var { useEffect, useRef, useState, createElement: _el } = window.wp.element; |
| 8 |
var Fragment = window.wp.element.Fragment; |
| 9 |
|
| 10 |
var LEG_POS = [{label:'Top',value:'top'},{label:'Bottom',value:'bottom'},{label:'Left',value:'left'},{label:'Right',value:'right'}]; |
| 11 |
|
| 12 |
function parseHex(hex, alpha) { |
| 13 |
hex = hex.replace('#',''); |
| 14 |
if (hex.length===3) hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]; |
| 15 |
var r=parseInt(hex.substring(0,2),16),g=parseInt(hex.substring(2,4),16),b=parseInt(hex.substring(4,6),16); |
| 16 |
return 'rgba('+r+','+g+','+b+','+(alpha/100).toFixed(2)+')'; |
| 17 |
} |
| 18 |
|
| 19 |
function PolarPreview(a) { |
| 20 |
var canvasRef = useRef(null); |
| 21 |
var chartRef = useRef(null); |
| 22 |
useEffect(function() { |
| 23 |
var canvas = canvasRef.current; if (!canvas) return; |
| 24 |
function render(ChartJS) { |
| 25 |
if (chartRef.current) {chartRef.current.destroy(); chartRef.current=null;} |
| 26 |
var labels = a.labels.split(',').map(function(s){return s.trim();}); |
| 27 |
var vals = a.values.split(',').map(function(s){return parseFloat(s.trim())||0;}); |
| 28 |
var cols = a.colors.split(',').map(function(s){return s.trim();}); |
| 29 |
var bgColors = cols.map(function(c){return parseHex(c, a.fillAlpha);}); |
| 30 |
chartRef.current = new ChartJS(canvas, { |
| 31 |
type: 'polarArea', |
| 32 |
data: { labels: labels, datasets: [{ data: vals, backgroundColor: bgColors, borderColor: cols, borderWidth: 2 }] }, |
| 33 |
options: { responsive:false, animation:false, plugins:{ legend:{ display:a.showLegend, position:a.legendPos, labels:{ font:{ size: a.legendFontSize||12 } } }, title:{ display:a.showTitle&&!!a.chartTitle, text:a.chartTitle, font:{ size: a.titleFontSize||14 } } } } |
| 34 |
}); |
| 35 |
} |
| 36 |
if (window.Chart) { render(window.Chart); return; } |
| 37 |
var s = document.createElement('script'); |
| 38 |
s.src = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js'; |
| 39 |
s.onload = function(){ render(window.Chart); }; |
| 40 |
document.head.appendChild(s); |
| 41 |
return function(){ if (chartRef.current){chartRef.current.destroy();chartRef.current=null;} }; |
| 42 |
},[a.labels,a.values,a.colors,a.fillAlpha,a.size,a.showLegend,a.legendPos,a.showTitle,a.chartTitle]); |
| 43 |
|
| 44 |
return el('div',{style:{background:a.bgColor,borderRadius:a.borderRadius+'px',padding:'24px',textAlign:'center',display:'flex',justifyContent:'center'}}, |
| 45 |
el('canvas',{ref:canvasRef,width:a.size,height:a.size})); |
| 46 |
} |
| 47 |
|
| 48 |
/* ── BkbgMultiColorControl ────────────────────────────────────────── */ |
| 49 |
function BkbgMultiColorControl(props) { |
| 50 |
var label = props.label; |
| 51 |
var value = props.value || ''; |
| 52 |
var onChange = props.onChange; |
| 53 |
var colors = value.split(',').map(function (c) { return c.trim(); }).filter(Boolean); |
| 54 |
var st = useState(-1); var openIdx = st[0]; var setOpenIdx = st[1]; |
| 55 |
return el(Fragment, null, |
| 56 |
el('div', { style: { marginBottom: '8px' } }, |
| 57 |
el('span', { style: { fontSize: '11px', fontWeight: 500, textTransform: 'uppercase', display: 'block', marginBottom: '4px' } }, label), |
| 58 |
el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', alignItems: 'center' } }, |
| 59 |
colors.map(function (c, i) { |
| 60 |
return el('div', { key: i, style: { position: 'relative', display: 'inline-flex' } }, |
| 61 |
el('button', { type: 'button', style: { width: 28, height: 28, borderRadius: 4, border: '1px solid #ccc', background: c, cursor: 'pointer', padding: 0 }, onClick: function () { setOpenIdx(openIdx === i ? -1 : i); } }), |
| 62 |
el('button', { type: 'button', 'aria-label': 'Remove', style: { position: 'absolute', top: -6, right: -6, width: 14, height: 14, borderRadius: '50%', border: 'none', background: '#d00', color: '#fff', fontSize: '10px', lineHeight: '14px', cursor: 'pointer', padding: 0, textAlign: 'center' }, onClick: function () { var n = colors.slice(); n.splice(i, 1); onChange(n.join(',')); } }, '×'), |
| 63 |
openIdx === i && el(Popover, { onClose: function () { setOpenIdx(-1); } }, el('div', { style: { padding: '8px' } }, el(ColorPicker, { color: c, enableAlpha: true, onChange: function (v) { var n = colors.slice(); n[i] = v; onChange(n.join(',')); } }))) |
| 64 |
); |
| 65 |
}), |
| 66 |
el(Button, { isSmall: true, variant: 'secondary', onClick: function () { onChange(value ? value + ',#6c3fb5' : '#6c3fb5'); }, style: { height: 28, minWidth: 28 } }, '+') |
| 67 |
) |
| 68 |
) |
| 69 |
); |
| 70 |
} |
| 71 |
|
| 72 |
registerBlockType('blockenberg/polar-chart', { |
| 73 |
edit: function(props) { |
| 74 |
var a = props.attributes; |
| 75 |
var set = props.setAttributes; |
| 76 |
return el('div',null, |
| 77 |
el(InspectorControls,null, |
| 78 |
el(PanelBody,{title:__('Chart Data'),initialOpen:true}, |
| 79 |
el(ToggleControl,{label:__('Show Title'),checked:a.showTitle,onChange:v=>set({showTitle:v}),__nextHasNoMarginBottom:true}), |
| 80 |
a.showTitle&&el(TextControl,{label:__('Title'),value:a.chartTitle,onChange:v=>set({chartTitle:v})}), |
| 81 |
el('p',{style:{margin:'0 0 4px',fontSize:'11px',color:'#757575'}},'Labels — comma-separated'), |
| 82 |
el(TextControl,{label:__('Labels'),value:a.labels,onChange:v=>set({labels:v})}), |
| 83 |
el(TextControl,{label:__('Values'),value:a.values,onChange:v=>set({values:v})}), |
| 84 |
el(BkbgMultiColorControl,{label:__('Colors (hex, comma-separated)'),value:a.colors,onChange:v=>set({colors:v})}), |
| 85 |
el(RangeControl,{label:__('Fill Opacity %'),value:a.fillAlpha,min:10,max:100,onChange:v=>set({fillAlpha:v})}), |
| 86 |
), |
| 87 |
el(PanelBody,{title:__('Display'),initialOpen:false}, |
| 88 |
el(RangeControl,{label:__('Chart Size (px)'),value:a.size,min:200,max:700,onChange:v=>set({size:v})}), |
| 89 |
el(ToggleControl,{label:__('Show Legend'),checked:a.showLegend,onChange:v=>set({showLegend:v}),__nextHasNoMarginBottom:true}), |
| 90 |
a.showLegend&&el(SelectControl,{label:__('Legend Position'),value:a.legendPos,options:LEG_POS,onChange:v=>set({legendPos:v})}), |
| 91 |
el(RangeControl,{label:__('Border Radius (px)'),value:a.borderRadius,min:0,max:32,onChange:v=>set({borderRadius:v})}), |
| 92 |
), |
| 93 |
el(PanelBody,{title:__('Typography'),initialOpen:false}, |
| 94 |
el(RangeControl,{label:__('Title Font Size (px)'),value:a.titleFontSize,min:10,max:32,onChange:v=>set({titleFontSize:v}),__nextHasNoMarginBottom:true}), |
| 95 |
el(SelectControl,{__nextHasNoMarginBottom:true,label:__('Title Weight'),value:a.titleFontWeight,options:[{label:'SemiBold',value:'600'},{label:'Bold',value:'700'},{label:'ExtraBold',value:'800'},{label:'Black',value:'900'}],onChange:v=>set({titleFontWeight:v})}), |
| 96 |
el(RangeControl,{label:__('Legend Font Size (px)'),value:a.legendFontSize,min:8,max:24,onChange:v=>set({legendFontSize:v}),__nextHasNoMarginBottom:true}), |
| 97 |
el(SelectControl,{__nextHasNoMarginBottom:true,label:__('Legend Weight'),value:a.legendFontWeight,options:[{label:'Normal',value:'400'},{label:'Medium',value:'500'},{label:'SemiBold',value:'600'},{label:'Bold',value:'700'},{label:'ExtraBold',value:'800'}],onChange:v=>set({legendFontWeight:v})}), |
| 98 |
), |
| 99 |
el(PanelColorSettings,{title:__('Colors'),initialOpen:false,colorSettings:[ |
| 100 |
{label:__('Card Background'),value:a.bgColor,onChange:v=>set({bgColor:v||'#ffffff'})}, |
| 101 |
]}), |
| 102 |
), |
| 103 |
el(PolarPreview,a), |
| 104 |
); |
| 105 |
}, |
| 106 |
|
| 107 |
save: function({attributes:a}) { |
| 108 |
var data = {labels:a.labels,values:a.values,colors:a.colors,fillAlpha:a.fillAlpha,showLegend:a.showLegend,legendPos:a.legendPos,showTitle:a.showTitle,chartTitle:a.chartTitle}; |
| 109 |
return el('div',{className:'bkpca-wrap','data-chart':JSON.stringify(data),style:{background:a.bgColor,borderRadius:a.borderRadius+'px',padding:'24px',textAlign:'center',display:'flex',justifyContent:'center'}}, |
| 110 |
el('canvas',{className:'bkpca-canvas','data-size':a.size,width:a.size,height:a.size})); |
| 111 |
} |
| 112 |
}); |
| 113 |
}() ); |
| 114 |
|