| 1 |
import { useSelect, select } from "@wordpress/data"; |
| 2 |
import { useEffect, useRef, useState } from "@wordpress/element"; |
| 3 |
import axios from "axios"; |
| 4 |
import { colorControls, convertToClassName } from "../blocks/shared/helpFn"; |
| 5 |
|
| 6 |
// Device type fn. |
| 7 |
export const useDeviceType = () => { |
| 8 |
const { deviceType } = useSelect((select) => { |
| 9 |
const coreEditor = select("core/editor"); |
| 10 |
|
| 11 |
// Old WP (5.9) → fallback |
| 12 |
if (!coreEditor?.getDeviceType) { |
| 13 |
return { deviceType: "Desktop" }; |
| 14 |
} |
| 15 |
|
| 16 |
// New WP (6.2+) → use core API |
| 17 |
return { deviceType: coreEditor.getDeviceType() }; |
| 18 |
}, []); |
| 19 |
return deviceType || "Desktop"; |
| 20 |
}; |
| 21 |
|
| 22 |
export const cssString = (css) => { |
| 23 |
let result = ""; |
| 24 |
for (const selector in css) { |
| 25 |
let cssProps = ""; |
| 26 |
for (const property in css[selector]) { |
| 27 |
if (css[selector][property] && css[selector][property].length > 0) { |
| 28 |
cssProps += property + ":" + css[selector][property] + ";"; |
| 29 |
} |
| 30 |
} |
| 31 |
result += "" !== cssProps ? selector + "{" + cssProps + "}" : ""; |
| 32 |
} |
| 33 |
return result; |
| 34 |
}; |
| 35 |
|
| 36 |
// this function create for capitalize any strings first word. |
| 37 |
export const capitalizeString = (name) => { |
| 38 |
if (name === "post_format") { |
| 39 |
return "Post_Format"; |
| 40 |
} |
| 41 |
return name.charAt(0).toUpperCase() + name.slice(1); |
| 42 |
}; |
| 43 |
|
| 44 |
// this function accept an random array, one label key and value key and return a array of objects that use for select fields options. |
| 45 |
export const filterSelectOptions = (dataArray, labelKey, valueKey, indexKey = false) => { |
| 46 |
const selectFieldData = dataArray?.map((data, index) => { |
| 47 |
return { |
| 48 |
id: indexKey ? data[indexKey] : index, |
| 49 |
label: data[labelKey], |
| 50 |
value: |
| 51 |
"number" === typeof data[valueKey] ? data[valueKey] : data[valueKey].replace(/\s+/g, "_").toLowerCase(), |
| 52 |
}; |
| 53 |
}); |
| 54 |
return selectFieldData; |
| 55 |
}; |
| 56 |
|
| 57 |
// Calculate time ago (Human Readable) for metadata. |
| 58 |
export const humanReadableTimeAgo = (postDate) => { |
| 59 |
const dateNow = new Date(); |
| 60 |
const secondsPast = Math.floor((dateNow.getTime() - parseInt(postDate.getTime())) / 1000); |
| 61 |
|
| 62 |
if (secondsPast < 60) { |
| 63 |
return `${secondsPast} seconds ago`; |
| 64 |
} |
| 65 |
if (secondsPast < 3600) { |
| 66 |
const minutes = Math.floor(secondsPast / 60); |
| 67 |
return `${minutes} minutes ago`; |
| 68 |
} |
| 69 |
if (secondsPast < 86400) { |
| 70 |
const hours = Math.floor(secondsPast / 3600); |
| 71 |
return `${hours} hours ago`; |
| 72 |
} |
| 73 |
if (secondsPast < 604800) { |
| 74 |
// 30 days |
| 75 |
const days = Math.floor(secondsPast / 86400); |
| 76 |
return `${days} days ago`; |
| 77 |
} |
| 78 |
if (secondsPast < 2592000) { |
| 79 |
// 30 days |
| 80 |
const weeks = Math.floor(secondsPast / 604800); |
| 81 |
return `${weeks} weeks ago`; |
| 82 |
} |
| 83 |
if (secondsPast < 31536000) { |
| 84 |
// 365 days |
| 85 |
const months = Math.floor(secondsPast / 2592000); |
| 86 |
return `${months} months ago`; |
| 87 |
} |
| 88 |
const years = Math.floor(secondsPast / 31536000); |
| 89 |
return `${years} years ago`; |
| 90 |
}; |
| 91 |
|
| 92 |
// Strip Gutenberg Comments for metadata reading time. |
| 93 |
export const stripGutenbergComments = (content) => { |
| 94 |
// Remove gutenberg comments. |
| 95 |
content = content.replace(/<!-- wp:.*? -->/g, ""); |
| 96 |
content = content.replace(/<!-- \/wp:.*? -->/g, ""); |
| 97 |
|
| 98 |
// Remove HTML Tag. |
| 99 |
content = content.replace(/<\/?[^>]+(>|$)/g, ""); |
| 100 |
|
| 101 |
return content.trim(); |
| 102 |
}; |
| 103 |
|
| 104 |
// Count total word and character of the content. |
| 105 |
export const countWordAndCharacter = (content) => { |
| 106 |
const text = stripGutenbergComments(content).trim(); |
| 107 |
const characterCount = text.length; |
| 108 |
const wordCount = text.split(/\s+/).filter(Boolean).length; |
| 109 |
return { |
| 110 |
words: wordCount, |
| 111 |
chars: characterCount, |
| 112 |
}; |
| 113 |
}; |
| 114 |
|
| 115 |
export const filterDndSelectValues = (values) => { |
| 116 |
const updatedValues = Array.isArray(values) && values?.map((val) => val.value); |
| 117 |
return updatedValues; |
| 118 |
}; |
| 119 |
|
| 120 |
export const filteredTaxonomiesValues = (taxonomies) => { |
| 121 |
const filteredTaxonomy = taxonomies?.map((taxonomy) => { |
| 122 |
return { ...taxonomy, value: filterDndSelectValues(taxonomy?.value) }; |
| 123 |
}); |
| 124 |
return filteredTaxonomy; |
| 125 |
}; |
| 126 |
|
| 127 |
export const findDataFromArray = (itemsArray, firstKey, secondKey) => { |
| 128 |
const result = itemsArray?.find((f) => f[firstKey] === secondKey); |
| 129 |
return result; |
| 130 |
}; |
| 131 |
|
| 132 |
export const unit = (attributes, deviceType) => { |
| 133 |
if ("object" !== typeof attributes.unit) { |
| 134 |
return attributes.unit || ""; |
| 135 |
} |
| 136 |
return attributes.unit?.[deviceType]; |
| 137 |
}; |
| 138 |
|
| 139 |
export const filterActivatedAjaxLiveFilter = (liveFilters) => { |
| 140 |
return liveFilters.filter( |
| 141 |
(liveFilter) => liveFilter?.ajaxLiveOderDirect === true && liveFilter.value !== "keywordSearch" |
| 142 |
); |
| 143 |
}; |
| 144 |
|
| 145 |
export const getMediaUrlFromContent = (tags, content) => { |
| 146 |
const parser = new DOMParser(); |
| 147 |
const doc = parser.parseFromString(content, "text/html"); |
| 148 |
const contentImages = doc.querySelectorAll("img"); |
| 149 |
|
| 150 |
if (tags === "img_gallery_in_post_content" && contentImages.length > 0) { |
| 151 |
return Array.from(contentImages)?.map((el) => ({ source_url: el.src })); |
| 152 |
} else if (Array.isArray(tags)) { |
| 153 |
const values = tags.map((tag) => { |
| 154 |
const element = doc.querySelector(tag); |
| 155 |
return element ? { type: tag, url: element.src } : null; |
| 156 |
}); |
| 157 |
|
| 158 |
const filterValues = values.filter((val) => val); |
| 159 |
return filterValues.length > 0 ? filterValues[0] : null; |
| 160 |
} |
| 161 |
|
| 162 |
return null; |
| 163 |
}; |
| 164 |
|
| 165 |
export const debounce = (func, delay) => { |
| 166 |
let timeoutId; |
| 167 |
return (...args) => { |
| 168 |
if (timeoutId) { |
| 169 |
clearTimeout(timeoutId); |
| 170 |
} |
| 171 |
timeoutId = setTimeout(() => { |
| 172 |
func(...args); |
| 173 |
}, delay); |
| 174 |
}; |
| 175 |
}; |
| 176 |
|
| 177 |
export const getMediaUrl = (attachment, attributes) => { |
| 178 |
const { attachment_metadata, content, attachment_url } = attachment; |
| 179 |
const { |
| 180 |
imageReplaceWith, |
| 181 |
imageFallbackReplace, |
| 182 |
toggleCustomFallbackBg, |
| 183 |
imageReplaceWithImage, |
| 184 |
imageReplaceWithVideo, |
| 185 |
post_thumbnail_url, |
| 186 |
imageGallerySource, |
| 187 |
} = attributes; |
| 188 |
|
| 189 |
const sourceImages = |
| 190 |
"img_gallery_in_post_content" === imageGallerySource |
| 191 |
? getMediaUrlFromContent("img_gallery_in_post_content", content) |
| 192 |
: []; |
| 193 |
|
| 194 |
let metadataImgUrl = ""; |
| 195 |
let mediaFromContent = {}; |
| 196 |
if (post_thumbnail_url) { |
| 197 |
metadataImgUrl = post_thumbnail_url; |
| 198 |
} else if (!attachment_metadata && imageFallbackReplace === "source") { |
| 199 |
const replaceWith = imageReplaceWith?.length > 0 ? imageReplaceWith : ["img", "video", "audio"]; |
| 200 |
mediaFromContent = getMediaUrlFromContent(replaceWith, content); |
| 201 |
sourceImages?.shift(); |
| 202 |
} else if (!attachment_metadata && imageFallbackReplace === "custom") { |
| 203 |
const items = { |
| 204 |
img: { |
| 205 |
type: "img", |
| 206 |
url: imageReplaceWithImage?.url, |
| 207 |
}, |
| 208 |
video: { |
| 209 |
type: "video", |
| 210 |
url: imageReplaceWithVideo?.url, |
| 211 |
}, |
| 212 |
}; |
| 213 |
mediaFromContent = items[toggleCustomFallbackBg]; |
| 214 |
} else if (!metadataImgUrl && attachment_url) { |
| 215 |
metadataImgUrl = attachment_url; |
| 216 |
} |
| 217 |
return { mediaUrl: metadataImgUrl, mediaFromContent, sourceImages }; |
| 218 |
}; |
| 219 |
|
| 220 |
export const uniqueIdToClientId = (uniqueId, blockName) => { |
| 221 |
const removeSlice = `sp-smart-${blockName}-`; |
| 222 |
return uniqueId?.replace(removeSlice, ""); |
| 223 |
}; |
| 224 |
|
| 225 |
export const getPaginationUniqueId = (uniqueId, blockName) => { |
| 226 |
const clientId = uniqueIdToClientId(uniqueId, blockName); |
| 227 |
const paginationUniqueId = `sp-smart-post-show-pagination-${clientId}`; |
| 228 |
return paginationUniqueId; |
| 229 |
}; |
| 230 |
|
| 231 |
const accordionStore = { |
| 232 |
get: () => localStorage.getItem("sp-opened-accordion"), |
| 233 |
set: (e) => localStorage.setItem("sp-opened-accordion", e), |
| 234 |
}; |
| 235 |
|
| 236 |
export const manageOpenAccordion = () => { |
| 237 |
const [openedAccordion, setOpenAccordion] = useState(accordionStore.get()); |
| 238 |
|
| 239 |
const togglePanelBody = (val) => { |
| 240 |
if (openedAccordion === val) { |
| 241 |
setOpenAccordion(""); |
| 242 |
accordionStore.set(""); |
| 243 |
} else { |
| 244 |
setOpenAccordion(val); |
| 245 |
accordionStore.set(val); |
| 246 |
} |
| 247 |
}; |
| 248 |
|
| 249 |
return { togglePanelBody, openedAccordion }; |
| 250 |
}; |
| 251 |
|
| 252 |
export const useHandleScroll = () => { |
| 253 |
const [height, setHeight] = useState(); |
| 254 |
const [heightUnit, setHeightUnit] = useState("px"); |
| 255 |
const ref = useRef(null); |
| 256 |
let newHeight = 0; |
| 257 |
|
| 258 |
const handleScroll = (e) => { |
| 259 |
e.defaultPrevent; |
| 260 |
const scrollPosition = window.scrollY + 200; |
| 261 |
const elementPosition = ref.current?.getBoundingClientRect().top + window.scrollY; |
| 262 |
|
| 263 |
if (ref.current?.getBoundingClientRect().bottom - 518 < 0) { |
| 264 |
setHeightUnit("%"); |
| 265 |
setHeight(100); |
| 266 |
} else { |
| 267 |
setHeightUnit("px"); |
| 268 |
} |
| 269 |
|
| 270 |
if (scrollPosition > elementPosition && ref.current?.getBoundingClientRect().bottom - 518 > 0) { |
| 271 |
newHeight = scrollPosition + 320 - elementPosition; |
| 272 |
setHeight(newHeight); |
| 273 |
} |
| 274 |
}; |
| 275 |
window.addEventListener("scroll", handleScroll); |
| 276 |
return { height, heightUnit, ref }; |
| 277 |
}; |
| 278 |
|
| 279 |
export const queryFn = async (data) => { |
| 280 |
const response = await axios.post(sp_smart_post_block_localize.ajaxUrl, data); |
| 281 |
return response.data; |
| 282 |
}; |
| 283 |
|
| 284 |
/// |
| 285 |
// Create css link for responsive device, |
| 286 |
export const createCssLink = (Id, linkId, href) => { |
| 287 |
// Tablet / Mobile Starts. |
| 288 |
const tabletPreview = document.getElementsByClassName("is-tablet-preview"); |
| 289 |
const mobilePreview = document.getElementsByClassName("is-mobile-preview"); |
| 290 |
const canvas = document.getElementsByClassName("edit-site-visual-editor__editor-canvas"); |
| 291 |
|
| 292 |
if (0 !== tabletPreview.length || 0 !== mobilePreview.length || 0 !== canvas.length) { |
| 293 |
const preview = tabletPreview[0] || mobilePreview[0] || canvas[0]; |
| 294 |
|
| 295 |
let iframe = false; |
| 296 |
|
| 297 |
if (preview) { |
| 298 |
iframe = preview.getElementsByTagName("iframe")[0]; |
| 299 |
if (0 !== canvas.length) { |
| 300 |
iframe = preview; |
| 301 |
} |
| 302 |
} |
| 303 |
|
| 304 |
const IframeDocument = iframe?.contentWindow.document || iframe?.contentDocument; |
| 305 |
|
| 306 |
linkId = IframeDocument.getElementById(linkId); |
| 307 |
|
| 308 |
if (null === linkId || undefined === linkId) { |
| 309 |
const $link = document.createElement("link"); |
| 310 |
$link.setAttribute("id", Id); |
| 311 |
$link.setAttribute("href", href); |
| 312 |
$link.setAttribute("media", "all"); |
| 313 |
$link.setAttribute("rel", "stylesheet"); |
| 314 |
|
| 315 |
IframeDocument.head.appendChild($link); |
| 316 |
} |
| 317 |
} |
| 318 |
}; |
| 319 |
|
| 320 |
// Create js link for responsive device, |
| 321 |
export const createJsLink = (Id, linkId, href) => { |
| 322 |
// Tablet / Mobile Starts. |
| 323 |
const tabletPreview = document.getElementsByClassName("is-tablet-preview"); |
| 324 |
const mobilePreview = document.getElementsByClassName("is-mobile-preview"); |
| 325 |
const canvas = document.getElementsByClassName("edit-site-visual-editor__editor-canvas"); |
| 326 |
|
| 327 |
if (0 !== tabletPreview.length || 0 !== mobilePreview.length || 0 !== canvas.length) { |
| 328 |
const preview = tabletPreview[0] || mobilePreview[0] || canvas[0]; |
| 329 |
|
| 330 |
let iframe = false; |
| 331 |
|
| 332 |
if (preview) { |
| 333 |
iframe = preview.getElementsByTagName("iframe")[0]; |
| 334 |
if (0 !== canvas.length) { |
| 335 |
iframe = preview; |
| 336 |
} |
| 337 |
} |
| 338 |
|
| 339 |
const IframeDocument = iframe?.contentWindow.document || iframe?.contentDocument; |
| 340 |
|
| 341 |
linkId = IframeDocument.getElementById(linkId); |
| 342 |
|
| 343 |
if (null === linkId || undefined === linkId) { |
| 344 |
const $link = document.createElement("script"); |
| 345 |
$link.setAttribute("id", Id); |
| 346 |
$link.setAttribute("src", href); |
| 347 |
$link.setAttribute("type", "text/javascript"); |
| 348 |
|
| 349 |
IframeDocument.body.appendChild($link); |
| 350 |
} |
| 351 |
} |
| 352 |
}; |
| 353 |
// path edit fn. |
| 354 |
const shortUniqueId = (uniqueId) => { |
| 355 |
return uniqueId.slice(uniqueId.length - 8, uniqueId.length); |
| 356 |
}; |
| 357 |
|
| 358 |
export const spSplit = (data, splitBy) => { |
| 359 |
return data?.split([splitBy]); |
| 360 |
}; |
| 361 |
|
| 362 |
export const inArray = (array, value) => { |
| 363 |
return array.includes(value); |
| 364 |
}; |
| 365 |
|
| 366 |
export const useSPLocation = (id) => { |
| 367 |
const { search } = window.location; |
| 368 |
const liveFilterArray = ["author", "order_by", "order"]; |
| 369 |
let queries = {}; |
| 370 |
let keywordSearchFromUrl = ""; |
| 371 |
let queriesArray = []; |
| 372 |
|
| 373 |
if (!search || !inArray(search, shortUniqueId(id))) { |
| 374 |
return { queries, keywordSearchFromUrl }; |
| 375 |
} |
| 376 |
const searchArrayFromUrl = spSplit(search, "&&"); |
| 377 |
const keywordSearch = spSplit(searchArrayFromUrl[searchArrayFromUrl.length - 1], "="); |
| 378 |
queriesArray = spSplit(spSplit(searchArrayFromUrl[1], "+")[1], "&"); |
| 379 |
keywordSearchFromUrl = keywordSearch[0] === "search" ? decodeURIComponent(keywordSearch[1]) : ""; |
| 380 |
|
| 381 |
queriesArray?.forEach((query) => { |
| 382 |
const queryKeyName = spSplit(query, "=")[0]; |
| 383 |
const queryValueName = spSplit(query, "=")[1]; |
| 384 |
const categoryName = inArray(liveFilterArray, queryKeyName) ? undefined : queryKeyName; |
| 385 |
const type = inArray(liveFilterArray, queryKeyName) ? queryKeyName : "taxonomy"; |
| 386 |
const label = categoryName ? categoryName : type; |
| 387 |
const id = |
| 388 |
inArray(["order", "order_by"], type) || queryValueName === "all" |
| 389 |
? queryValueName |
| 390 |
: parseInt(queryValueName); |
| 391 |
|
| 392 |
queries = { |
| 393 |
...queries, |
| 394 |
[label]: { id, type, taxonomy_type: categoryName }, |
| 395 |
}; |
| 396 |
}); |
| 397 |
return { queries, keywordSearchFromUrl }; |
| 398 |
}; |
| 399 |
|
| 400 |
export const setSPCustomPath = ({ uniqueId, queries, keywordSearch }) => { |
| 401 |
const id = shortUniqueId(uniqueId); |
| 402 |
const allQueries = Object.values(queries)?.filter((query) => query.id !== "all"); |
| 403 |
|
| 404 |
const filter = allQueries?.reduce((acc, { id, type, taxonomy_type }, index) => { |
| 405 |
return `${acc}${index === 0 ? "" : "&"}${taxonomy_type ? taxonomy_type : type}=${id}`; |
| 406 |
}, ""); |
| 407 |
|
| 408 |
const query = `?sps=${id}${filter.length > 0 ? `&&filter+${filter}` : ""}${ |
| 409 |
keywordSearch.length > 0 ? `&&search=${keywordSearch}` : "" |
| 410 |
}`; |
| 411 |
const baseUrl = window.location.pathname; |
| 412 |
const url = filter.length > 0 || keywordSearch.length > 0 ? query : baseUrl; |
| 413 |
history.pushState({}, "", url); |
| 414 |
}; |
| 415 |
|
| 416 |
export const breakpoint = () => { |
| 417 |
if (typeof select("core/edit-site") !== "undefined" || typeof select("core/editor") !== "undefined") { |
| 418 |
return useDeviceType(); |
| 419 |
} |
| 420 |
|
| 421 |
let breakpoints = { |
| 422 |
"(min-width: 1024px)": "Desktop", |
| 423 |
"(min-width: 600px) and (max-width: 1023.98px)": "Tablet", |
| 424 |
"(min-width: 0px) and (max-width: 599.98px)": "Mobile", |
| 425 |
}; |
| 426 |
|
| 427 |
for (let media in breakpoints) { |
| 428 |
if (window.matchMedia(media).matches) { |
| 429 |
return breakpoints[media]; |
| 430 |
} |
| 431 |
} |
| 432 |
|
| 433 |
return "Desktop"; |
| 434 |
}; |
| 435 |
|
| 436 |
export const paginationDotType = (swiperDotsRef, type, uniqueId = "") => { |
| 437 |
const carousel_id = uniqueId ? `#${uniqueId}` : ""; |
| 438 |
const paginationDotStyle = { |
| 439 |
dots: { |
| 440 |
el: swiperDotsRef?.current || `${carousel_id} .sp-pagination-horizontal`, |
| 441 |
clickable: true, |
| 442 |
}, |
| 443 |
strokes: { |
| 444 |
el: swiperDotsRef?.current || `${carousel_id} .sp-pagination-horizontal`, |
| 445 |
clickable: true, |
| 446 |
}, |
| 447 |
dynamic: { |
| 448 |
el: swiperDotsRef?.current || `${carousel_id} .sp-pagination-horizontal`, |
| 449 |
dynamicBullets: true, |
| 450 |
clickable: true, |
| 451 |
}, |
| 452 |
fraction: { |
| 453 |
el: swiperDotsRef?.current || `${carousel_id} .sp-pagination-horizontal`, |
| 454 |
type: "fraction", |
| 455 |
}, |
| 456 |
numbers: { |
| 457 |
el: swiperDotsRef?.current || `${carousel_id} .sp-pagination-horizontal`, |
| 458 |
clickable: true, |
| 459 |
renderBullet: function (index, className) { |
| 460 |
return '<span class="' + className + '">' + (index + 1) + "</span>"; |
| 461 |
}, |
| 462 |
paginationType: "number", |
| 463 |
}, |
| 464 |
scrollbar: false, |
| 465 |
}; |
| 466 |
|
| 467 |
return paginationDotStyle[type]; |
| 468 |
}; |
| 469 |
|
| 470 |
export const maxValueFromObject = (objName) => { |
| 471 |
const newArray = Object.values(objName); |
| 472 |
const arrayOfNumbers = newArray.map((value) => (value === "" ? 0 : Number(value))); |
| 473 |
return Math.max(...arrayOfNumbers); |
| 474 |
}; |
| 475 |
|
| 476 |
export const swiperPaddingForBoxShadow = (normalBool, normalObj, hoverBool, hoverObj) => { |
| 477 |
const normalValue = normalBool ? maxValueFromObject(normalObj) || 0 : 0; |
| 478 |
const hoverValue = hoverBool ? maxValueFromObject(hoverObj) || 0 : 0; |
| 479 |
|
| 480 |
const maxValue = Math.max(normalValue, hoverValue); |
| 481 |
|
| 482 |
return `0 ${maxValue}px ${maxValue}px`; |
| 483 |
}; |
| 484 |
|
| 485 |
export const classNameDeviceType = ( |
| 486 |
property, |
| 487 |
pValue, |
| 488 |
deviceType, |
| 489 |
currentScreen = "Desktop", |
| 490 |
page = "editor", |
| 491 |
important = false, |
| 492 |
extraClass = false, |
| 493 |
customUnit = "" |
| 494 |
) => { |
| 495 |
const devicePrefix = { |
| 496 |
Desktop: "", |
| 497 |
Tablet: "md", |
| 498 |
Mobile: "sm", |
| 499 |
}; |
| 500 |
const classNamePrefix = { |
| 501 |
"font-size": "font", |
| 502 |
"letter-spacing": "ls", |
| 503 |
"line-height": "lh", |
| 504 |
height: "h", |
| 505 |
width: "w", |
| 506 |
"column-gap": "c-gap", |
| 507 |
gap: "gap", |
| 508 |
top: "vertical", |
| 509 |
left: "horizontal", |
| 510 |
}; |
| 511 |
|
| 512 |
const deviceValue = pValue?.device?.[deviceType]; |
| 513 |
const classNameValue = typeof deviceValue === "object" && side ? deviceValue?.[side] : deviceValue; |
| 514 |
|
| 515 |
if (classNameValue == null || !classNamePrefix[property]) { |
| 516 |
console.warn(`Invalid inputs: property=${property}, deviceType=${deviceType}, pValue=`, pValue); |
| 517 |
return null; |
| 518 |
} |
| 519 |
|
| 520 |
const unit = customUnit ? customUnit : pValue?.unit?.[deviceType] || ""; |
| 521 |
const endTag = extraClass && extraClass === "meta-svg" ? " svg" : ""; |
| 522 |
const importantText = |
| 523 |
page === "editor" ? (deviceType.includes(currentScreen) ? " !important" : "") : important ? " !important" : ""; |
| 524 |
const finalValue = `${classNameValue}${unit}${importantText}`; |
| 525 |
const suffix = devicePrefix[deviceType]; |
| 526 |
|
| 527 |
return ![undefined, null].includes(classNameValue) |
| 528 |
? { |
| 529 |
class: `.sp-${extraClass ? `${extraClass}-` : ""}${classNamePrefix[property]}${ |
| 530 |
suffix ? `-${suffix}` : "" |
| 531 |
}-${convertToClassName(classNameValue.toString() + unit)}${endTag}`, |
| 532 |
property, |
| 533 |
value: finalValue, |
| 534 |
} |
| 535 |
: {}; |
| 536 |
}; |
| 537 |
|
| 538 |
export const buildFontClasses = (property, value, extraClass = false, customUnit = "") => { |
| 539 |
const deviceSuffixes = { |
| 540 |
Desktop: "", |
| 541 |
Mobile: "sm", |
| 542 |
Tablet: "md", |
| 543 |
}; |
| 544 |
|
| 545 |
// Abbreviations for CSS properties |
| 546 |
const propertyAbbreviations = { |
| 547 |
"font-size": "font", |
| 548 |
"letter-spacing": "ls", |
| 549 |
"line-height": "lh", |
| 550 |
height: "h", |
| 551 |
width: "w", |
| 552 |
"column-gap": "c-gap", |
| 553 |
gap: "gap", |
| 554 |
top: "vertical", |
| 555 |
left: "horizontal", |
| 556 |
}; |
| 557 |
|
| 558 |
const shortProperty = propertyAbbreviations[property] || property; |
| 559 |
|
| 560 |
return Object.keys(deviceSuffixes).reduce((classes, device) => { |
| 561 |
const suffix = deviceSuffixes[device]; |
| 562 |
|
| 563 |
// Ensure 0 is a valid value by explicitly checking for undefined or null |
| 564 |
if (value?.device?.[device] !== "" && (value?.unit?.[device] !== "" || customUnit)) { |
| 565 |
const className = `sp${extraClass ? `-${extraClass}` : ""}-${shortProperty}${ |
| 566 |
suffix ? `-${suffix}` : "" |
| 567 |
}-${convertToClassName(value.device?.[device] + (customUnit ? customUnit : value?.unit?.[device]))}`; |
| 568 |
classes[className] = true; |
| 569 |
} |
| 570 |
return classes; |
| 571 |
}, {}); |
| 572 |
}; |
| 573 |
|
| 574 |
export const isObjectEmpty = (obj) => { |
| 575 |
if (!obj || typeof obj !== "object") return false; |
| 576 |
return Object.values(obj).every((value) => (typeof value === "object" ? isObjectEmpty(value) : value === "")); |
| 577 |
}; |
| 578 |
|
| 579 |
export const isEditor = () => { |
| 580 |
// return typeof select( 'core/editor' ) !== 'undefined' ? true : false; |
| 581 |
return true; |
| 582 |
}; |
| 583 |
|
| 584 |
// Google fonts list controls fn. |
| 585 |
export const googleFonts = (fonts, page = "edit") => { |
| 586 |
if (!fonts?.length) { |
| 587 |
return []; |
| 588 |
} |
| 589 |
|
| 590 |
let returnFont = ""; |
| 591 |
|
| 592 |
if (page !== "edit") { |
| 593 |
// Frontend fonts array (unique + cleaned). |
| 594 |
const fontList = fonts |
| 595 |
.map((font) => |
| 596 |
font?.typography?.family?.length > 0 ? `${font.typography.family}:${font.typography.fontWeight}` : "" |
| 597 |
) |
| 598 |
.filter(Boolean); // remove empty strings |
| 599 |
|
| 600 |
// Return unique values only |
| 601 |
returnFont = [...new Set(fontList)]; |
| 602 |
} else { |
| 603 |
// Edit page (Google Fonts import) |
| 604 |
const fontList = fonts |
| 605 |
.map((font) => |
| 606 |
font?.typography?.family?.length > 0 |
| 607 |
? `family=${font.typography.family.replaceAll(" ", "+")}:wght@${font.typography.fontWeight}&` |
| 608 |
: "" |
| 609 |
) |
| 610 |
.filter(Boolean); |
| 611 |
|
| 612 |
// Deduplicate imports |
| 613 |
const uniqueFonts = [...new Set(fontList)]; |
| 614 |
|
| 615 |
const updatedUniqueFonts = |
| 616 |
uniqueFonts.length > 0 && |
| 617 |
uniqueFonts?.filter((item) => { |
| 618 |
const [name] = item.split(":"); |
| 619 |
return name.trim() !== ""; |
| 620 |
}); |
| 621 |
|
| 622 |
returnFont = |
| 623 |
updatedUniqueFonts.length > 0 |
| 624 |
? `@import url('https://fonts.googleapis.com/css2?${updatedUniqueFonts.join("")}display=swap');` |
| 625 |
: ""; |
| 626 |
} |
| 627 |
return returnFont; |
| 628 |
}; |
| 629 |
|
| 630 |
// Show/hide on device type (Desktop, Tablet, Mobile) |
| 631 |
export const showHide = (deviceCss, id, hide, defaultVal = "") => { |
| 632 |
return [ |
| 633 |
...deviceCss, |
| 634 |
{ |
| 635 |
class: `#${id}`, |
| 636 |
styles: { |
| 637 |
display: hide ? "none" : defaultVal, |
| 638 |
}, |
| 639 |
}, |
| 640 |
]; |
| 641 |
}; |
| 642 |
|
| 643 |
export const backgroundStyle = (attributes, bgImageObj = {}, hover = false, condition = true) => { |
| 644 |
if (!attributes && !condition) return {}; |
| 645 |
|
| 646 |
if (attributes?.color?.style === "video") { |
| 647 |
return {}; |
| 648 |
} |
| 649 |
if ((!hover && attributes?.color?.style === "image") || (hover && attributes?.hover?.style === "image")) { |
| 650 |
return { |
| 651 |
"background-image": Object.keys(bgImageObj).length !== 0 ? `url(${bgImageObj?.url})` : "", |
| 652 |
"background-position": "center", |
| 653 |
"background-attachment": "scroll", |
| 654 |
"background-repeat": "no-repeat", |
| 655 |
"background-size": "cover", |
| 656 |
}; |
| 657 |
} |
| 658 |
// Handle hover style |
| 659 |
const styleSource = hover ? attributes?.hover : attributes?.color; |
| 660 |
|
| 661 |
return { |
| 662 |
background: colorControls(styleSource?.style, styleSource?.solidColor, styleSource?.gradient), |
| 663 |
}; |
| 664 |
}; |
| 665 |
|
| 666 |
export const gradientHoverStyle = (selector, bgAttr, imgObj = "", alt = "") => { |
| 667 |
if (!bgAttr) return; |
| 668 |
|
| 669 |
const normalBGStyle = [ |
| 670 |
{ |
| 671 |
class: `${selector}:hover`, |
| 672 |
styles: { |
| 673 |
...(backgroundStyle(bgAttr, imgObj, true) || backgroundStyle(bgAttr, alt, true)), |
| 674 |
}, |
| 675 |
}, |
| 676 |
]; |
| 677 |
const gradientBGStyle = [ |
| 678 |
{ |
| 679 |
class: `${selector}::before`, |
| 680 |
styles: { |
| 681 |
content: '""', |
| 682 |
display: "block", |
| 683 |
position: "absolute", |
| 684 |
width: "100%", |
| 685 |
height: "100%", |
| 686 |
top: "0", |
| 687 |
left: "0", |
| 688 |
"z-index": "1", |
| 689 |
opacity: "0", |
| 690 |
...backgroundStyle(bgAttr, "", true), |
| 691 |
transition: "opacity 0.3s ease-in-out", |
| 692 |
}, |
| 693 |
}, |
| 694 |
{ |
| 695 |
class: `${selector}`, |
| 696 |
styles: { |
| 697 |
position: "relative", |
| 698 |
}, |
| 699 |
}, |
| 700 |
{ |
| 701 |
class: `${selector}:hover::before`, |
| 702 |
styles: { |
| 703 |
opacity: "1", |
| 704 |
}, |
| 705 |
}, |
| 706 |
]; |
| 707 |
return bgAttr?.hover?.style !== "gradient" ? normalBGStyle : gradientBGStyle; |
| 708 |
}; |
| 709 |
|
| 710 |
export const capitalizeWords = (str) => |
| 711 |
str |
| 712 |
.trim() |
| 713 |
.toLowerCase() |
| 714 |
.split(" ") |
| 715 |
.map((word) => { |
| 716 |
const i = ["(", "-", "/", "{", "[", "_"].includes(word.charAt(0)) ? 1 : 0; |
| 717 |
return word.slice(0, i) + word.charAt(i).toUpperCase() + word.slice(i + 1); |
| 718 |
}) |
| 719 |
.join(" "); |
| 720 |
|
| 721 |
export const typographyCss = (attr) => { |
| 722 |
return { |
| 723 |
"font-family": attr?.typography?.family, |
| 724 |
"font-weight": attr?.typography?.fontWeight, |
| 725 |
"font-style": attr?.typography?.style || "normal", |
| 726 |
"text-decoration": attr?.typography?.decoration || "none", |
| 727 |
"text-transform": attr?.typography?.transform, |
| 728 |
}; |
| 729 |
}; |
| 730 |
|