frontblocks-advanced-option.js
2 weeks ago
frontblocks-advanced-option.jsx
2 weeks ago
frontblocks-carousel-editor.css
4 months ago
frontblocks-carousel.css
2 weeks ago
frontblocks-carousel.js
2 weeks ago
glide.min.js
8 months ago
frontblocks-advanced-option.js
633 lines
| 1 | "use strict"; |
| 2 | |
| 3 | function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } |
| 4 | function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } |
| 5 | function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } |
| 6 | // Add custom controls to the Advanced panel of GenerateBlocks Grid block |
| 7 | var addFilter = wp.hooks.addFilter; |
| 8 | var _wp$element = wp.element, |
| 9 | Fragment = _wp$element.Fragment, |
| 10 | useEffect = _wp$element.useEffect, |
| 11 | useRef = _wp$element.useRef; |
| 12 | var _wp$blockEditor = wp.blockEditor, |
| 13 | InspectorControls = _wp$blockEditor.InspectorControls, |
| 14 | PanelColorSettings = _wp$blockEditor.PanelColorSettings, |
| 15 | MediaUpload = _wp$blockEditor.MediaUpload; |
| 16 | var _wp$components = wp.components, |
| 17 | SelectControl = _wp$components.SelectControl, |
| 18 | TextControl = _wp$components.TextControl, |
| 19 | PanelBody = _wp$components.PanelBody, |
| 20 | ToggleControl = _wp$components.ToggleControl, |
| 21 | Button = _wp$components.Button; |
| 22 | var __ = wp.i18n.__; |
| 23 | |
| 24 | /** |
| 25 | * Returns the document that renders block content. |
| 26 | * WordPress 6.x uses an <iframe> for the editor canvas. |
| 27 | */ |
| 28 | function getEditorDocument() { |
| 29 | var iframe = document.querySelector('iframe[name="editor-canvas"]'); |
| 30 | return iframe && iframe.contentDocument && iframe.contentDocument.body ? iframe.contentDocument : document; |
| 31 | } |
| 32 | var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/; |
| 33 | |
| 34 | /** |
| 35 | * Walk an element's subtree to find the container whose DIRECT children |
| 36 | * are actual blocks (UUID data-block). Stops at depth 4. |
| 37 | */ |
| 38 | function findSlidesParent(el, depth) { |
| 39 | if (depth === 0) return null; |
| 40 | if (Array.from(el.children).some(function (c) { |
| 41 | return UUID_RE.test(c.dataset.block || ''); |
| 42 | })) { |
| 43 | return el; |
| 44 | } |
| 45 | var _iterator = _createForOfIteratorHelper(el.children), |
| 46 | _step; |
| 47 | try { |
| 48 | for (_iterator.s(); !(_step = _iterator.n()).done;) { |
| 49 | var child = _step.value; |
| 50 | var found = findSlidesParent(child, depth - 1); |
| 51 | if (found) return found; |
| 52 | } |
| 53 | } catch (err) { |
| 54 | _iterator.e(err); |
| 55 | } finally { |
| 56 | _iterator.f(); |
| 57 | } |
| 58 | return null; |
| 59 | } |
| 60 | |
| 61 | /** |
| 62 | * Find the grid DOM element for a given block. |
| 63 | * |
| 64 | * For generateblocks/element: [data-block][data-type] IS the gb-element. |
| 65 | * Do NOT search inside – that returns a child item. |
| 66 | * For generateblocks/grid: look for .gb-grid-wrapper inside. |
| 67 | * For core/group: walk the subtree to find the element whose children |
| 68 | * are the real blocks, because WP nests them differently across versions. |
| 69 | */ |
| 70 | function findGridEl(blockEl, name) { |
| 71 | if (name === 'generateblocks/element') { |
| 72 | return blockEl; |
| 73 | } |
| 74 | if (name === 'generateblocks/grid') { |
| 75 | if (blockEl.classList.contains('gb-grid-wrapper')) return blockEl; |
| 76 | var grid = blockEl.querySelector('.gb-grid-wrapper'); |
| 77 | return grid || null; |
| 78 | } |
| 79 | if (name === 'core/group') { |
| 80 | // Walk up to 4 levels deep to find where the child blocks live. |
| 81 | return findSlidesParent(blockEl, 4) || blockEl; |
| 82 | } |
| 83 | if (name === 'core/query') { |
| 84 | return blockEl.querySelector('.wp-block-post-template') || null; |
| 85 | } |
| 86 | return null; |
| 87 | } |
| 88 | function addCustomCarouselPanel(BlockEdit) { |
| 89 | return function (props) { |
| 90 | if (props.name !== 'generateblocks/grid' && props.name !== 'generateblocks/element' && props.name !== 'core/group' && props.name !== 'core/query') { |
| 91 | return /*#__PURE__*/React.createElement(BlockEdit, props); |
| 92 | } |
| 93 | if (props.name === 'generateblocks/element') { |
| 94 | var styles = props.attributes.styles || {}; |
| 95 | if (styles.display !== 'grid') { |
| 96 | return /*#__PURE__*/React.createElement(BlockEdit, props); |
| 97 | } |
| 98 | } |
| 99 | if (props.name === 'core/group') { |
| 100 | var layout = props.attributes.layout || {}; |
| 101 | if (layout.type !== 'grid') { |
| 102 | return /*#__PURE__*/React.createElement(BlockEdit, props); |
| 103 | } |
| 104 | } |
| 105 | var _props$attributes = props.attributes, |
| 106 | _props$attributes$frb = _props$attributes.frblGridOption, |
| 107 | frblGridOption = _props$attributes$frb === void 0 ? 'none' : _props$attributes$frb, |
| 108 | _props$attributes$frb2 = _props$attributes.frblItemsToView, |
| 109 | frblItemsToView = _props$attributes$frb2 === void 0 ? '4' : _props$attributes$frb2, |
| 110 | _props$attributes$frb3 = _props$attributes.frblLaptopToView, |
| 111 | frblLaptopToView = _props$attributes$frb3 === void 0 ? '3' : _props$attributes$frb3, |
| 112 | _props$attributes$frb4 = _props$attributes.frblTabletToView, |
| 113 | frblTabletToView = _props$attributes$frb4 === void 0 ? '2' : _props$attributes$frb4, |
| 114 | _props$attributes$frb5 = _props$attributes.frblResponsiveToView, |
| 115 | frblResponsiveToView = _props$attributes$frb5 === void 0 ? '1' : _props$attributes$frb5, |
| 116 | _props$attributes$frb6 = _props$attributes.frblAutoplay, |
| 117 | frblAutoplay = _props$attributes$frb6 === void 0 ? '' : _props$attributes$frb6, |
| 118 | _props$attributes$frb7 = _props$attributes.frblGap, |
| 119 | frblGap = _props$attributes$frb7 === void 0 ? '20' : _props$attributes$frb7, |
| 120 | _props$attributes$frb8 = _props$attributes.frblButtons, |
| 121 | frblButtons = _props$attributes$frb8 === void 0 ? 'arrows' : _props$attributes$frb8, |
| 122 | _props$attributes$frb9 = _props$attributes.frblRewind, |
| 123 | frblRewind = _props$attributes$frb9 === void 0 ? true : _props$attributes$frb9, |
| 124 | frblButtonColor = _props$attributes.frblButtonColor, |
| 125 | frblButtonBgColor = _props$attributes.frblButtonBgColor, |
| 126 | _props$attributes$frb0 = _props$attributes.frblButtonsPosition, |
| 127 | frblButtonsPosition = _props$attributes$frb0 === void 0 ? 'side' : _props$attributes$frb0, |
| 128 | _props$attributes$frb1 = _props$attributes.frblArrowLeftUrl, |
| 129 | frblArrowLeftUrl = _props$attributes$frb1 === void 0 ? '' : _props$attributes$frb1, |
| 130 | _props$attributes$frb10 = _props$attributes.frblArrowRightUrl, |
| 131 | frblArrowRightUrl = _props$attributes$frb10 === void 0 ? '' : _props$attributes$frb10, |
| 132 | _props$attributes$frb11 = _props$attributes.frblDisableOnDesktop, |
| 133 | frblDisableOnDesktop = _props$attributes$frb11 === void 0 ? false : _props$attributes$frb11; |
| 134 | |
| 135 | // ── Editor carousel preview ────────────────────────────────────────── |
| 136 | var stateRef = useRef(null); |
| 137 | useEffect(function () { |
| 138 | var mounted = true; |
| 139 | var timer = null; |
| 140 | function cleanup() { |
| 141 | if (!stateRef.current) return; |
| 142 | var _stateRef$current = stateRef.current, |
| 143 | gridEl = _stateRef$current.gridEl, |
| 144 | slides = _stateRef$current.slides, |
| 145 | spacer = _stateRef$current.spacer, |
| 146 | prevBtn = _stateRef$current.prevBtn, |
| 147 | nextBtn = _stateRef$current.nextBtn, |
| 148 | resizeObs = _stateRef$current.resizeObs, |
| 149 | scrollFn = _stateRef$current.scrollFn; |
| 150 | |
| 151 | // Disconnect observer and scroll listener. |
| 152 | if (resizeObs) resizeObs.disconnect(); |
| 153 | var editorDoc = getEditorDocument(); |
| 154 | var editorScrollEl = editorDoc.documentElement || editorDoc.body; |
| 155 | if (scrollFn) editorScrollEl.removeEventListener('scroll', scrollFn, true); |
| 156 | |
| 157 | // Remove arrows from outer window body (completely outside React). |
| 158 | [prevBtn, nextBtn].forEach(function (btn) { |
| 159 | if (btn && btn.parentNode) btn.parentNode.removeChild(btn); |
| 160 | }); |
| 161 | |
| 162 | // Remove right spacer element. |
| 163 | if (spacer && spacer.parentNode) spacer.parentNode.removeChild(spacer); |
| 164 | |
| 165 | // Restore gridEl styles. |
| 166 | try { |
| 167 | var preventScroll = stateRef.current.preventScroll; |
| 168 | if (preventScroll) { |
| 169 | gridEl.removeEventListener('wheel', preventScroll); |
| 170 | gridEl.removeEventListener('touchstart', preventScroll); |
| 171 | gridEl.removeEventListener('touchmove', preventScroll); |
| 172 | } |
| 173 | gridEl.classList.remove('frbl-carousel-noscrollbar'); |
| 174 | ['display', 'flex-wrap', 'gap', 'overflow-x', 'scroll-behavior', 'padding-left', 'padding-right', 'max-width', 'grid-template-columns'].forEach(function (p) { |
| 175 | return gridEl.style.removeProperty(p); |
| 176 | }); |
| 177 | slides.forEach(function (slide) { |
| 178 | ['flex-shrink', 'width', 'min-width', 'margin-left', 'margin-right', 'grid-column', 'grid-row'].forEach(function (p) { |
| 179 | return slide.style.removeProperty(p); |
| 180 | }); |
| 181 | }); |
| 182 | } catch (e) {} |
| 183 | stateRef.current = null; |
| 184 | } |
| 185 | function init() { |
| 186 | if (!mounted) return; |
| 187 | cleanup(); |
| 188 | var editorDoc = getEditorDocument(); |
| 189 | |
| 190 | // GB 2.x wraps blocks in a root element that shares the same data-block UUID. |
| 191 | // Use data-type to select the correct inner element; fall back for native blocks. |
| 192 | var blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"][data-type=\"").concat(props.name, "\"]")); |
| 193 | if (!blockEl) { |
| 194 | blockEl = editorDoc.querySelector("[data-block=\"".concat(props.clientId, "\"]")); |
| 195 | } |
| 196 | if (!blockEl) return; |
| 197 | var gridEl = findGridEl(blockEl, props.name); |
| 198 | if (!gridEl) return; |
| 199 | |
| 200 | // For core/query, <li> items don't have data-block UUIDs (server-rendered). |
| 201 | // For other blocks, filter by UUID data-block attribute. |
| 202 | var isQueryLoop = props.name === 'core/query'; |
| 203 | var slides = isQueryLoop ? Array.from(gridEl.children).filter(function (el) { |
| 204 | return el.tagName === 'LI'; |
| 205 | }) : Array.from(gridEl.children).filter(function (el) { |
| 206 | return UUID_RE.test(el.dataset.block || ''); |
| 207 | }); |
| 208 | if (slides.length === 0) return; |
| 209 | var perView = Math.max(1, parseInt(frblItemsToView) || 4); |
| 210 | var gap = Math.max(0, parseInt(frblGap) || 20); |
| 211 | var btnColor = frblButtonColor || '#fff'; |
| 212 | var btnBg = frblButtonBgColor || 'rgba(0,0,0,0.45)'; |
| 213 | |
| 214 | // For core/query, force flex via setProperty to beat WP's grid CSS. |
| 215 | if (isQueryLoop) { |
| 216 | gridEl.style.setProperty('display', 'flex', 'important'); |
| 217 | gridEl.style.setProperty('flex-wrap', 'nowrap', 'important'); |
| 218 | gridEl.style.setProperty('max-width', 'none', 'important'); |
| 219 | gridEl.style.setProperty('grid-template-columns', 'none', 'important'); |
| 220 | gridEl.style.setProperty('list-style', 'none', 'important'); |
| 221 | gridEl.style.setProperty('padding-left', '0', 'important'); |
| 222 | } |
| 223 | |
| 224 | // Measure content-box width before any style changes. |
| 225 | var editorWin = editorDoc.defaultView || window; |
| 226 | var ARROW_W = 40; // px reserved on each side for arrow buttons. |
| 227 | var cs = editorWin.getComputedStyle(gridEl); |
| 228 | var innerW = gridEl.getBoundingClientRect().width - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0); |
| 229 | var totalWidth = Math.round(innerW) || 600; |
| 230 | // Content area after reserving space for both arrow buttons. |
| 231 | var contentW = totalWidth - ARROW_W * 2; |
| 232 | var slideWidth = Math.round((contentW - gap * (perView - 1)) / perView); |
| 233 | var step = slideWidth + gap; |
| 234 | |
| 235 | // ── Apply scroll-based layout directly to gridEl ───────────── |
| 236 | // No DOM restructuring → no React reconciliation conflicts. |
| 237 | gridEl.classList.add('frbl-carousel-noscrollbar'); |
| 238 | if (!isQueryLoop) { |
| 239 | gridEl.style.display = 'flex'; |
| 240 | gridEl.style.flexWrap = 'nowrap'; |
| 241 | gridEl.style.paddingLeft = ARROW_W + 'px'; |
| 242 | } else { |
| 243 | // paddingLeft already set via setProperty above; override with arrow offset. |
| 244 | gridEl.style.setProperty('padding-left', ARROW_W + 'px', 'important'); |
| 245 | } |
| 246 | gridEl.style.gap = gap + 'px'; |
| 247 | gridEl.style.overflowX = 'scroll'; |
| 248 | gridEl.style.scrollBehavior = 'smooth'; |
| 249 | gridEl.style.paddingRight = '0'; |
| 250 | slides.forEach(function (slide) { |
| 251 | slide.style.flexShrink = '0'; |
| 252 | slide.style.width = slideWidth + 'px'; |
| 253 | slide.style.minWidth = slideWidth + 'px'; |
| 254 | slide.style.marginLeft = '0'; |
| 255 | slide.style.marginRight = '0'; |
| 256 | slide.style.gridColumn = 'unset'; |
| 257 | slide.style.gridRow = 'unset'; |
| 258 | }); |
| 259 | |
| 260 | // Right-side spacer: Chrome does not include padding-right in horizontal |
| 261 | // scroll extent, so we use a real flex child to guarantee right space. |
| 262 | var appender = gridEl.querySelector('.block-list-appender'); |
| 263 | var spacer = editorDoc.createElement('span'); |
| 264 | spacer.setAttribute('data-frbl-spacer', '1'); |
| 265 | spacer.style.cssText = "display:block;flex-shrink:0;width:".concat(ARROW_W, "px;min-width:").concat(ARROW_W, "px;"); |
| 266 | gridEl.insertBefore(spacer, appender || null); |
| 267 | |
| 268 | // Prevent manual scroll — only arrows drive navigation. |
| 269 | var preventScroll = function preventScroll(e) { |
| 270 | return e.preventDefault(); |
| 271 | }; |
| 272 | gridEl.addEventListener('wheel', preventScroll, { |
| 273 | passive: false |
| 274 | }); |
| 275 | gridEl.addEventListener('touchstart', preventScroll, { |
| 276 | passive: false |
| 277 | }); |
| 278 | gridEl.addEventListener('touchmove', preventScroll, { |
| 279 | passive: false |
| 280 | }); |
| 281 | |
| 282 | // ── Navigation (scrollLeft, item-by-item) ──────────────────── |
| 283 | var idx = 0; |
| 284 | var lastIdx = Math.max(0, slides.length - perView); |
| 285 | function scrollTo(n) { |
| 286 | if (n > lastIdx) { |
| 287 | // Wrap forward to start. |
| 288 | gridEl.style.scrollBehavior = 'auto'; |
| 289 | gridEl.scrollLeft = 0; |
| 290 | void gridEl.offsetWidth; |
| 291 | gridEl.style.scrollBehavior = 'smooth'; |
| 292 | idx = 0; |
| 293 | return; |
| 294 | } |
| 295 | if (n < 0) { |
| 296 | // Wrap back to end. |
| 297 | gridEl.style.scrollBehavior = 'auto'; |
| 298 | gridEl.scrollLeft = Math.round(lastIdx * step); |
| 299 | void gridEl.offsetWidth; |
| 300 | gridEl.style.scrollBehavior = 'smooth'; |
| 301 | idx = lastIdx; |
| 302 | return; |
| 303 | } |
| 304 | idx = n; |
| 305 | gridEl.scrollLeft = Math.round(idx * step); |
| 306 | } |
| 307 | |
| 308 | // ── Arrows in OUTER document body ──────────────────────────── |
| 309 | // Placing them outside the iframe means React never touches them. |
| 310 | var iframe = document.querySelector('iframe[name="editor-canvas"]'); |
| 311 | function updateArrowPos() { |
| 312 | if (!stateRef.current) return; |
| 313 | var ifrRect = iframe ? iframe.getBoundingClientRect() : { |
| 314 | top: 0, |
| 315 | left: 0 |
| 316 | }; |
| 317 | var rect = gridEl.getBoundingClientRect(); // coords in iframe viewport |
| 318 | var midY = Math.round(ifrRect.top + rect.top + rect.height / 2 - 16); |
| 319 | prevBtn.style.top = midY + 'px'; |
| 320 | prevBtn.style.left = Math.round(ifrRect.left + rect.left + 8) + 'px'; |
| 321 | nextBtn.style.top = midY + 'px'; |
| 322 | nextBtn.style.right = Math.round(window.innerWidth - (ifrRect.left + rect.right) + 8) + 'px'; |
| 323 | } |
| 324 | function makeArrow(dir) { |
| 325 | var btn = document.createElement('button'); |
| 326 | btn.type = 'button'; |
| 327 | btn.className = "frbl-editor-arrow frbl-editor-arrow-".concat(dir); |
| 328 | btn.setAttribute('aria-label', dir === 'prev' ? 'Previous slide' : 'Next slide'); |
| 329 | btn.style.cssText = "position:fixed;z-index:99999;background-color:".concat(btnBg, ";"); |
| 330 | var d = dir === 'prev' ? 'M6 1L1 6L6 11' : 'M1 11L6 6L1 1'; |
| 331 | btn.innerHTML = "<svg width=\"7\" height=\"12\" viewBox=\"0 0 7 12\" fill=\"none\"><path d=\"".concat(d, "\" stroke=\"").concat(btnColor, "\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>"); |
| 332 | btn.addEventListener('click', function (e) { |
| 333 | e.stopPropagation(); |
| 334 | scrollTo(dir === 'prev' ? idx - 1 : idx + 1); |
| 335 | }); |
| 336 | document.body.appendChild(btn); |
| 337 | return btn; |
| 338 | } |
| 339 | var prevBtn = makeArrow('prev'); |
| 340 | var nextBtn = makeArrow('next'); |
| 341 | updateArrowPos(); |
| 342 | |
| 343 | // Keep arrows positioned correctly when the editor scrolls or resizes. |
| 344 | var resizeObs = new ResizeObserver(updateArrowPos); |
| 345 | resizeObs.observe(gridEl); |
| 346 | var editorScrollEl = editorDoc.documentElement || editorDoc.body; |
| 347 | var scrollFn = updateArrowPos; |
| 348 | editorScrollEl.addEventListener('scroll', scrollFn, { |
| 349 | passive: true, |
| 350 | capture: true |
| 351 | }); |
| 352 | stateRef.current = { |
| 353 | gridEl: gridEl, |
| 354 | slides: slides, |
| 355 | spacer: spacer, |
| 356 | prevBtn: prevBtn, |
| 357 | nextBtn: nextBtn, |
| 358 | resizeObs: resizeObs, |
| 359 | scrollFn: scrollFn, |
| 360 | preventScroll: preventScroll |
| 361 | }; |
| 362 | } |
| 363 | if (frblGridOption !== 'none') { |
| 364 | timer = setTimeout(init, 300); |
| 365 | } else { |
| 366 | cleanup(); |
| 367 | } |
| 368 | return function () { |
| 369 | mounted = false; |
| 370 | if (timer) clearTimeout(timer); |
| 371 | cleanup(); |
| 372 | }; |
| 373 | }, [frblGridOption, frblItemsToView, frblGap, frblButtonColor, frblButtonBgColor, props.clientId]); |
| 374 | // ── Inspector panel ────────────────────────────────────────────────── |
| 375 | |
| 376 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockEdit, props), /*#__PURE__*/React.createElement(InspectorControls, null, /*#__PURE__*/React.createElement(PanelBody, { |
| 377 | title: __('FrontBlocks - Carousel', 'frontblocks'), |
| 378 | initialOpen: true |
| 379 | }, /*#__PURE__*/React.createElement(SelectControl, { |
| 380 | label: __('FrontBlocks Grid Option', 'frontblocks'), |
| 381 | value: frblGridOption, |
| 382 | options: [{ |
| 383 | label: __('None', 'frontblocks'), |
| 384 | value: 'none' |
| 385 | }, { |
| 386 | label: __('Carousel', 'frontblocks'), |
| 387 | value: 'carousel' |
| 388 | }, { |
| 389 | label: __('Slider', 'frontblocks'), |
| 390 | value: 'slider' |
| 391 | }], |
| 392 | onChange: function onChange(value) { |
| 393 | return props.setAttributes({ |
| 394 | frblGridOption: value |
| 395 | }); |
| 396 | }, |
| 397 | help: __('This option gives the option to make carousel in your grid block.', 'frontblocks') |
| 398 | }), frblGridOption !== 'none' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TextControl, { |
| 399 | label: __('Items to view (Desktop)', 'frontblocks'), |
| 400 | value: frblItemsToView, |
| 401 | onChange: function onChange(value) { |
| 402 | return props.setAttributes({ |
| 403 | frblItemsToView: value |
| 404 | }); |
| 405 | }, |
| 406 | help: __('Number of items to show on desktop (>1200px)', 'frontblocks') |
| 407 | }), /*#__PURE__*/React.createElement(TextControl, { |
| 408 | label: __('Items to view (Laptop)', 'frontblocks'), |
| 409 | value: frblLaptopToView, |
| 410 | onChange: function onChange(value) { |
| 411 | return props.setAttributes({ |
| 412 | frblLaptopToView: value |
| 413 | }); |
| 414 | }, |
| 415 | help: __('Number of items to show on laptop (992px-1199px)', 'frontblocks') |
| 416 | }), /*#__PURE__*/React.createElement(TextControl, { |
| 417 | label: __('Items to view (Tablet)', 'frontblocks'), |
| 418 | value: frblTabletToView, |
| 419 | onChange: function onChange(value) { |
| 420 | return props.setAttributes({ |
| 421 | frblTabletToView: value |
| 422 | }); |
| 423 | }, |
| 424 | help: __('Number of items to show on tablet (768px-991px)', 'frontblocks') |
| 425 | }), /*#__PURE__*/React.createElement(TextControl, { |
| 426 | label: __('Items to view (Mobile)', 'frontblocks'), |
| 427 | value: frblResponsiveToView, |
| 428 | onChange: function onChange(value) { |
| 429 | return props.setAttributes({ |
| 430 | frblResponsiveToView: value |
| 431 | }); |
| 432 | }, |
| 433 | help: __('Number of items to show on mobile (<768px)', 'frontblocks') |
| 434 | }), /*#__PURE__*/React.createElement(TextControl, { |
| 435 | label: __('Autoplay (seconds)', 'frontblocks'), |
| 436 | value: frblAutoplay, |
| 437 | onChange: function onChange(value) { |
| 438 | return props.setAttributes({ |
| 439 | frblAutoplay: value |
| 440 | }); |
| 441 | } |
| 442 | }), /*#__PURE__*/React.createElement(TextControl, { |
| 443 | label: __('Gap (px)', 'frontblocks'), |
| 444 | value: frblGap, |
| 445 | onChange: function onChange(value) { |
| 446 | return props.setAttributes({ |
| 447 | frblGap: value |
| 448 | }); |
| 449 | }, |
| 450 | help: __('Space between slides in pixels. Leave empty for 20.', 'frontblocks') |
| 451 | }), frblGridOption === 'slider' && /*#__PURE__*/React.createElement(ToggleControl, { |
| 452 | label: __('Rewind', 'frontblocks'), |
| 453 | checked: frblRewind, |
| 454 | onChange: function onChange(value) { |
| 455 | return props.setAttributes({ |
| 456 | frblRewind: value |
| 457 | }); |
| 458 | } |
| 459 | }), /*#__PURE__*/React.createElement(SelectControl, { |
| 460 | label: __('Buttons', 'frontblocks'), |
| 461 | value: frblButtons, |
| 462 | options: [{ |
| 463 | label: __('None', 'frontblocks'), |
| 464 | value: 'none' |
| 465 | }, { |
| 466 | label: __('Bullets', 'frontblocks'), |
| 467 | value: 'bullets' |
| 468 | }, { |
| 469 | label: __('Arrows', 'frontblocks'), |
| 470 | value: 'arrows' |
| 471 | }], |
| 472 | onChange: function onChange(value) { |
| 473 | return props.setAttributes({ |
| 474 | frblButtons: value |
| 475 | }); |
| 476 | } |
| 477 | }), frblButtons === 'arrows' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SelectControl, { |
| 478 | label: __('Buttons Position', 'frontblocks'), |
| 479 | value: frblButtonsPosition, |
| 480 | options: [{ |
| 481 | label: __('Side (left & right)', 'frontblocks'), |
| 482 | value: 'side' |
| 483 | }, { |
| 484 | label: __('Bottom left', 'frontblocks'), |
| 485 | value: 'bottom-left' |
| 486 | }, { |
| 487 | label: __('Bottom right', 'frontblocks'), |
| 488 | value: 'bottom-right' |
| 489 | }, { |
| 490 | label: __('Top left', 'frontblocks'), |
| 491 | value: 'top-left' |
| 492 | }, { |
| 493 | label: __('Top right', 'frontblocks'), |
| 494 | value: 'top-right' |
| 495 | }], |
| 496 | onChange: function onChange(value) { |
| 497 | return props.setAttributes({ |
| 498 | frblButtonsPosition: value |
| 499 | }); |
| 500 | } |
| 501 | }), /*#__PURE__*/React.createElement("div", { |
| 502 | style: { |
| 503 | marginBottom: '12px' |
| 504 | } |
| 505 | }, /*#__PURE__*/React.createElement("p", { |
| 506 | style: { |
| 507 | marginBottom: '4px', |
| 508 | fontWeight: 500 |
| 509 | } |
| 510 | }, __('Left arrow icon', 'frontblocks')), frblArrowLeftUrl && /*#__PURE__*/React.createElement("img", { |
| 511 | src: frblArrowLeftUrl, |
| 512 | alt: "", |
| 513 | style: { |
| 514 | display: 'block', |
| 515 | width: '32px', |
| 516 | height: '32px', |
| 517 | marginBottom: '6px', |
| 518 | objectFit: 'contain' |
| 519 | } |
| 520 | }), /*#__PURE__*/React.createElement(MediaUpload, { |
| 521 | onSelect: function onSelect(media) { |
| 522 | return props.setAttributes({ |
| 523 | frblArrowLeftUrl: media.url |
| 524 | }); |
| 525 | }, |
| 526 | allowedTypes: ['image'], |
| 527 | value: frblArrowLeftUrl, |
| 528 | render: function render(_ref) { |
| 529 | var open = _ref.open; |
| 530 | return /*#__PURE__*/React.createElement("div", { |
| 531 | style: { |
| 532 | display: 'flex', |
| 533 | gap: '6px', |
| 534 | flexWrap: 'wrap' |
| 535 | } |
| 536 | }, /*#__PURE__*/React.createElement(Button, { |
| 537 | onClick: open, |
| 538 | variant: "secondary", |
| 539 | size: "small" |
| 540 | }, frblArrowLeftUrl ? __('Change', 'frontblocks') : __('Select SVG', 'frontblocks')), frblArrowLeftUrl && /*#__PURE__*/React.createElement(Button, { |
| 541 | onClick: function onClick() { |
| 542 | return props.setAttributes({ |
| 543 | frblArrowLeftUrl: '' |
| 544 | }); |
| 545 | }, |
| 546 | variant: "link", |
| 547 | isDestructive: true, |
| 548 | size: "small" |
| 549 | }, __('Remove', 'frontblocks'))); |
| 550 | } |
| 551 | })), /*#__PURE__*/React.createElement("div", { |
| 552 | style: { |
| 553 | marginBottom: '12px' |
| 554 | } |
| 555 | }, /*#__PURE__*/React.createElement("p", { |
| 556 | style: { |
| 557 | marginBottom: '4px', |
| 558 | fontWeight: 500 |
| 559 | } |
| 560 | }, __('Right arrow icon', 'frontblocks')), frblArrowRightUrl && /*#__PURE__*/React.createElement("img", { |
| 561 | src: frblArrowRightUrl, |
| 562 | alt: "", |
| 563 | style: { |
| 564 | display: 'block', |
| 565 | width: '32px', |
| 566 | height: '32px', |
| 567 | marginBottom: '6px', |
| 568 | objectFit: 'contain' |
| 569 | } |
| 570 | }), /*#__PURE__*/React.createElement(MediaUpload, { |
| 571 | onSelect: function onSelect(media) { |
| 572 | return props.setAttributes({ |
| 573 | frblArrowRightUrl: media.url |
| 574 | }); |
| 575 | }, |
| 576 | allowedTypes: ['image'], |
| 577 | value: frblArrowRightUrl, |
| 578 | render: function render(_ref2) { |
| 579 | var open = _ref2.open; |
| 580 | return /*#__PURE__*/React.createElement("div", { |
| 581 | style: { |
| 582 | display: 'flex', |
| 583 | gap: '6px', |
| 584 | flexWrap: 'wrap' |
| 585 | } |
| 586 | }, /*#__PURE__*/React.createElement(Button, { |
| 587 | onClick: open, |
| 588 | variant: "secondary", |
| 589 | size: "small" |
| 590 | }, frblArrowRightUrl ? __('Change', 'frontblocks') : __('Select SVG', 'frontblocks')), frblArrowRightUrl && /*#__PURE__*/React.createElement(Button, { |
| 591 | onClick: function onClick() { |
| 592 | return props.setAttributes({ |
| 593 | frblArrowRightUrl: '' |
| 594 | }); |
| 595 | }, |
| 596 | variant: "link", |
| 597 | isDestructive: true, |
| 598 | size: "small" |
| 599 | }, __('Remove', 'frontblocks'))); |
| 600 | } |
| 601 | }))), /*#__PURE__*/React.createElement(PanelColorSettings, { |
| 602 | title: __('Button Colors', 'frontblocks'), |
| 603 | colorSettings: [{ |
| 604 | value: frblButtonColor, |
| 605 | onChange: function onChange(color) { |
| 606 | return props.setAttributes({ |
| 607 | frblButtonColor: color |
| 608 | }); |
| 609 | }, |
| 610 | label: __('Color button', 'frontblocks') |
| 611 | }, { |
| 612 | value: frblButtonBgColor, |
| 613 | onChange: function onChange(color) { |
| 614 | return props.setAttributes({ |
| 615 | frblButtonBgColor: color |
| 616 | }); |
| 617 | }, |
| 618 | label: __('Color background button', 'frontblocks') |
| 619 | }] |
| 620 | }), /*#__PURE__*/React.createElement(ToggleControl, { |
| 621 | label: __('Disable on Desktop', 'frontblocks'), |
| 622 | checked: frblDisableOnDesktop, |
| 623 | onChange: function onChange(value) { |
| 624 | return props.setAttributes({ |
| 625 | frblDisableOnDesktop: value |
| 626 | }); |
| 627 | }, |
| 628 | help: __('If enabled, carousel/slider will only work on mobile devices.', 'frontblocks') |
| 629 | }))))); |
| 630 | }; |
| 631 | } |
| 632 | addFilter('editor.BlockEdit', 'frontblocks/gb-grid-carousel-panel', addCustomCarouselPanel); |
| 633 |