reblendjs
Version:
ReblendJs uses Reactjs pradigm to build UI components, with isolated state for each components.
226 lines (188 loc) • 5.95 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { IAny } from '../interface/IAny'
import NullException from '../exceptions/NullException'
import { ConfigUtil } from '../internal/ConfigUtil'
export function objectEquals(obj1: { [x: string]: any } | null, obj2: { [x: string]: any } | null) {
// Check if both object are strictly equal
if (obj1 === obj2) {
return true
}
// Check if either object is null or not
if (typeof obj1 !== 'object' || obj1 == null || typeof obj2 !== 'object' || obj2 == null) {
return false
}
// Get the keys of both objects
const keys1 = Object.keys(obj1)
const keys2 = Object.keys(obj2)
// Check if the number of keys is the same
if (keys1.length !== keys2.length) {
return false
}
// Iterate through the keys and recursively check for equality
for (const key of keys1) {
if (!keys2.includes(key) || !objectEquals(obj1[key], obj2[key])) {
return false
}
}
return true
}
export function getDefinedValuesFrom(object: { [key: string]: any }) {
const definedValues: { [key: string]: any } = {}
for (const key in object) {
const value = object[key]
if (value != null && value != undefined) {
definedValues[key] = value
}
}
return definedValues
}
export function escapeRegExp(value: string) {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
export function sumField(objArr: { [key: string]: any }[], ...field: string[]) {
if (!objArr || (Array.isArray(objArr) && objArr.length <= 0)) {
return 0
}
let sum = 0
for (const obj of objArr) {
let theValue = getObjectField(obj, field)
if (theValue) {
if (typeof theValue === 'string') {
theValue = parseInt(theValue)
}
if (typeof theValue === 'number') {
sum += theValue
}
}
}
return sum
}
export function getObjectField(obj: { [key: string]: any }, fields: string[]): any {
const f = [...fields]
if (f.length <= 0 || !obj) {
return obj
}
const leftMostFieldName = f.shift()
if (!leftMostFieldName) {
return obj
}
return getObjectField(obj[leftMostFieldName], f)
}
export const shallowRemoveDuplicates = (arr: any[]): any[] => {
const unique = new Set()
const filtered = arr?.filter((item) => {
if (item && !unique.has(item)) {
unique.add(item)
return true
}
return false
})
return filtered
}
export const snakeCase = (camelCase: string): string => {
return camelCase.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`).substring(1)
}
export const appendChildren = (parent: HTMLElement | null, ...children: HTMLElement[]) => {
if (!parent) {
throw new NullException()
}
for (const child of children) {
parent.appendChild(child)
}
return parent
}
export const removeLastChild = (parent: HTMLElement | null) => {
if (!parent) {
throw new NullException()
}
const removedChild = parent.removeChild(parent.lastChild as ChildNode)
return removedChild
}
export const cssString = (styleObject: IAny) => {
let styleString = ''
for (const [key, value] of Object.entries(styleObject)) {
styleString += `${key}: ${value === undefined ? 'initial' : value}; \n`
}
return styleString.trim()
}
export const cssObjectFromString = (styleString: string): CSSStyleDeclaration => {
const regex = /([a-zA-Z-]+)\s*:\s*([^;]+)/g
const cssObject: CSSStyleDeclaration = {} as any
let match: RegExpExecArray | null
while ((match = regex.exec(styleString)) !== null) {
const styleName = match[1].trim()
const value = match[2].trim()
cssObject[styleName] = value
}
return cssObject
}
export const spreadTo = (parentObj: IAny, objToSpread: IAny) => {
if (!objToSpread || !parentObj) {
return parentObj
}
const keys = Object.keys(objToSpread)
const values = Object.values(objToSpread)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const value = values[i]
parentObj[key] = value
}
return parentObj
}
export function registerElement(name: string, element: typeof HTMLElement): any {
if (!element) {
throw new Error('Element to register is null')
}
const tagName = snakeCase(name)
if (!customElements.get(tagName)) {
try {
customElements.define(tagName, element)
} catch (error: any) {
console.warn(error.message)
}
}
return element
}
export function capitalize(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
export const rand = (min = 1234, max = 9876) => {
return Math.floor(Math.random() * (max - min + 1)) + min
}
export const isCallable = (obj: any) => {
if (typeof obj !== 'function') {
return false
}
try {
// Check if obj is a class constructor by inspecting its string representation
// Classes typically have a string representation starting with "class"
const str = Function.prototype.toString.call(obj)
if (str.startsWith('class')) {
return false
}
} catch (e) {
// If any error occurs during string conversion, assume it's not callable
return false
}
return true
}
export const replaceOrAddItemToList = <T extends Array<any> | Set<any>>(list: T, oldItem: any, newItem: any): T => {
if (!list) return null as any
const items = Array.from(list)
const lastAttachedIndex = items.indexOf(oldItem)
if (lastAttachedIndex !== -1) {
items.splice(lastAttachedIndex, 1, newItem)
} else {
items.push(newItem)
}
if (list instanceof Set) {
return new Set(items) as any
}
return items as any
}
export const getConfig = () => ConfigUtil.getInstance().configs
export const donotDeffer = () => getConfig().noDefering
export const REBLEND_COMPONENT = 'reblendcomponent'
export const REBLEND_WRAPPER_FOR_REACT_COMPONENT = 'reblendwrapperforreactcomponent'
export const REBLEND_CHILDREN_WRAPPER_FOR_REACT_COMPONENT = 'reblendchildrenwrapperforreactcomponent'
export const CUSTOM_TAGNAME = 'customTagName'