UNPKG

reblendjs

Version:

ReblendJs uses Reactjs pradigm to build UI components, with isolated state for each components.

1,509 lines (1,498 loc) 148 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); class NullException extends Error { constructor(message) { super(message ?? 'Null object not accepted'); } } class ConfigUtil { static instance; static getInstance() { return new ConfigUtil(); } defaultConfigs = { noDefering: false, deferTimeout: 0, noPreloader: false, preloaderDeferTimeout: 1000, placeholderDeferTimeout: 100, lazyComponentDeferTimeout: 500, diffConfig: { keyThreshold: 50, depthThreshold: 3, treatInstancesAsEqual: [Node], excludeKeys: ['ref'] } }; configs = this.defaultConfigs; constructor() { if (ConfigUtil.instance) { return ConfigUtil.instance; } else { ConfigUtil.instance = this; } } update(config) { if (config) { Object.assign(this.configs, config); } return this.configs; } reset() { this.configs = this.defaultConfigs; } } function objectEquals(obj1, obj2) { // 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; } function getDefinedValuesFrom(object) { const definedValues = {}; for (const key in object) { const value = object[key]; if (value != null && value != undefined) { definedValues[key] = value; } } return definedValues; } function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } function sumField(objArr, ...field) { 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; } function getObjectField(obj, fields) { const f = [...fields]; if (f.length <= 0 || !obj) { return obj; } const leftMostFieldName = f.shift(); if (!leftMostFieldName) { return obj; } return getObjectField(obj[leftMostFieldName], f); } const shallowRemoveDuplicates = arr => { const unique = new Set(); const filtered = arr?.filter(item => { if (item && !unique.has(item)) { unique.add(item); return true; } return false; }); return filtered; }; const snakeCase = camelCase => { return camelCase.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`).substring(1); }; const appendChildren = (parent, ...children) => { if (!parent) { throw new NullException(); } for (const child of children) { parent.appendChild(child); } return parent; }; const removeLastChild = parent => { if (!parent) { throw new NullException(); } const removedChild = parent.removeChild(parent.lastChild); return removedChild; }; const cssString = styleObject => { let styleString = ''; for (const [key, value] of Object.entries(styleObject)) { styleString += `${key}: ${value === undefined ? 'initial' : value}; \n`; } return styleString.trim(); }; const cssObjectFromString = styleString => { const regex = /([a-zA-Z-]+)\s*:\s*([^;]+)/g; const cssObject = {}; let match; while ((match = regex.exec(styleString)) !== null) { const styleName = match[1].trim(); const value = match[2].trim(); cssObject[styleName] = value; } return cssObject; }; const spreadTo = (parentObj, objToSpread) => { 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; }; function registerElement(name, element) { 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) { console.warn(error.message); } } return element; } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } const rand = (min = 1234, max = 9876) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; const isCallable = obj => { 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; }; const replaceOrAddItemToList = (list, oldItem, newItem) => { if (!list) return null; 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); } return items; }; const getConfig = () => ConfigUtil.getInstance().configs; const donotDeffer = () => getConfig().noDefering; const REBLEND_COMPONENT = 'reblendcomponent'; const REBLEND_WRAPPER_FOR_REACT_COMPONENT = 'reblendwrapperforreactcomponent'; const REBLEND_CHILDREN_WRAPPER_FOR_REACT_COMPONENT = 'reblendchildrenwrapperforreactcomponent'; const CUSTOM_TAGNAME = 'customTagName'; var utils = /*#__PURE__*/Object.freeze({ __proto__: null, CUSTOM_TAGNAME: CUSTOM_TAGNAME, REBLEND_CHILDREN_WRAPPER_FOR_REACT_COMPONENT: REBLEND_CHILDREN_WRAPPER_FOR_REACT_COMPONENT, REBLEND_COMPONENT: REBLEND_COMPONENT, REBLEND_WRAPPER_FOR_REACT_COMPONENT: REBLEND_WRAPPER_FOR_REACT_COMPONENT, appendChildren: appendChildren, capitalize: capitalize, cssObjectFromString: cssObjectFromString, cssString: cssString, donotDeffer: donotDeffer, escapeRegExp: escapeRegExp, getConfig: getConfig, getDefinedValuesFrom: getDefinedValuesFrom, getObjectField: getObjectField, isCallable: isCallable, objectEquals: objectEquals, rand: rand, registerElement: registerElement, removeLastChild: removeLastChild, replaceOrAddItemToList: replaceOrAddItemToList, shallowRemoveDuplicates: shallowRemoveDuplicates, snakeCase: snakeCase, spreadTo: spreadTo, sumField: sumField }); /* eslint-disable @typescript-eslint/no-explicit-any */ class StyleUtil { static instance; elementStyles = { [`[${REBLEND_COMPONENT}], [${REBLEND_WRAPPER_FOR_REACT_COMPONENT}], [${REBLEND_CHILDREN_WRAPPER_FOR_REACT_COMPONENT}]`]: { display: 'contents !important' } }; styleElement; constructor() { if (StyleUtil.instance) { return StyleUtil.instance; } else { this.init(); StyleUtil.instance = this; } } init() { this.styleElement = document.createElement('style'); document.head.appendChild(this.styleElement); this.refresh(); } update(elementQuerySelector, style) { if (!elementQuerySelector) { throw new Error('Invalid query selector or style'); } const styleObject = typeof style === 'string' ? cssObjectFromString(style) : style; this.elementStyles[elementQuerySelector] = { ...this.elementStyles[elementQuerySelector], ...styleObject }; this.refresh(); } remove(elementQuerySelector, styleKey) { this.elementStyles[elementQuerySelector] && delete this.elementStyles[elementQuerySelector][styleKey]; this.refresh(); } refresh() { const textContent = []; for (const [querySelector, elementStyle] of Object.entries(this.elementStyles)) { textContent.push(`${querySelector} {${cssString(elementStyle)}}\n\n`); } this.styleElement.textContent = textContent.join(''); } } /** * A map of attribute keys to their corresponding standard HTML attribute names, default values, * or React-specific properties. The object supports various attribute types such as standard * HTML attributes, RDFa attributes, microdata attributes, React-specific attributes, and more. * * - If the value is a string, it represents the corresponding HTML attribute name. * - If the value is `null`, the attribute does not map to an HTML attribute (e.g., React-specific attributes like `children`). * - If the value is an object, it represents an attribute with a custom name that should be used for the corresponding property (e.g., `dangerouslySetInnerHTML` maps to the `innerHTML` property). * * @type {Record<string, string | null | { name: string }>} */ const allAttribute = { // Standard HTML attributes accept: 'accept', acceptCharset: 'accept-charset', accessKey: 'accesskey', action: 'action', allowFullScreen: 'allowfullscreen', allowTransparency: 'allowtransparency', alt: 'alt', async: 'async', autoComplete: 'autocomplete', autoFocus: 'autofocus', autoPlay: 'autoplay', capture: 'capture', cellPadding: 'cellpadding', cellSpacing: 'cellspacing', charSet: 'charset', checked: 'checked', cite: 'cite', class: 'class', classID: 'classid', cols: 'cols', colSpan: 'colspan', contentEditable: 'contenteditable', contextMenu: 'contextmenu', controls: 'controls', coords: 'coords', crossOrigin: 'crossorigin', data: 'data', dateTime: 'datetime', default: 'default', defer: 'defer', dir: 'dir', disabled: 'disabled', download: 'download', draggable: 'draggable', encType: 'enctype', form: 'form', formAction: 'formaction', formEncType: 'formenctype', formMethod: 'formmethod', formNoValidate: 'formnovalidate', formTarget: 'formtarget', frameBorder: 'frameborder', headers: 'headers', height: 'height', hidden: 'hidden', high: 'high', href: 'href', hrefLang: 'hreflang', htmlFor: 'for', httpEquiv: 'http-equiv', id: 'id', inputMode: 'inputmode', integrity: 'integrity', is: 'is', keyParams: 'keyparams', keyType: 'keytype', kind: 'kind', label: 'label', lang: 'lang', list: 'list', loop: 'loop', low: 'low', manifest: 'manifest', marginHeight: 'marginheight', marginWidth: 'marginwidth', max: 'max', maxLength: 'maxlength', media: 'media', mediaGroup: 'mediagroup', method: 'method', min: 'min', minLength: 'minlength', multiple: 'multiple', muted: 'muted', name: 'name', nonce: 'nonce', noValidate: 'novalidate', open: 'open', optimum: 'optimum', pattern: 'pattern', placeholder: 'placeholder', playsInline: 'playsinline', poster: 'poster', preload: 'preload', radioGroup: 'radiogroup', readOnly: 'readonly', rel: 'rel', required: 'required', reversed: 'reversed', role: 'role', rows: 'rows', rowSpan: 'rowspan', sandbox: 'sandbox', scope: 'scope', scoped: 'scoped', scrolling: 'scrolling', seamless: 'seamless', selected: 'selected', shape: 'shape', size: 'size', sizes: 'sizes', slot: 'slot', span: 'span', spellCheck: 'spellcheck', src: 'src', srcDoc: 'srcdoc', srcLang: 'srclang', srcSet: 'srcset', start: 'start', step: 'step', style: 'style', summary: 'summary', tabIndex: 'tabindex', target: 'target', title: 'title', translate: 'translate', type: 'type', useMap: 'usemap', value: 'value', width: 'width', wmode: 'wmode', wrap: 'wrap', /** * A map of attribute keys to their corresponding standard HTML attribute names, default values, * or React-specific properties. The object supports various attribute types such as standard * HTML attributes, RDFa attributes, microdata attributes, React-specific attributes, and more. * * - If the value is a string, it represents the corresponding HTML attribute name. * - If the value is `null`, the attribute does not map to an HTML attribute (e.g., React-specific attributes like `children`). * - If the value is an object, it represents an attribute with a custom name that should be used for the corresponding property (e.g., `dangerouslySetInnerHTML` maps to the `innerHTML` property). * * @type {Record<string, string | null | { name: string }>} */ // Referrer policy attributes referrerPolicy: 'referrerpolicy', // Default values defaultChecked: 'checked', defaultValue: 'value', // Suppressions suppressContentEditableWarning: 'suppresscontenteditablewarning', suppressHydrationWarning: 'suppresshydrationwarning', // RDFa attributes about: 'about', datatype: 'datatype', inlist: 'inlist', prefix: 'prefix', property: 'property', resource: 'resource', typeof: 'typeof', vocab: 'vocab', // Microdata attributes itemProp: 'itemprop', itemScope: 'itemscope', itemType: 'itemtype', itemID: 'itemid', itemRef: 'itemref', // Other attributes autoCapitalize: 'autocapitalize', autoCorrect: 'autocorrect', autoSave: 'autosave', color: 'color', results: 'results', security: 'security', unselectable: 'unselectable', // React-specific attributes className: 'class', dangerouslySetInnerHTML: { name: 'innerHTML' }, children: null, // Event attributes (React-specific camelCase and standard HTML lowercase) onCopy: 'oncopy', oncopy: 'oncopy', onCut: 'oncut', oncut: 'oncut', onPaste: 'onpaste', onpaste: 'onpaste', onCompositionEnd: 'oncompositionend', oncompositionend: 'oncompositionend', onCompositionStart: 'oncompositionstart', oncompositionstart: 'oncompositionstart', onCompositionUpdate: 'oncompositionupdate', oncompositionupdate: 'oncompositionupdate', onFocus: 'onfocus', onfocus: 'onfocus', onBlur: 'onblur', onblur: 'onblur', onChange: 'onchange', onchange: 'onchange', onInput: 'oninput', oninput: 'oninput', onReset: 'onreset', onreset: 'onreset', onSubmit: 'onsubmit', onsubmit: 'onsubmit', onInvalid: 'oninvalid', oninvalid: 'oninvalid', onLoad: 'onload', onload: 'onload', onError: 'onerror', onerror: 'onerror', onKeyDown: 'onkeydown', onkeydown: 'onkeydown', onKeyPress: 'onkeypress', onkeypress: 'onkeypress', onKeyUp: 'onkeyup', onkeyup: 'onkeyup', onAbort: 'onabort', onabort: 'onabort', onCanPlay: 'oncanplay', oncanplay: 'oncanplay', onCanPlayThrough: 'oncanplaythrough', oncanplaythrough: 'oncanplaythrough', onDurationChange: 'ondurationchange', ondurationchange: 'ondurationchange', onEmptied: 'onemptied', onemptied: 'onemptied', onEncrypted: 'onencrypted', onencrypted: 'onencrypted', onEnded: 'onended', onended: 'onended', onLoadedData: 'onloadeddata', onloadeddata: 'onloadeddata', onLoadedMetadata: 'onloadedmetadata', onloadedmetadata: 'onloadedmetadata', onLoadStart: 'onloadstart', onloadstart: 'onloadstart', onPause: 'onpause', onpause: 'onpause', onPlay: 'onplay', onplay: 'onplay', onPlaying: 'onplaying', onplaying: 'onplaying', onProgress: 'onprogress', onprogress: 'onprogress', onRateChange: 'onratechange', onratechange: 'onratechange', onSeeked: 'onseeked', onseeked: 'onseeked', onSeeking: 'onseeking', onseeking: 'onseeking', onStalled: 'onstalled', onstalled: 'onstalled', onSuspend: 'onsuspend', onsuspend: 'onsuspend', onTimeUpdate: 'ontimeupdate', ontimeupdate: 'ontimeupdate', onVolumeChange: 'onvolumechange', onvolumechange: 'onvolumechange', onWaiting: 'onwaiting', onwaiting: 'onwaiting', onAuxClick: 'onauxclick', onauxclick: 'onauxclick', onClick: 'onclick', onclick: 'onclick', onContextMenu: 'oncontextmenu', oncontextmenu: 'oncontextmenu', onDoubleClick: 'ondoubleclick', ondoubleclick: 'ondoubleclick', onDrag: 'ondrag', ondrag: 'ondrag', onDragEnd: 'ondragend', ondragend: 'ondragend', onDragEnter: 'ondragenter', ondragenter: 'ondragenter', onDragExit: 'ondragexit', ondragexit: 'ondragexit', onDragLeave: 'ondragleave', ondragleave: 'ondragleave', onDragOver: 'ondragover', ondragover: 'ondragover', onDragStart: 'ondragstart', ondragstart: 'ondragstart', onDrop: 'ondrop', ondrop: 'ondrop', onMouseDown: 'onmousedown', onmousedown: 'onmousedown', onMouseEnter: 'onmouseenter', onmouseenter: 'onmouseenter', onMouseLeave: 'onmouseleave', onmouseleave: 'onmouseleave', onMouseMove: 'onmousemove', onmousemove: 'onmousemove', onMouseOut: 'onmouseout', onmouseout: 'onmouseout', onMouseOver: 'onmouseover', onmouseover: 'onmouseover', onMouseUp: 'onmouseup', onmouseup: 'onmouseup', onSelect: 'onselect', onselect: 'onselect', onTouchCancel: 'ontouchcancel', ontouchcancel: 'ontouchcancel', onTouchEnd: 'ontouchend', ontouchend: 'ontouchend', onTouchMove: 'ontouchmove', ontouchmove: 'ontouchmove', onTouchStart: 'ontouchstart', ontouchstart: 'ontouchstart', onPointerDown: 'onpointerdown', onpointerdown: 'onpointerdown', onPointerMove: 'onpointermove', onpointermove: 'onpointermove', onPointerUp: 'onpointerup', onpointerup: 'onpointerup', onPointerCancel: 'onpointercancel', onpointercancel: 'onpointercancel', onPointerEnter: 'onpointerenter', onpointerenter: 'onpointerenter', onPointerLeave: 'onpointerleave', onpointerleave: 'onpointerleave', onPointerOver: 'onpointerover', onpointerover: 'onpointerover', onPointerOut: 'onpointerout', onpointerout: 'onpointerout', onGotPointerCapture: 'ongotpointercapture', ongotpointercapture: 'ongotpointercapture', onLostPointerCapture: 'onlostpointercapture', onlostpointercapture: 'onlostpointercapture', onScroll: 'onscroll', onscroll: 'onscroll', onWheel: 'onwheel', onwheel: 'onwheel', onAnimationStart: 'onanimationstart', onanimationstart: 'onanimationstart', onAnimationEnd: 'onanimationend', onanimationend: 'onanimationend', onAnimationIteration: 'onanimationiteration', onanimationiteration: 'onanimationiteration', onTransitionEnd: 'ontransitionend', ontransitionend: 'ontransitionend', onAbortCapture: 'onabortcapture', onCanPlayCapture: 'oncanplaycapture', onCanPlayThroughCapture: 'oncanplaythroughcapture', onDurationChangeCapture: 'ondurationchangecapture', onEmptiedCapture: 'onemptiedcapture', onEncryptedCapture: 'onencryptedcapture', onEndedCapture: 'onendedcapture', onLoadedDataCapture: 'onloadeddatacapture', onLoadedMetadataCapture: 'onloadedmetadatacapture', onLoadStartCapture: 'onloadstartcapture', onPauseCapture: 'onpausecapture', onPlayCapture: 'onplaycapture', onPlayingCapture: 'onplayingcapture', onProgressCapture: 'onprogresscapture', onRateChangeCapture: 'onratechangecapture', onSeekedCapture: 'onseekedcapture', onSeekingCapture: 'onseekingcapture', onStalledCapture: 'onstalledcapture', onSuspendCapture: 'onsuspendcapture', onTimeUpdateCapture: 'ontimeupdatecapture', onVolumeChangeCapture: 'onvolumechangecapture', onWaitingCapture: 'onwaitingcapture', onAuxClickCapture: 'onauxclickcapture', onClickCapture: 'onclickcapture', onContextMenuCapture: 'oncontextmenucapture', onDoubleClickCapture: 'ondoubleclickcapture', onDragCapture: 'ondragcapture', onDragEndCapture: 'ondragendcapture', onDragEnterCapture: 'ondragentercapture', onDragExitCapture: 'ondragexitcapture', onDragLeaveCapture: 'ondragleavecapture', onDragOverCapture: 'ondragovercapture', onDragStartCapture: 'ondragstartcapture', onDropCapture: 'ondropcapture', onMouseDownCapture: 'onmousedowncapture', onMouseEnterCapture: 'onmouseentercapture', onMouseLeaveCapture: 'onmouseleavecapture', onMouseMoveCapture: 'onmousemovecapture', onMouseOutCapture: 'onmouseoutcapture', onMouseOverCapture: 'onmouseovercapture', onMouseUpCapture: 'onmouseupcapture', onSelectCapture: 'onselectcapture', onTouchCancelCapture: 'ontouchcancelcapture', onTouchEndCapture: 'ontouchendcapture', onTouchMoveCapture: 'ontouchmovecapture', onTouchStartCapture: 'ontouchstartcapture', onPointerDownCapture: 'onpointerdowncapture', onPointerMoveCapture: 'onpointermovecapture', onPointerUpCapture: 'onpointerupcapture', onPointerCancelCapture: 'onpointercancelcapture', onPointerEnterCapture: 'onpointerentercapture', onPointerLeaveCapture: 'onpointerleavecapture', onPointerOverCapture: 'onpointerovercapture', onPointerOutCapture: 'onpointeroutcapture', onGotPointerCaptureCapture: 'ongotpointercapturecapture', onLostPointerCaptureCapture: 'onlostpointercapturecapture', onScrollCapture: 'onscrollcapture', onWheelCapture: 'onwheelcapture', onAnimationStartCapture: 'onanimationstartcapture', onAnimationEndCapture: 'onanimationendcapture', onAnimationIterationCapture: 'onanimationiterationcapture', onTransitionEndCapture: 'ontransitionendcapture', // SVG attributes accentHeight: 'accent-height', accumulate: 'accumulate', additive: 'additive', alignmentBaseline: 'alignment-baseline', allowReorder: 'allowReorder', alphabetic: 'alphabetic', amplitude: 'amplitude', arabicForm: 'arabic-form', ascent: 'ascent', attributeName: 'attributeName', attributeType: 'attributeType', autoReverse: 'autoReverse', azimuth: 'azimuth', baseFrequency: 'baseFrequency', baselineShift: 'baseline-shift', baseProfile: 'baseProfile', bbox: 'bbox', begin: 'begin', bias: 'bias', by: 'by', calcMode: 'calcMode', capHeight: 'cap-height', clip: 'clip', clipPath: 'clip-path', clipRule: 'clip-rule', colorInterpolation: 'color-interpolation', colorInterpolationFilters: 'color-interpolation-filters', colorProfile: 'color-profile', colorRendering: 'color-rendering', contentScriptType: 'contentScriptType', contentStyleType: 'contentStyleType', cursor: 'cursor', cx: 'cx', cy: 'cy', d: 'd', decelerate: 'decelerate', descent: 'descent', diffuseConstant: 'diffuseConstant', direction: 'direction', display: 'display', divisor: 'divisor', dominantBaseline: 'dominant-baseline', dur: 'dur', dx: 'dx', dy: 'dy', edgeMode: 'edgeMode', elevation: 'elevation', enableBackground: 'enable-background', end: 'end', exponent: 'exponent', externalResourcesRequired: 'externalResourcesRequired', fill: 'fill', fillOpacity: 'fill-opacity', fillRule: 'fill-rule', filter: 'filter', filterRes: 'filterRes', filterUnits: 'filterUnits', floodColor: 'flood-color', floodOpacity: 'flood-opacity', focusable: 'focusable', fontFamily: 'font-family', fontSize: 'font-size', fontSizeAdjust: 'font-size-adjust', fontStretch: 'font-stretch', fontStyle: 'font-style', fontVariant: 'font-variant', fontWeight: 'font-weight', format: 'format', from: 'from', fx: 'fx', fy: 'fy', g1: 'g1', g2: 'g2', glyphName: 'glyph-name', glyphOrientationHorizontal: 'glyph-orientation-horizontal', glyphOrientationVertical: 'glyph-orientation-vertical', glyphRef: 'glyphRef', gradientTransform: 'gradientTransform', gradientUnits: 'gradientUnits', hanging: 'hanging', horizAdvX: 'horiz-adv-x', horizOriginX: 'horiz-origin-x', ideographic: 'ideographic', imageRendering: 'image-rendering', in2: 'in2', in: 'in', intercept: 'intercept', k1: 'k1', k2: 'k2', k3: 'k3', k4: 'k4', k: 'k', kernelMatrix: 'kernelMatrix', kernelUnitLength: 'kernelUnitLength', kerning: 'kerning', keyPoints: 'keyPoints', keySplines: 'keySplines', keyTimes: 'keyTimes', lengthAdjust: 'lengthAdjust', letterSpacing: 'letter-spacing', lightingColor: 'lighting-color', limitingConeAngle: 'limitingConeAngle', local: 'local', markerEnd: 'marker-end', markerHeight: 'markerHeight', markerMid: 'marker-mid', markerStart: 'marker-start', markerUnits: 'markerUnits', markerWidth: 'markerWidth', mask: 'mask', maskContentUnits: 'maskContentUnits', maskUnits: 'maskUnits', mathematical: 'mathematical', mode: 'mode', numOctaves: 'numOctaves', offset: 'offset', opacity: 'opacity', operator: 'operator', order: 'order', orient: 'orient', orientation: 'orientation', origin: 'origin', overflow: 'overflow', overlinePosition: 'overline-position', overlineThickness: 'overline-thickness', paintOrder: 'paint-order', panose1: 'panose-1', pathLength: 'pathLength', patternContentUnits: 'patternContentUnits', patternTransform: 'patternTransform', patternUnits: 'patternUnits', pointerEvents: 'pointer-events', points: 'points', pointsAtX: 'pointsAtX', pointsAtY: 'pointsAtY', pointsAtZ: 'pointsAtZ', preserveAlpha: 'preserveAlpha', preserveAspectRatio: 'preserveAspectRatio', primitiveUnits: 'primitiveUnits', r: 'r', radius: 'radius', refX: 'refX', refY: 'refY', renderingIntent: 'rendering-intent', repeatCount: 'repeatCount', repeatDur: 'repeatDur', requiredExtensions: 'requiredExtensions', requiredFeatures: 'requiredFeatures', restart: 'restart', result: 'result', rotate: 'rotate', rx: 'rx', ry: 'ry', scale: 'scale', seed: 'seed', shapeRendering: 'shape-rendering', slope: 'slope', spacing: 'spacing', specularConstant: 'specularConstant', specularExponent: 'specularExponent', speed: 'speed', spreadMethod: 'spreadMethod', startOffset: 'startOffset', stdDeviation: 'stdDeviation', stemh: 'stemh', stemv: 'stemv', stitchTiles: 'stitchTiles', stopColor: 'stop-color', stopOpacity: 'stop-opacity', strikethroughPosition: 'strikethrough-position', strikethroughThickness: 'strikethrough-thickness', string: 'string', stroke: 'stroke', strokeDasharray: 'stroke-dasharray', strokeDashoffset: 'stroke-dashoffset', strokeLinecap: 'stroke-linecap', strokeLinejoin: 'stroke-linejoin', strokeMiterlimit: 'stroke-miterlimit', strokeOpacity: 'stroke-opacity', strokeWidth: 'stroke-width', surfaceScale: 'surfaceScale', systemLanguage: 'systemLanguage', tableValues: 'tableValues', targetX: 'targetX', targetY: 'targetY', textAnchor: 'text-anchor', textDecoration: 'text-decoration', textRendering: 'text-rendering', textLength: 'textLength', to: 'to', transform: 'transform', u1: 'u1', u2: 'u2', underlinePosition: 'underline-position', underlineThickness: 'underline-thickness', unicode: 'unicode', unicodeBidi: 'unicode-bidi', unicodeRange: 'unicode-range', unitsPerEm: 'units-per-em', vAlphabetic: 'v-alphabetic', values: 'values', vectorEffect: 'vector-effect', version: 'version', vertAdvY: 'vert-adv-y', vertOriginX: 'vert-origin-x', vertOriginY: 'vert-origin-y', vHanging: 'v-hanging', vIdeographic: 'v-ideographic', viewBox: 'viewBox', viewTarget: 'viewTarget', visibility: 'visibility', vMathematical: 'v-mathematical', widths: 'widths', wordSpacing: 'word-spacing', writingMode: 'writing-mode', x: 'x', xHeight: 'x-height', x1: 'x1', x2: 'x2', xChannelSelector: 'xChannelSelector', xlinkActuate: 'xlink:actuate', xlinkArcrole: 'xlink:arcrole', xlinkHref: 'xlink:href', xlinkRole: 'xlink:role', xlinkShow: 'xlink:show', xlinkTitle: 'xlink:title', xlinkType: 'xlink:type', xmlBase: 'xml:base', xmlLang: 'xml:lang', xmlns: 'xmlns', xmlnsXlink: 'xmlns:xlink', xmlSpace: 'xml:space', y: 'y', y1: 'y1', y2: 'y2', yChannelSelector: 'yChannelSelector', z: 'z', zoomAndPan: 'zoomAndPan', }; /** * A list of attributes that have corresponding properties and should not use `setAttribute`. * Instead, these attributes should directly manipulate the corresponding property on the element. */ const attributesWithDirectProperties = [ 'value', 'checked', 'selected', 'disabled', ]; /** * Determines whether to use `setAttribute` for a given attribute key. * * @param {string} key - The attribute key to check. * @returns {boolean} - Returns true if `setAttribute` should be used, false if the direct property should be accessed. */ const shouldUseSetAttribute = (key) => { if (!key) return false; if (key.includes('aria-') || key.includes(':') || key.includes('data-')) { return true; } const attribute = allAttribute[key]; // Handle cases where we should use direct property access if (!attribute || attribute instanceof Object || attribute.startsWith('on') || attributesWithDirectProperties.includes(key)) { return false; } return true; }; /** * Returns the correct attribute name for a given key. * * @param {string} key - The key to be transformed into an attribute name. * @returns {string} - The corresponding attribute name. */ const attributeName = (key) => { const attribute = allAttribute[key]; if (attribute === undefined) { return key; } if (attribute instanceof Object) { return attribute?.name || key; } if (attribute === null || attribute.startsWith('aria-')) { return key; } else if (attribute.startsWith('on')) { return key.toLowerCase(); } else { return attribute; } }; class Component { } exports.ChildrenPropsUpdateType = void 0; (function (ChildrenPropsUpdateType) { ChildrenPropsUpdateType[ChildrenPropsUpdateType["NON_CHILDREN"] = 0] = "NON_CHILDREN"; ChildrenPropsUpdateType[ChildrenPropsUpdateType["CHILDREN"] = 1] = "CHILDREN"; })(exports.ChildrenPropsUpdateType || (exports.ChildrenPropsUpdateType = {})); exports.PatchTypeAndOrder = void 0; (function (PatchTypeAndOrder) { PatchTypeAndOrder[PatchTypeAndOrder["NONE"] = 0] = "NONE"; PatchTypeAndOrder[PatchTypeAndOrder["REMOVE"] = 1] = "REMOVE"; PatchTypeAndOrder[PatchTypeAndOrder["TEXT"] = 2] = "TEXT"; PatchTypeAndOrder[PatchTypeAndOrder["CREATE"] = 3] = "CREATE"; PatchTypeAndOrder[PatchTypeAndOrder["REPLACE"] = 4] = "REPLACE"; PatchTypeAndOrder[PatchTypeAndOrder["UPDATE"] = 5] = "UPDATE"; })(exports.PatchTypeAndOrder || (exports.PatchTypeAndOrder = {})); exports.EffectType = void 0; (function (EffectType) { EffectType["BEFORE"] = "BEFORE"; EffectType["AFTER"] = "AFTER"; })(exports.EffectType || (exports.EffectType = {})); const ERROR_EVENTNAME = "reblend-render-error"; const REBLEND_PRIMITIVE_ELEMENT_NAME = "ReblendPrimitive"; /* eslint-disable @typescript-eslint/no-explicit-any */ const Symbols = { ReblendNode: Symbol('Reblend.Node'), ReblendVNode: Symbol('Reblend.VNode'), ReblendLazyNode: Symbol('Reblend.Lazy.Node'), ReblendLazyVNode: Symbol('Reblend.Lazy.VNode'), ReactToReblendNode: Symbol('React.Reblend.Node'), ReactToReblendVNode: Symbol('React.Reblend.VNode'), ReblendNodeStandard: Symbol('Reblend.Node.Standard'), ReblendVNodeStandard: Symbol('Reblend.VNode.Standard') }; var ReblendNodeTypeDict; (function (ReblendNodeTypeDict) { ReblendNodeTypeDict["ReblendNode"] = "ReblendNode"; ReblendNodeTypeDict["ReblendVNode"] = "ReblendVNode"; ReblendNodeTypeDict["ReblendLazyNode"] = "ReblendLazyNode"; ReblendNodeTypeDict["ReblendLazyVNode"] = "ReblendLazyVNode"; ReblendNodeTypeDict["ReactToReblendNode"] = "ReactToReblendNode"; ReblendNodeTypeDict["ReactToReblendVNode"] = "ReactToReblendVNode"; ReblendNodeTypeDict["ReblendNodeStandard"] = "ReblendNodeStandard"; ReblendNodeTypeDict["ReblendVNodeStandard"] = "ReblendVNodeStandard"; })(ReblendNodeTypeDict || (ReblendNodeTypeDict = {})); function addSymbol(type, obj) { const symb = Symbols[type]; if (!obj || !symb) { return false; } obj[symb] = true; return obj[symb]; } /** * Checks if the provided node is a rendered Reblend node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a rendered Reblend node, otherwise `false`. */ function isReblendRenderedNode(node) { return node && typeof node === 'object' && node[Symbols.ReblendNode]; } /** * Checks if the provided node is a virtual Reblend node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a virtual Reblend node, otherwise `false`. */ function isReblendVirtualNode(node) { return node && typeof node === 'object' && node[Symbols.ReblendVNode]; } /** * Checks if the provided node is a rendered Reblend lazy node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a rendered Reblend lazy node, otherwise `false`. */ function isReblendRenderedLazyNode(node) { return node && typeof node === 'object' && node[Symbols.ReblendLazyNode]; } /** * Checks if the provided node is a virtual Reblend lazy node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a virtual Reblend lazy node, otherwise `false`. */ function isReblendLazyVirtualNode(node) { return node && typeof node === 'object' && node[Symbols.ReblendLazyVNode]; } /** * Checks if the provided node is a standard rendered Reblend node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a standard rendered Reblend node, otherwise `false`. */ function isReblendRenderedNodeStandard(node) { return node && typeof node === 'object' && node[Symbols.ReblendNodeStandard]; } /** * Checks if the provided node is a standard virtual Reblend node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a standard virtual Reblend node, otherwise `false`. */ function isReblendVirtualNodeStandard(node) { return node && typeof node === 'object' && node[Symbols.ReblendVNodeStandard]; } /** * Checks if the provided node is a React to Reblend rendered node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a React to Reblend rendered node, otherwise `false`. */ function isReactToReblendRenderedNode(node) { return node && typeof node === 'object' && node[Symbols.ReactToReblendNode]; } /** * Checks if the provided node is a React to Reblend virtual node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a React to Reblend virtual node, otherwise `false`. */ function isReactToReblendVirtualNode(node) { return node && typeof node === 'object' && node[Symbols.ReactToReblendVNode]; } /** * Checks if the provided node is a standard virtual node. * * @param {any} node - The node to check. * @returns {boolean} `true` if the node is a standard virtual node, otherwise `false`. */ function isStandardVirtualNode(node) { return node && typeof node === 'object' && node[Symbols.ReblendVNodeStandard]; } /** * Checks if the provided element is a Reblend primitive element. * * @param {any} element - The element to check. * @returns {boolean} `true` if the element is a Reblend primitive element, otherwise `false`. */ function isReblendPrimitiveElement(element) { return !isPrimitive(element) && element.displayName === REBLEND_PRIMITIVE_ELEMENT_NAME; } /** * Checks if the provided data is a primitive type. * Primitive types include string, number, boolean, bigint, null, undefined, and symbol. * * @param {any} data - The data to check. * @returns {boolean} `true` if the data is a primitive, otherwise `false`. */ function isPrimitive(data) { const primitves = ['string', 'number', 'boolean', 'bigint', 'null', 'undefined', 'symbol']; const dataType = typeof data; return primitves.some(primitve => primitve === (data === null ? 'null' : dataType)); } /** * Checks if the provided display name represents a React node. * * @param {ReblendTyping.IAny} displayName - The display name to check. * @returns {boolean} `true` if the display name represents a React node, otherwise `false`. */ function isReactNode(displayName) { return displayName && (typeof displayName === 'object' || typeof displayName === 'function') && !('construct' in displayName && 'mountOn' in displayName && 'createInnerHtmlElements' in displayName.prototype) && ('$$typeof' in displayName || displayName.prototype && displayName.prototype.isReactComponent); } /** * Checks if the provided display name represents a Lazy node. * * @param {ReblendTyping.IAny} displayName - The display name to check. * @returns {boolean} `true` if the display name represents a Promise Instance, otherwise `false`. */ function isLazyNode(displayName) { return displayName && typeof displayName === 'object' && displayName instanceof Promise; } /** * Checks if a node is a standard HTML element or a Reblend primitive element. * * @param {ReblendTyping.Component | HTMLElement} node - The node to check. * @returns {boolean} - True if the node is standard or a Reblend primitive element, false otherwise. */ function isStandard(node) { if (!node) { return false; } return isReblendRenderedNodeStandard(node) || isReblendPrimitiveElement(node); } /** * Determines if a given node is a text node. * * @param {Node} node - The node to check. * @returns {boolean} - True if the node is a text node, otherwise false. */ function isTextNode(node) { return node?.nodeType === Node.TEXT_NODE; } /** * Checks whether the given data is empty (undefined or null). * * @param {*} data - The data to check. * @returns {boolean} - True if the data is empty, otherwise false. */ function isEmpty(data) { return data === undefined || data === null; } /** * Extends the prototype of the target object with the provided prototype, skipping constructors and existing functions. * * @param {any} target - The target object to extend. * @param {any} prototype - The prototype object to copy properties and methods from. */ function extendPrototype(target, prototype) { // If there's a prototype chain, continue copying from the prototype chain const proto = Object.getPrototypeOf(prototype); if (proto && proto !== Object.prototype) { extendPrototype(target, proto); } const descriptors = Object.getOwnPropertyDescriptors(prototype); for (const key in descriptors) { if (Object.prototype.hasOwnProperty.call(descriptors, key)) { // Skip the constructor if (key === 'constructor') continue; const descriptor = descriptors[key]; // Avoid replacing existing functions on the target //if (!(key in target) || (typeof descriptor.value !== 'function' && !(key in target))) { Object.defineProperty(target, key, descriptor); //} } } } /* eslint-disable @typescript-eslint/no-explicit-any */ /** * Deeply flattens an array or set of elements. * * @template T * @param {T[] | Set<T>} data - The data to flatten. * @returns {T[]} A flattened array of elements. */ function deepFlat(data) { if (!data) { return []; } if (!(data instanceof Set) && !Array.isArray(data)) { data = [data]; } const ts = []; for (const t of data) { if (t instanceof Set || Array.isArray(t)) { ts.push(...deepFlat(t)); } else { ts.push(t); } } return ts; } /** * Flattens a nested array or set of virtual nodes (VNode) and adds the result to the `containerArr`. * * @template T * @param {(T | T[])[] | Set<T | T[]>} arr - The array or set of VNode children to flatten. * @param {T[]} [containerArr=[]] - The container array to store flattened nodes. * @returns {T[]} The flattened array of VNode children. */ function flattenVNodeChildren(arr, containerArr = []) { if (!arr) { return []; } if (!Array.isArray(arr)) { arr = [arr]; } if ((arr.length || arr.size) < 1) { return []; } for (const item of arr) { if (item instanceof Set || Array.isArray(item)) { flattenVNodeChildren(item, containerArr); } else { containerArr.push(item); } } return containerArr; } /* eslint-disable @typescript-eslint/no-explicit-any */ const componentConfig = { ReblendPlaceholder: true, defaultReblendPlaceholderStyle: true }; /** * Creates an HTML, SVG, MathML, or XML element based on the provided tag name. * * @param {string} tag - The tag name of the element to create. * @returns {HTMLElement | SVGElement | Element} The created element. */ function createElementWithNamespace(tag) { const svgTags = ['svg', 'path', 'circle', 'rect', 'line', 'text', 'use', 'g', 'defs', 'clipPath', 'polygon', 'polyline', 'image', 'symbol']; const mathMLTags = ['math', 'mi', 'mn', 'mo', 'ms', 'mtext']; const xmlTags = ['xml', 'xmlns']; if (svgTags.includes(tag)) { return document.createElementNS('http://www.w3.org/2000/svg', tag); } else if (mathMLTags.includes(tag)) { return document.createElementNS('http://www.w3.org/1998/Math/MathML', tag); } else if (xmlTags.includes(tag)) { return document.createElementNS('http://www.w3.org/XML/1998/namespace', tag); } else { return document.createElement(tag); // Default to HTML namespace } } /** * Sets attributes on the given element, handling namespaces for XML, SVG, MathML, and XLink attributes. * * @param {HTMLElement | SVGElement} element - The element on which to set attributes. * @param {Record<string, string>} attributes - A record of attribute names and values to set. */ function setAttributesWithNamespace(element, attributes) { const svgAttributes = [ /* SVG attributes */ ]; const mathMLAttributes = ['displaystyle', 'scriptlevel', 'mathvariant', 'mathsize', 'lspace', 'rspace']; for (const [key, value] of Object.entries(attributes)) { if (key.startsWith('xmlns:')) { // Handle XML namespace attributes element.setAttributeNS('http://www.w3.org/2000/xmlns/', key, value); } else if (key === 'xmlns') { // Handle default XML namespace attribute element.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', value); } else if (element instanceof SVGElement && svgAttributes.includes(key)) { // Handle SVG attributes element.setAttributeNS('http://www.w3.org/2000/svg', key, value); } else if (element instanceof Element && mathMLAttributes.includes(key)) { // Handle MathML attributes element.setAttributeNS('http://www.w3.org/1998/Math/MathML', key, value); } else if (key.startsWith('xlink:')) { // Handle XLink attributes element.setAttributeNS('http://www.w3.org/1999/xlink', key, value); } else { // Handle standard HTML attributes element.setAttribute(key, value); } } } /** * Creates child nodes from the given ReblendTyping.VNode children and appends them to the container array. * Supports nested arrays, Sets, and various node types such as Reblend, DOM Nodes, React Nodes, and primitive values. * * @param {ReblendTyping.VNodeChildren} children - The children to process. * @param {(ReblendTyping.Component<P, S> | HTMLElement)[]} [containerArr=[]] - The array to store the created child nodes. * @returns {(ReblendTyping.Component<P, S> | HTMLElement)[]} The array containing the created child nodes. */ async function createChildren(children, containerArr = []) { if (!children) { return containerArr; } if (!(children instanceof Set) && !Array.isArray(children)) { children = [children]; } for (const child of children instanceof Set ? Array.from(children) : children) { if (Array.isArray(child)) { await createChildren(child, containerArr); } else if (!isPrimitive(child) && 'construct' in child && 'mountOn' in child && 'createInnerHtmlElements' in child.prototype) { await createChildren(BaseComponent.construct(child, {}), containerArr); } else if (isCallable(child) || child instanceof Reblend || child instanceof Node || isPrimitive(child) || isReactToReblendVirtualNode(child) || isLazyNode(child) || isReblendLazyVirtualNode(child) || isReblendVirtualNode(child) || isStandardVirtualNode(child)) { const domChild = deepFlat(await createElement(child)); if (domChild) { containerArr.push(...domChild); } } else { throw new TypeError('Invalid child node in children'); } } return containerArr; } /** * Creates an element based on the provided virtual node (ReblendTyping.VNode) or primitive value. * The created element is returned as a `BaseComponent`. * * @param {ReblendTyping.VNode | ReblendTyping.VNode[] | ReblendTyping.ReactNode | ReblendTyping.Primitive} ui - The virtual node or primitive to create an element from. * @returns {ReblendTyping.Component<P, S>[]} The created `BaseComponent` instances. */ async function createElement(ui) { if (ui instanceof Reblend || ui instanceof Node) { if (!ui.displayName) { ui.displayName = capitalize(ui.tagName); extendPrototype(ui, Reblend.prototype); addSymbol(ReblendNodeTypeDict.ReblendNodeStandard, ui); ui._constructor(); } return [ui]; } if (Array.isArray(ui)) { return await createChildren(ui); } if (isPrimitive(ui)) { return [newReblendPrimitive()?.setData(ui)]; } if (isCallable(ui)) { ui = ui({}); } if (isPrimitive(ui)) { return [newReblendPrimitive()?.setData(ui)]; } if (ui instanceof Promise) { return await createChildren(BaseComponent.construct(ui, {})); } const tempComponent = ui; // Handle Reblend class component if ('construct' in tempComponent && 'mountOn' in tempComponent && 'createInnerHtmlElements' in tempComponent.prototype) { return await createChildren(BaseComponent.construct(tempComponent, {})); } let { displayName } = ui; const reactComponent = ui && ui['props'] && ui.props.reactcomponent; if (!reactComponent && isCallable(displayName)) { displayName = await displayName(ui.props); } if (typeof displayName !== 'string' && isPrimitive(displayName)) { return [newReblendPrimitive()?.setData(displayName)]; } const node = displayName; if (displayName instanceof Reblend || displayName instanceof Node) { if (!node.displayName) { node.displayName = capitalize(node.tagName); extendPrototype(node, Reblend.prototype); addSymbol(ReblendNodeTypeDict.ReblendNodeStandard, node); node._constructor(); } if (ui?.props) { if (!node.props) { node.props = {}; } node.props = { ...node.props, ...ui.props }; } return [node]; } if (isReblendVirtualNodeStandard(node) || isReblendVirtualNode(node) || isReactToReblendVirtualNode(node) || isReactToReblendVirtualNode(node) || isReblendLazyVirtualNode(node)) { if (ui?.props) { if (!node.props) { node.props = {}; } node.props = { ...node.props, ...ui.props }; } return await createElement(node); } let clazz = displayName; const isTagStandard = typeof displayName === 'string'; const _isReactNode = reactComponent || isReactNode(displayName); const _isLazyNode = isLazyNode(ui) || isLazyNode(displayName); let tagName; if (_isLazyNode) { tagName = ReblendNodeTypeDict.ReblendLazyNode; } else if (isTagStandard) { tagName = displayName; } else if (isReactNode(clazz)) { tagName = clazz.displayName || clazz.name || 'ReactComponent'; } else if (clazz?.ELEMENT_NAME === 'Fragment') { tagName = clazz.name; } else { tagName = clazz?.ELEMENT_NAME || 'Anonymous'; } if (!isTagStandard && !_isLazyNode && !_isReactNode) { if (displayName?.ELEMENT_NAME === 'Reblend' && displayName?.name === 'Reblend') { return [...(displayName?.children || [])]; } clazz.ELEMENT_NAME = tagName; } if (_isReactNode) { clazz = ReblendReactClass; clazz.ELEMENT_NAME = capitalize(`${displayName.displayName}`); } const element = createElementWithNamespace(isTagStandard ? displayName : 'div'); let symbolType; if (_isLazyNode) { symbolType = ReblendNodeTypeDict.ReblendLazyNode; } else if (_isReactNode) { symbolType = ReblendNodeTypeDict.ReactToReblendNode; } else if (isTagStandard) { symbolType = ReblendNodeTypeDict.ReblendNodeStandard; } else { symbolType = ReblendNodeTypeDict.ReblendNode; } addSymbol(symbolType, element); element.displayName = tagName; if (isTagStandard || _isReactNode) { extendPrototype(element, Reblend.prototype); } else { const config = _isLazyNode ? ui?.config : clazz.config; if (_isLazyNode) { extendPrototype(element, Reblend.prototype); } else { extendPrototype(element, clazz.prototype); } if (config) { Object.entries(config).forEach(([key, value]) => { if (!componentConfig[key]) { console.warn(`Unsupported key \`${key}\` found in component configu