@meonode/ui 0.4.9 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,92 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.4.11
6
+
7
+ ### Fix
8
+ - **core**: enhance MeoNodeUnmounter cleanup logic and support additional props cloning ([`02c17f7`](https://github.com/l7aromeo/meonode-ui/commit/02c17f7))
9
+ - Refactor MeoNodeUnmounter to use useEffectEvent for stable cleanup on unmount
10
+ - Cleanup removes node from BaseNode.elementCache, untracks mount via MountTrackerUtil, unregisters from BaseNode.cacheCleanupRegistry, and clears lastSignature to prevent memory leaks
11
+ - Support cloning and forwarding additional props to valid React children elements
12
+
13
+ ### Refactor
14
+ - **node.util**: enhance documentation for utility methods and improve clarity ([`ee42c24`](https://github.com/l7aromeo/meonode-ui/commit/ee42c24))
15
+ - **theme**: reorder ThemeResolverCache methods for clarity ([`cb842c8`](https://github.com/l7aromeo/meonode-ui/commit/cb842c8))
16
+ - Moved `_generateCacheKey` and `_evict` methods below the main logic in `ThemeResolverCache` for better readability and organization
17
+ - Removed duplicate declaration of `_instance` property
18
+ - Kept functionality unchanged, improving code structure and maintainability
19
+
20
+ ### Test
21
+ - **perf**: add memory leak detection test for navigation cycles and improve formatMemory function ([`ba139fc`](https://github.com/l7aromeo/meonode-ui/commit/ba139fc))
22
+ - Added a new performance test to detect memory leaks during repeated navigation cycles between pages
23
+ - The test measures heap memory usage before, during, and after navigation, ensuring memory growth stays within acceptable limits
24
+ - Enhanced the formatMemory utility to correctly handle negative byte values and added JSDoc comments for clarity
25
+ - Removed an obsolete shallowly equal props performance test to streamline the test suite
26
+ - **unmounter**: add regression test for MeoNodeUnmounter to forward implicit props in MUI RadioGroup integration ([`2ecaabd`](https://github.com/l7aromeo/meonode-ui/commit/2ecaabd))
27
+ - Added a test to ensure MeoNodeUnmounter correctly forwards props injected via React.cloneElement, addressing issues with libraries like MUI where RadioGroup injects 'checked' and 'onChange' into Radio components
28
+ - This prevents swallowing of props and verifies proper behavior of controlled radio inputs
29
+ - Also updated an existing cache size assertion to allow equality, reflecting improved mount tracking
30
+ - **perf**: update react-createelement comparison tests with 5000 nested nodes and fix typings ([`b345ec0`](https://github.com/l7aromeo/meonode-ui/commit/b345ec0))
31
+ - Changed rerender to use React.cloneElement<any> for proper typing
32
+ - Updated NUM_NODES constant to 5000 for nested structure tests
33
+ - Removed redundant comments about node count reduction to prevent stack overflow
34
+
35
+ ### Chore
36
+ - **deps**: upgrade devDependencies and update test scripts ([`2ea128e`](https://github.com/l7aromeo/meonode-ui/commit/2ea128e))
37
+ - add new devDependencies: @emotion/is-prop-valid@1.4.0, @emotion/styled@11.14.1, @mui/material@7.3.5, and related packages
38
+ - update yarn to version 4.11.0
39
+ - update test scripts to increase max-old-space-size to 8192 and include react-createelement-comparison.test.ts in test and perf runs
40
+ - update various package resolutions in yarn.lock to align with new versions and dependencies
41
+ - **babel**: add "builtIns": false to minify plugin configuration ([`e16cdfb`](https://github.com/l7aromeo/meonode-ui/commit/e16cdfb))
42
+ - **yarn**: update yarnPath to version 4.11.0 ([`ecb6c68`](https://github.com/l7aromeo/meonode-ui/commit/ecb6c68))
43
+
44
+ ### Docs
45
+ - **CONTRIBUTING**: improve formatting and readability of contribution guidelines ([`a7462ed`](https://github.com/l7aromeo/meonode-ui/commit/a7462ed))
46
+
47
+ ## 0.4.10
48
+
49
+ ### Fix
50
+ - **unmounter**: prevent redundant FinalizationRegistry callbacks ([`59f5adf`](https://github.com/l7aromeo/meonode-ui/commit/59f5adf2f553aa49a88d1b44366b004d829ca107))
51
+ - Explicitly unregister node from cacheCleanupRegistry on unmount
52
+ - Prevents double cleanup when node is both unmounted and GC'd
53
+ - Improves cleanup efficiency and reduces unnecessary registry callbacks
54
+
55
+ ### Perf
56
+ - **util**: optimize prop processing and child handling ([`be26488`](https://github.com/l7aromeo/meonode-ui/commit/be26488e304629dd13851dfcaa7fedf43ad8b5c3))
57
+ - Conditional sort: only sort keys if length > 1 (eliminates unnecessary sorts)
58
+ - Replace for...in with Object.keys() iteration for better performance and safety
59
+ - Add fast path for single child processing (non-array or 1-element array)
60
+ - Avoid unnecessary array operations for common single-child case
61
+ - Performance impact:
62
+ - Reduced CPU overhead for small prop objects
63
+ - Faster iteration with Object.keys() vs for...in
64
+ - Eliminates array map() call for single child components
65
+
66
+ - **core**: add exception safety and optimize render method ([`5aad000`](https://github.com/l7aromeo/meonode-ui/commit/5aad000335ff29f078a9d40192d5a70fe9b61d12))
67
+ - Wrap render logic in try-finally to ensure renderContext is always released
68
+ - Null out workStack slots before releasing to help GC
69
+ - Pre-allocate finalChildren array to avoid resizing during iteration
70
+ - Replace non-null assertion with explicit error handling for better debugging
71
+ - Add object pooling for workStack and renderedElements (reduces GC pressure)
72
+ - Pool capped at 50 contexts with 2048-item limit to prevent memory issues
73
+ - Exception safety ensures cleanup even if rendering throws
74
+
75
+ ### Test
76
+ - **perf**: add React comparison tests with memory tracking ([`bc66d54`](https://github.com/l7aromeo/meonode-ui/commit/bc66d540c4ffa4ad083322dbdbc201f652ea5314))
77
+ - Add comprehensive performance comparison between React.createElement and MeoNode
78
+ - Test both flat (10k nodes) and nested (5k nodes) structures
79
+ - Include memory usage measurements (initial + after 100 updates)
80
+ - Reduce nested nodes from 10k to 5k to prevent stack overflow with StyledRenderer
81
+ - Add table output with time and memory columns for clear comparison
82
+ - Add GC availability warning for accurate measurements
83
+ - Provides detailed performance and memory behavior insights during re-renders
84
+ - Avoids stack overflow in deeply nested test scenarios
85
+
86
+ - **performance**: enhance performance metrics report formatting and adjust thresholds ([`6f3abe4`](https://github.com/l7aromeo/meonode-ui/commit/6f3abe4442938aa6cd414341fdf2aba25a9ece58))
87
+ - Improve table formatting for performance metrics
88
+ - Adjust test thresholds based on optimization results
89
+ - Enhanced reporting for better visibility into performance characteristics
90
+
5
91
  ## [0.4.9] - 2025-11-19
6
92
 
7
93
  ### Feat
@@ -843,4 +929,4 @@ All notable changes to this project will be documented in this file.
843
929
  - This changelog covers the most recent development history available
844
930
  - The project focuses on building React UIs with type-safe fluency without JSX syntax
845
931
  - Recent development has emphasized Emotion integration, type safety improvements, and enhanced flexbox support
846
- - For a complete history, view all commits on GitHub: [View all commits](https://github.com/l7aromeo/meonode-ui/commits)
932
+ - For a complete history, view all commits on GitHub: [View all commits](https://github.com/l7aromeo/meonode-ui/commits)
@@ -1,21 +1,23 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { NodeInstance } from '../types/node.type.js';
3
3
  /**
4
- * `MeoNodeUnmounter` is a client-side React component responsible for cleaning up
5
- * resources associated with a rendered node when it unmounts.
4
+ * `MeoNodeUnmounter` is a client-side React component responsible for performing cleanup
5
+ * operations when a `MeoNode` instance is unmounted from the React tree.
6
6
  *
7
- * It uses a `useEffect` hook to register a cleanup function that runs when the component
8
- * unmounts or when its `stableKey` changes. The cleanup function checks if the node
9
- * identified by `stableKey` is currently tracked as mounted. If it is, it removes
10
- * the node from `BaseNode.elementCache` and untracks its mount status using `MountTrackerUtil`.
11
- * Additionally, it clears the `lastPropsRef` and `lastSignature` of the associated `BaseNode`
12
- * instance to prevent memory leaks from retained prop objects.
7
+ * It leverages `useEffectEvent` to create a stable cleanup function that is called
8
+ * when the component unmounts. This cleanup function performs the following actions:
9
+ * - Deletes the node from `BaseNode.elementCache` using its `stableKey`.
10
+ * - Untracks the node's mount status via `MountTrackerUtil.untrackMount`.
11
+ * - Unregisters the node from `BaseNode.cacheCleanupRegistry` to prevent redundant
12
+ * finalization callbacks.
13
+ * - Clears the `lastSignature` of the associated `BaseNode` instance to help prevent
14
+ * memory leaks from retained prop objects.
13
15
  * @param {object} props The component's props.
14
16
  * @param {NodeInstance} props.node The BaseNode instance associated with this component.
15
17
  * @param {ReactNode} [props.children] The children to be rendered by this component.
16
18
  * @returns {ReactNode} The `children` passed to the component.
17
19
  */
18
- export default function MeoNodeUnmounter({ node, children }: {
20
+ export default function MeoNodeUnmounter({ node, children, ...rest }: {
19
21
  node: NodeInstance;
20
22
  children?: ReactNode;
21
23
  }): ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"meonode-unmounter.client.d.ts","sourceRoot":"","sources":["../../src/components/meonode-unmounter.client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,OAAO,CAAA;AAGjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,CAmBpH"}
1
+ {"version":3,"file":"meonode-unmounter.client.d.ts","sourceRoot":"","sources":["../../src/components/meonode-unmounter.client.ts"],"names":[],"mappings":"AACA,OAAO,EAAgC,KAAK,SAAS,EAA6B,MAAM,OAAO,CAAA;AAG/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,CA0B7H"}
@@ -1,15 +1,17 @@
1
- "use client";import{useEffect,useEffectEvent}from"react";import{MountTrackerUtil}from"../util/mount-tracker.util.js";import{BaseNode}from"../core.node.js";/**
2
- * `MeoNodeUnmounter` is a client-side React component responsible for cleaning up
3
- * resources associated with a rendered node when it unmounts.
1
+ "use client";const _excluded=["node","children"];function _objectWithoutProperties(a,b){if(null==a)return{};var c,d,e=_objectWithoutPropertiesLoose(a,b);if(Object.getOwnPropertySymbols){var f=Object.getOwnPropertySymbols(a);for(d=0;d<f.length;d++)c=f[d],-1===b.indexOf(c)&&{}.propertyIsEnumerable.call(a,c)&&(e[c]=a[c])}return e}function _objectWithoutPropertiesLoose(a,b){if(null==a)return{};var c={};for(var d in a)if({}.hasOwnProperty.call(a,d)){if(-1!==b.indexOf(d))continue;c[d]=a[d]}return c}import{cloneElement,isValidElement,useEffect,useEffectEvent}from"react";import{MountTrackerUtil}from"../util/mount-tracker.util.js";import{BaseNode}from"../core.node.js";/**
2
+ * `MeoNodeUnmounter` is a client-side React component responsible for performing cleanup
3
+ * operations when a `MeoNode` instance is unmounted from the React tree.
4
4
  *
5
- * It uses a `useEffect` hook to register a cleanup function that runs when the component
6
- * unmounts or when its `stableKey` changes. The cleanup function checks if the node
7
- * identified by `stableKey` is currently tracked as mounted. If it is, it removes
8
- * the node from `BaseNode.elementCache` and untracks its mount status using `MountTrackerUtil`.
9
- * Additionally, it clears the `lastPropsRef` and `lastSignature` of the associated `BaseNode`
10
- * instance to prevent memory leaks from retained prop objects.
5
+ * It leverages `useEffectEvent` to create a stable cleanup function that is called
6
+ * when the component unmounts. This cleanup function performs the following actions:
7
+ * - Deletes the node from `BaseNode.elementCache` using its `stableKey`.
8
+ * - Untracks the node's mount status via `MountTrackerUtil.untrackMount`.
9
+ * - Unregisters the node from `BaseNode.cacheCleanupRegistry` to prevent redundant
10
+ * finalization callbacks.
11
+ * - Clears the `lastSignature` of the associated `BaseNode` instance to help prevent
12
+ * memory leaks from retained prop objects.
11
13
  * @param {object} props The component's props.
12
14
  * @param {NodeInstance} props.node The BaseNode instance associated with this component.
13
15
  * @param {ReactNode} [props.children] The children to be rendered by this component.
14
16
  * @returns {ReactNode} The `children` passed to the component.
15
- */export default function MeoNodeUnmounter({node:a,children:b}){const c=useEffectEvent(()=>{a.stableKey&&(BaseNode.elementCache.delete(a.stableKey),MountTrackerUtil.mountedNodes.has(a.stableKey)&&MountTrackerUtil.untrackMount(a.stableKey)),a.lastSignature=void 0});return useEffect(()=>()=>c(),[]),b}
17
+ */export default function MeoNodeUnmounter(a){let{node:b,children:c}=a,d=_objectWithoutProperties(a,_excluded);const e=useEffectEvent(()=>{b.stableKey&&(BaseNode.elementCache.delete(b.stableKey),MountTrackerUtil.mountedNodes.has(b.stableKey)&&MountTrackerUtil.untrackMount(b.stableKey),BaseNode.cacheCleanupRegistry.unregister(b)),b.lastSignature=void 0});return useEffect(()=>()=>e(),[]),isValidElement(c)?cloneElement(c,d):c}
@@ -22,6 +22,9 @@ export declare class BaseNode<E extends NodeElementType = NodeElementType> {
22
22
  static propProcessingCache: Map<string, PropProcessingCache>;
23
23
  static scheduledCleanup: boolean;
24
24
  private static _navigationStarted;
25
+ private static renderContextPool;
26
+ private static acquireRenderContext;
27
+ private static releaseRenderContext;
25
28
  constructor(element: E, rawProps?: Partial<NodeProps<E>>, deps?: DependencyList);
26
29
  /**
27
30
  * Lazily processes and retrieves the final, normalized props for the node.
@@ -1 +1 @@
1
- {"version":3,"file":"core.node.d.ts","sourceRoot":"","sources":["../src/core.node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.node.d.ts","sourceRoot":"","sources":["../src/core.node.ts"],"names":[],"mappings":"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"}
package/dist/core.node.js CHANGED
@@ -5,7 +5,7 @@ const _excluded=["ref","children"],_excluded2=["key"],_excluded3=["children","ke
5
5
  * It uses an iterative rendering approach to handle deeply nested structures without causing stack overflows.
6
6
  * @class BaseNode
7
7
  * @template E - The type of React element or component this node represents.
8
- */export class BaseNode{constructor(a,b={},c){// Element type validation is performed once at construction to prevent invalid nodes from being created.
8
+ */export class BaseNode{static acquireRenderContext(){const a=BaseNode.renderContextPool;return 0<a.length?a.pop():{workStack:Array(512),renderedElements:new Map}}static releaseRenderContext(a){50>BaseNode.renderContextPool.length&&2048>a.workStack.length&&(a.workStack.length=0,a.renderedElements.clear(),BaseNode.renderContextPool.push(a))}constructor(a,b={},c){// Element type validation is performed once at construction to prevent invalid nodes from being created.
9
9
  if(_defineProperty(this,"instanceId",Math.random().toString(36).slice(2)+Date.now().toString(36)),_defineProperty(this,"rawProps",{}),_defineProperty(this,"isBaseNode",!0),!isValidElementType(a)){const b=getComponentType(a);throw new Error(`Invalid element type: ${b} provided!`)}this.element=a,this.rawProps=b,this._deps=c;// Extract commonly handled props; the remaining `propsForSignature` are used to compute a stable hash.
10
10
  const{ref:d,children:e}=b,f=_objectWithoutProperties(b,_excluded);// Generate or get cached stable key
11
11
  this.stableKey=this._getStableKey(f),NodeUtil.isServer||BaseNode._navigationStarted||(NavigationCacheManagerUtil.getInstance().start(),BaseNode._navigationStarted=!0)}/**
@@ -55,31 +55,36 @@ this.stableKey=this._getStableKey(f),NodeUtil.isServer||BaseNode._navigationStar
55
55
  const b=NodeUtil.isServer||!this.stableKey?void 0:BaseNode.elementCache.get(this.stableKey),c=NodeUtil.shouldNodeUpdate(b?.prevDeps,this._deps,a);// Decide whether this node (and its subtree) should update given dependency arrays.
56
56
  // Fast return: if nothing should update and we have a cached element, reuse it.
57
57
  if(!c&&b?.renderedElement)return b.accessCount+=1,b.renderedElement;// When this node doesn't need update, its children are considered "blocked" and may be skipped.
58
- // Start with aggressive initial capacity to minimize reallocations
59
- let d=Array(512),e=0;// Fast capacity check with exponential growth
60
- const f=a=>{if(a>d.length){// Double capacity or use exact requirement (whichever is larger)
61
- const b=Math.max(a,d.length<<1),c=Array(b);// Manual copy is faster than Array methods for primitive/object arrays
62
- for(let a=0;a<e;a++)c[a]=d[a];d=c}};// Push initial work item
63
- d[e++]={node:this,isProcessed:!1,blocked:!c};// Map to collect rendered React elements for processed BaseNode instances.
64
- const g=new Map;// Iterative depth-first traversal with explicit begin/complete phases to avoid recursion.
65
- for(;0<e;){const a=d[e-1];if(!a){e--;continue}const{node:b,isProcessed:c,blocked:h}=a;if(!c){a.isProcessed=!0;const c=b.props.children;if(c){// Only consider BaseNode children for further traversal; primitives and React elements are terminal.
66
- const a=(Array.isArray(c)?c:[c]).filter(NodeUtil.isNodeInstance),b=e+a.length;// --- Check capacity ONCE before loop ---
67
- f(b);for(let b=a.length-1;0<=b;b--){const c=a[b],f=NodeUtil.isServer||!c.stableKey?void 0:BaseNode.elementCache.get(c.stableKey),i=NodeUtil.shouldNodeUpdate(f?.prevDeps,c._deps,h);// Respect server/client differences for child cache lookup.
58
+ const d=BaseNode.acquireRenderContext();// Acquire context from pool to reduce allocation pressure
59
+ let{workStack:e}=d;const{renderedElements:f}=d;let g=0;try{// Fast capacity check with exponential growth
60
+ const a=a=>{if(a>e.length){// Double capacity or use exact requirement (whichever is larger)
61
+ const b=Math.max(a,e.length<<1),c=Array(b);// Manual copy is faster than Array methods for primitive/object arrays
62
+ for(let a=0;a<g;a++)c[a]=e[a];e=c}};// Push initial work item
63
+ // Iterative depth-first traversal with explicit begin/complete phases to avoid recursion.
64
+ for(e[g++]={node:this,isProcessed:!1,blocked:!c};0<g;){const b=e[g-1];if(!b){g--;continue}const{node:c,isProcessed:d,blocked:h}=b;if(!d){b.isProcessed=!0;const d=c.props.children;if(d){// Only consider BaseNode children for further traversal; primitives and React elements are terminal.
65
+ const b=(Array.isArray(d)?d:[d]).filter(NodeUtil.isNodeInstance),c=g+b.length;// --- Check capacity ONCE before loop ---
66
+ a(c);for(let a=b.length-1;0<=a;a--){const c=b[a],d=NodeUtil.isServer||!c.stableKey?void 0:BaseNode.elementCache.get(c.stableKey),i=NodeUtil.shouldNodeUpdate(d?.prevDeps,c._deps,h);// Respect server/client differences for child cache lookup.
68
67
  // Determine whether the child should update given its deps and the parent's blocked state.
69
68
  // If child doesn't need update and has cached element, reuse it immediately (no push).
70
- if(!i&&f?.renderedElement){g.set(c,f.renderedElement);continue}// Otherwise push child for processing; childBlocked inherits parent's blocked state.
71
- const j=h||!i;d[e++]={node:c,isProcessed:!1,blocked:j}}}}else{e--;// Extract node props. Non-present props default to undefined via destructuring.
72
- const a=b.props,{children:c,key:d,css:f,nativeProps:h,disableEmotion:i}=a,j=_objectWithoutProperties(a,_excluded3);let k=[];c&&(k=(Array.isArray(c)?c:[c]).map(a=>NodeUtil.isNodeInstance(a)?g.get(a):isValidElement(a)?a:a));// Merge element props: explicit other props + DOM native props + React key.
69
+ if(!i&&d?.renderedElement){f.set(c,d.renderedElement);continue}// Otherwise push child for processing; childBlocked inherits parent's blocked state.
70
+ const j=h||!i;e[g++]={node:c,isProcessed:!1,blocked:j}}}}else{g--;// Extract node props. Non-present props default to undefined via destructuring.
71
+ const a=c.props,{children:b,key:d,css:e,nativeProps:h,disableEmotion:i}=a,j=_objectWithoutProperties(a,_excluded3);let k=[];if(b){// Convert child placeholders into concrete React nodes:
72
+ // - If it's a BaseNode, lookup its rendered ReactElement from the map.
73
+ // - If it's already a React element, use it directly.
74
+ // - Otherwise treat as primitive ReactNode.
75
+ const a=Array.isArray(b)?b:[b],c=a.length;// Pre-allocate array to avoid resizing during iteration
76
+ k=Array(c);for(let b=0;b<c;b++){const c=a[b];if(NodeUtil.isNodeInstance(c)){const a=f.get(c);if(!a)throw new Error(`[MeoNode] Missing rendered element for child node: ${c.stableKey}`);k[b]=a}else k[b]=isValidElement(c)?c:c}}// Merge element props: explicit other props + DOM native props + React key.
73
77
  const l=_objectSpread(_objectSpread({},j),{},{key:d},h);let m;// Handle fragments specially: create fragment element with key and children.
74
- if(b.element===Fragment||isFragment(b.element))m=createElement(b.element,{key:d},...k);else{// StyledRenderer for emotion-based styling unless explicitly disabled or no styles are present.
78
+ if(c.element===Fragment||isFragment(c.element))m=createElement(c.element,{key:d},...k);else{// StyledRenderer for emotion-based styling unless explicitly disabled or no styles are present.
75
79
  // StyledRenderer handles SSR hydration and emotion CSS injection when css prop exists or element has style tags.
76
- const a=!i&&(f||!hasNoStyleTag(b.element));m=a?createElement(StyledRenderer,_objectSpread(_objectSpread({element:b.element},l),{},{css:f,suppressHydrationWarning:!0}),...k):createElement(b.element,l,...k)}// Cache the generated element on client-side to speed up future renders.
77
- if(!NodeUtil.isServer&&b.stableKey){const a=BaseNode.elementCache.get(b.stableKey);if(a)a.prevDeps=b._deps,a.renderedElement=m,a.accessCount+=1;else{// Create new cache entry and register for cleanup
78
- const a={prevDeps:b._deps,renderedElement:m,nodeRef:new WeakRef(b),createdAt:Date.now(),accessCount:1,instanceId:b.instanceId};// Set new cache entry
79
- BaseNode.elementCache.set(b.stableKey,a),BaseNode.cacheCleanupRegistry.register(b,{cacheKey:b.stableKey,instanceId:b.instanceId},b)}}// Store the rendered element so parent nodes can reference it.
80
- g.set(b,m)}}// Clear references for GC unconditionally
81
- d.length=0;// Get the final rendered element for the root node of this render cycle.
82
- const h=g.get(this);return!NodeUtil.isServer&&this.stableKey?createElement(MeoNodeUnmounter,{node:this},h):h}/**
80
+ const a=!i&&(e||!hasNoStyleTag(c.element));m=a?createElement(StyledRenderer,_objectSpread(_objectSpread({element:c.element},l),{},{css:e,suppressHydrationWarning:!0}),...k):createElement(c.element,l,...k)}// Cache the generated element on client-side to speed up future renders.
81
+ if(!NodeUtil.isServer&&c.stableKey){const a=BaseNode.elementCache.get(c.stableKey);if(a)a.prevDeps=c._deps,a.renderedElement=m,a.accessCount+=1;else{// Create new cache entry and register for cleanup
82
+ const a={prevDeps:c._deps,renderedElement:m,nodeRef:new WeakRef(c),createdAt:Date.now(),accessCount:1,instanceId:c.instanceId};// Set new cache entry
83
+ BaseNode.elementCache.set(c.stableKey,a),BaseNode.cacheCleanupRegistry.register(c,{cacheKey:c.stableKey,instanceId:c.instanceId},c)}}// Store the rendered element so parent nodes can reference it.
84
+ f.set(c,m)}}// Get the final rendered element for the root node of this render cycle.
85
+ const b=f.get(this);return!NodeUtil.isServer&&this.stableKey?createElement(MeoNodeUnmounter,{node:this},b):b}finally{// Always release context back to pool, even if an exception occurred
86
+ // Null out workStack slots to help GC before releasing
87
+ for(let a=0;a<g;a++)e[a]=null;BaseNode.releaseRenderContext({workStack:e,renderedElements:f})}}/**
83
88
  * Renders the node into a React Portal, mounting it directly under `document.body`.
84
89
  * Returns a handle with `update` and `unmount` methods to control the portal's lifecycle.
85
90
  * @method toPortal
@@ -107,7 +112,7 @@ BaseNode.propProcessingCache.clear(),BaseNode.elementCache.clear(),ThemeUtil.cle
107
112
  * The primary factory function for creating a `BaseNode` instance.
108
113
  * It's the simplest way to wrap a component or element.
109
114
  * @function Node
110
- */_BaseNode=BaseNode,_defineProperty(BaseNode,"elementCache",new Map),_defineProperty(BaseNode,"propProcessingCache",new Map),_defineProperty(BaseNode,"scheduledCleanup",!1),_defineProperty(BaseNode,"_navigationStarted",!1),_defineProperty(BaseNode,"cacheCleanupRegistry",new FinalizationRegistry(a=>{const{cacheKey:b,instanceId:c}=a,d=_BaseNode.elementCache.get(b);d?.instanceId===c&&_BaseNode.elementCache.delete(b),MountTrackerUtil.mountedNodes.has(b)&&MountTrackerUtil.untrackMount(b)})),_defineProperty(BaseNode,"portalCleanupRegistry",new FinalizationRegistry(a=>{const{domElement:b,reactRoot:c}=a;__DEBUG__&&console.log("[MeoNode] FinalizationRegistry auto-cleaning portal");// Guard: Check if already unmounted
115
+ */_BaseNode=BaseNode,_defineProperty(BaseNode,"elementCache",new Map),_defineProperty(BaseNode,"propProcessingCache",new Map),_defineProperty(BaseNode,"scheduledCleanup",!1),_defineProperty(BaseNode,"_navigationStarted",!1),_defineProperty(BaseNode,"renderContextPool",[]),_defineProperty(BaseNode,"cacheCleanupRegistry",new FinalizationRegistry(a=>{const{cacheKey:b,instanceId:c}=a,d=_BaseNode.elementCache.get(b);d?.instanceId===c&&_BaseNode.elementCache.delete(b),MountTrackerUtil.mountedNodes.has(b)&&MountTrackerUtil.untrackMount(b)})),_defineProperty(BaseNode,"portalCleanupRegistry",new FinalizationRegistry(a=>{const{domElement:b,reactRoot:c}=a;__DEBUG__&&console.log("[MeoNode] FinalizationRegistry auto-cleaning portal");// Guard: Check if already unmounted
111
116
  try{c&&"function"==typeof c.unmount&&c.unmount()}catch(a){__DEBUG__&&console.error("[MeoNode] Portal auto-cleanup unmount error:",a)}// Guard: Check if DOM element still connected
112
117
  try{b?.isConnected&&b.remove()}catch(a){__DEBUG__&&console.error("[MeoNode] Portal auto-cleanup DOM removal error:",a)}}));function Node(a,b={},c){return new BaseNode(a,b,c)}/**
113
118
  * Static alias on the `Node` factory for clearing all internal caches used by `BaseNode`.
@@ -38,19 +38,31 @@ export declare class NodeUtil {
38
38
  * This check is performed only on the client-side by checking if the property exists in `document.body.style`.
39
39
  * On the server-side, it always returns `false`.
40
40
  * @param k The string to check.
41
+ * @returns True if the string is a valid CSS style property, false otherwise.
41
42
  */
42
43
  static isStyleProp: (k: string) => boolean;
43
44
  /**
44
45
  * Combines FNV-1a and djb2 hash functions for a more robust signature.
45
- * @method hashString
46
+ * This hybrid approach provides better distribution than either algorithm alone.
47
+ * @param str The string to hash.
48
+ * @returns A combined hash string in base-36 format.
46
49
  */
47
50
  static hashString(str: string): string;
51
+ /**
52
+ * Generates a fast structural hash for CSS objects without full serialization.
53
+ * This is an optimized hashing method that samples the first 10 keys for performance.
54
+ * @param css The CSS object to hash.
55
+ * @returns A hash string representing the CSS object structure.
56
+ */
48
57
  private static hashCSS;
49
58
  /**
50
59
  * Creates a unique, stable signature from the element type and props.
51
60
  * This signature includes the element's type to prevent collisions between different components
52
61
  * and handles primitive values in arrays and objects for better caching.
53
- * @method createPropSignature
62
+ * On server environments, returns undefined as signatures are not needed for server-side rendering.
63
+ * @param element The element type to include in the signature.
64
+ * @param props The props object to include in the signature.
65
+ * @returns A unique signature string or undefined on the server.
54
66
  */
55
67
  static createPropSignature(element: NodeElementType, props: Record<string, unknown>): string | undefined;
56
68
  /**
@@ -59,12 +71,18 @@ export declare class NodeUtil {
59
71
  * `aria-*` attributes, `data-*` attributes, `css`, `className`, and `style`.
60
72
  * This method is used to optimize prop processing by focusing on props that are
61
73
  * most likely to influence rendering or behavior.
74
+ * @param props The original props object.
75
+ * @param keys The keys to process from the props object.
76
+ * @returns An object containing only the critical props with an added count property.
62
77
  */
63
78
  static extractCriticalProps(props: Record<string, unknown>, keys: string[]): Record<string, unknown>;
64
79
  /**
65
80
  * Retrieves computed CSS props from the cache with LRU tracking.
66
81
  * Access time and hit count are tracked for smarter eviction.
67
- * @method getCachedCssProps
82
+ * Falls back to direct computation if no signature is provided or running on server.
83
+ * @param cacheableProps The props to compute CSS properties from.
84
+ * @param signature The cache signature to use for lookup.
85
+ * @returns An object containing the CSS props.
68
86
  */
69
87
  static getCachedCssProps(cacheableProps: Record<string, unknown>, signature?: string): {
70
88
  cssProps: Record<string, unknown>;
@@ -72,46 +90,66 @@ export declare class NodeUtil {
72
90
  /**
73
91
  * Implements an LRU eviction strategy that removes multiple entries at once.
74
92
  * It uses a scoring system where older and less frequently used entries have a higher eviction priority.
75
- * @method _evictLRUEntries
93
+ * This batch eviction approach improves performance by avoiding frequent cache cleanup operations.
76
94
  */
77
95
  private static _evictLRUEntries;
78
96
  /**
79
97
  * Calculates an eviction score based on age and frequency of access.
80
98
  * Higher scores mean more likelihood to be evicted.
81
- * @method _calculateEvictionScore
99
+ * The scoring system uses weighted factors: 30% recency and 70% frequency.
100
+ * @param value The cache entry to score.
101
+ * @param now The current timestamp for calculating age.
102
+ * @returns A numeric score representing how likely the entry should be evicted.
82
103
  */
83
104
  private static _calculateEvictionScore;
84
105
  /**
85
106
  * The main prop processing pipeline. It separates cacheable and non-cacheable props,
86
107
  * generates a signature for caching, and assembles the final props object.
87
- * @method processProps
108
+ * This method applies optimizations like fast-path for simple props and hybrid caching strategy.
109
+ * @param element The element type for which props are being processed.
110
+ * @param rawProps The original props to process.
111
+ * @param stableKey The stable key used for child normalization (optional).
112
+ * @returns The processed props object ready for rendering.
88
113
  */
89
114
  static processProps(element: NodeElementType, rawProps?: Partial<NodeProps<NodeElementType>>, stableKey?: string): FinalNodeProps;
90
115
  /**
91
116
  * Processes and normalizes children of the node.
92
117
  * Converts raw children (React elements, primitives, or other BaseNodes) into a consistent format.
118
+ * Applies optimizations for single and multiple children scenarios.
93
119
  * @param children The raw children to process.
94
120
  * @param disableEmotion If true, emotion styling will be disabled for these children.
95
121
  * @param parentStableKey The stable key of the parent node, used for generating unique keys for children.
122
+ * @returns The processed children in normalized format.
96
123
  */
97
124
  private static _processChildren;
98
125
  /**
99
126
  * Determines if a node should update based on its dependency array.
100
127
  * Uses a shallow comparison, similar to React's `useMemo` and `useCallback`.
101
- * @method shouldNodeUpdate
128
+ * On server environments, always returns true since SSR has no concept of re-renders.
129
+ * @param prevDeps Previous dependency array to compare.
130
+ * @param newDeps New dependency array to compare.
131
+ * @param parentBlocked Flag indicating if the parent is blocked from updating.
132
+ * @returns True if the node should update, false otherwise.
102
133
  */
103
134
  static shouldNodeUpdate(prevDeps: DependencyList | undefined, newDeps: DependencyList | undefined, parentBlocked: boolean): boolean;
104
135
  /**
105
136
  * The core normalization function for a single child. It takes any valid `NodeElement`
106
137
  * (primitive, React element, function, `BaseNode` instance) and converts it into a standardized `BaseNode`
107
138
  * instance if it isn't one already. This ensures a consistent structure for the iterative renderer.
108
- * @method processRawNode
139
+ * Handles various node types including primitives, BaseNode instances, function-as-children, React elements,
140
+ * component classes, and component instances.
141
+ * @param node The node element to process and normalize.
142
+ * @param disableEmotion If true, emotion styling will be disabled for this node.
143
+ * @param stableKey The stable key for positional information in parent-child relationships.
144
+ * @returns The normalized node element in BaseNode format.
109
145
  */
110
146
  static processRawNode(node: NodeElement, disableEmotion?: boolean, stableKey?: string): NodeElement;
111
147
  /**
112
148
  * A helper to reliably identify if a given function is a "function-as-a-child" (render prop)
113
149
  * rather than a standard Function Component.
114
- * @method isFunctionChild
150
+ * Distinguishes between render prop functions and component functions by checking for React component signatures.
151
+ * @param node The node to check.
152
+ * @returns True if the node is a function-as-a-child, false otherwise.
115
153
  */
116
154
  static isFunctionChild<E extends NodeInstance | ReactNode>(node: NodeElement): node is NodeFunction<E>;
117
155
  /**
@@ -122,11 +160,9 @@ export declare class NodeUtil {
122
160
  *
123
161
  * This allows `BaseNode` to support render props while maintaining its internal processing
124
162
  * and normalization logic for the dynamically generated content.
125
- * @method functionRenderer
126
- * @param {Object} props The properties passed to the renderer.
127
- * @param {Function} props.render The function-as-a-child to execute.
128
- * @param {boolean} [props.disableEmotion] Inherited flag to disable Emotion styling for children.
129
- * @returns {ReactNode | null | undefined} The processed and rendered output of the render function.
163
+ * @param render The function-as-a-child to execute.
164
+ * @param disableEmotion Inherited flag to disable Emotion styling for children.
165
+ * @returns The processed and rendered output of the render function, or null if an error occurs.
130
166
  */
131
167
  static functionRenderer<E extends ReactNode | NodeInstance>({ render, disableEmotion }: FunctionRendererProps<E>): ReactNode | null | undefined;
132
168
  /**
@@ -137,7 +173,10 @@ export declare class NodeUtil {
137
173
  *
138
174
  * This method is part of the child processing pipeline, converting internal `NodeElement` representations
139
175
  * into actual React elements that can be rendered by React.
140
- * @method renderProcessedNode
176
+ * @param processedElement The processed node element to render.
177
+ * @param passedKey Optional key to apply to the rendered element.
178
+ * @param disableEmotion Flag to disable emotion styling if needed.
179
+ * @returns The rendered ReactNode.
141
180
  */
142
181
  static renderProcessedNode({ processedElement, passedKey, disableEmotion }: {
143
182
  processedElement: NodeElement;
@@ -147,9 +186,16 @@ export declare class NodeUtil {
147
186
  /**
148
187
  * Ensures that the necessary DOM element and React root are available for portal rendering.
149
188
  * This is only executed on the client-side.
150
- * @method ensurePortalInfrastructure
189
+ * Handles cleanup of stale infrastructure and creates new infrastructure as needed.
190
+ * @param node The node instance that requires portal infrastructure.
191
+ * @returns True if portal infrastructure is ready, false on server or if setup fails.
151
192
  */
152
193
  static ensurePortalInfrastructure(node: NodeInstance): boolean;
194
+ /**
195
+ * Cleans up portal infrastructure by unmounting the React root and removing the DOM element.
196
+ * This ensures proper memory cleanup and prevents memory leaks.
197
+ * @param infra The infrastructure object containing the DOM element and React root to clean up.
198
+ */
153
199
  static cleanupPortalInfra(infra: {
154
200
  domElement: HTMLDivElement;
155
201
  reactRoot: Root;
@@ -1 +1 @@
1
- {"version":3,"file":"node.util.d.ts","sourceRoot":"","sources":["../../src/util/node.util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node.util.d.ts","sourceRoot":"","sources":["../../src/util/node.util.ts"],"names":[],"mappings":"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"}
@@ -6,19 +6,30 @@ const _excluded=["ref","key","children","css","props","disableEmotion"],_exclude
6
6
  */export class NodeUtil{constructor(){}// Determines if the current environment is server-side (Node.js) or client-side (browser).
7
7
  /**
8
8
  * Combines FNV-1a and djb2 hash functions for a more robust signature.
9
- * @method hashString
9
+ * This hybrid approach provides better distribution than either algorithm alone.
10
+ * @param str The string to hash.
11
+ * @returns A combined hash string in base-36 format.
10
12
  */static hashString(a){let b=2166136261,c=5381;// FNV offset basis
11
13
  // djb2 init
12
14
  for(let d=0;d<a.length;d++){const e=a.charCodeAt(d);// FNV-1a
13
15
  // djb2
14
- b^=e,b=Math.imul(b,16777619),c=33*c^e}return`${(b>>>0).toString(36)}_${(c>>>0).toString(36)}`}static hashCSS(a){var b=Math.min;const c=this._cssCache.get(a);if(c)return c;// Fast structural hash without full serialization
15
- const d=Object.keys(a);let e=d.length;for(let c=0;c<b(d.length,10);c++){// Sample first 10
16
- const b=d[c],f=a[b],g=b.charCodeAt(0);e=(e<<5)-e+g,e&=e,"string"==typeof f&&(e=(e<<5)-e+f.length)}const f=e.toString(36);return this._cssCache.set(a,f),f}/**
16
+ b^=e,b=Math.imul(b,16777619),c=33*c^e}return`${(b>>>0).toString(36)}_${(c>>>0).toString(36)}`}/**
17
+ * Generates a fast structural hash for CSS objects without full serialization.
18
+ * This is an optimized hashing method that samples the first 10 keys for performance.
19
+ * @param css The CSS object to hash.
20
+ * @returns A hash string representing the CSS object structure.
21
+ */static hashCSS(a){const b=this._cssCache.get(a);if(b)return b;// Fast structural hash without full serialization
22
+ const c=Object.keys(a);let d=c.length;for(let b=0;b<Math.min(c.length,10);b++){// Sample first 10
23
+ const e=c[b],f=a[e],g=e.charCodeAt(0);d=(d<<5)-d+g,d&=d,"string"==typeof f&&(d=(d<<5)-d+f.length)}const e=d.toString(36);return this._cssCache.set(a,e),e}/**
17
24
  * Creates a unique, stable signature from the element type and props.
18
25
  * This signature includes the element's type to prevent collisions between different components
19
26
  * and handles primitive values in arrays and objects for better caching.
20
- * @method createPropSignature
21
- */static createPropSignature(a,b){if(NodeUtil.isServer)return;const c=getElementTypeName(a),d=Object.keys(b).sort(),e=[`${c}:`];if("function"==typeof a){let b=NodeUtil._functionSignatureCache.get(a);b||(b=NodeUtil.hashString(a.toString()),NodeUtil._functionSignatureCache.set(a,b)),e.push(b)}for(const c of d){const a=b[c];let d;const f=typeof a;if("string"==f||"number"===f||"boolean"===f)d=`${c}:${a};`;else if(null===a)d=`${c}:null;`;else if(a===void 0)d=`${c}:undefined;`;else if("css"===c&&"object"==typeof a)d=`css:${this.hashCSS(a)};`;else if(Array.isArray(a)){// Hash primitive values in arrays for better cache hits
27
+ * On server environments, returns undefined as signatures are not needed for server-side rendering.
28
+ * @param element The element type to include in the signature.
29
+ * @param props The props object to include in the signature.
30
+ * @returns A unique signature string or undefined on the server.
31
+ */static createPropSignature(a,b){if(NodeUtil.isServer)return;const c=getElementTypeName(a),d=Object.keys(b);// Optimization: Only sort if there's more than one key to ensure stability
32
+ 1<d.length&&d.sort();const e=[`${c}:`];if("function"==typeof a){let b=NodeUtil._functionSignatureCache.get(a);b||(b=NodeUtil.hashString(a.toString()),NodeUtil._functionSignatureCache.set(a,b)),e.push(b)}for(const c of d){const a=b[c];let d;const f=typeof a;if("string"==f||"number"===f||"boolean"===f)d=`${c}:${a};`;else if(null===a)d=`${c}:null;`;else if(a===void 0)d=`${c}:undefined;`;else if("css"===c&&"object"==typeof a)d=`css:${this.hashCSS(a)};`;else if(Array.isArray(a)){// Hash primitive values in arrays for better cache hits
22
33
  const b=a.filter(a=>{const b=typeof a;return"string"==b||"number"===b||"boolean"===b||null===a});d=b.length===a.length?`${c}:[${b.join(",")}];`:`${c}:[${a.length}];`}else if(a&&a.isBaseNode)d=`${c}:${a.stableKey};`;else{// Include sorted keys for object structure signature
23
34
  const b=Object.keys(a).sort();d=`${c}:{${b.join(",")}};`}e.push(d)}return NodeUtil.hashString(e.join(","))}/**
24
35
  * Extracts "critical" props from a given set of props. Critical props are those
@@ -26,6 +37,9 @@ const b=Object.keys(a).sort();d=`${c}:{${b.join(",")}};`}e.push(d)}return NodeUt
26
37
  * `aria-*` attributes, `data-*` attributes, `css`, `className`, and `style`.
27
38
  * This method is used to optimize prop processing by focusing on props that are
28
39
  * most likely to influence rendering or behavior.
40
+ * @param props The original props object.
41
+ * @param keys The keys to process from the props object.
42
+ * @returns An object containing only the critical props with an added count property.
29
43
  */static extractCriticalProps(a,b){const c={_keyCount:b.length};let d=0;for(const e of b){if(50<=d)break;// Fast path: direct Set check first (O(1))
30
44
  if(NodeUtil.CRITICAL_PROPS.has(e)){c[e]=a[e],d++;continue}// Inline prefix checks using charCode (faster than startsWith for short prefixes)
31
45
  const f=e.charCodeAt(0);// Check 'on' prefix (111 = 'o', 110 = 'n')
@@ -35,42 +49,62 @@ if(100===f&&97===e.charCodeAt(1)&&116===e.charCodeAt(2)&&97===e.charCodeAt(3)){c
35
49
  100>=b.length&&NodeUtil.isStyleProp(e)&&(c[e]=a[e],d++)}return c}/**
36
50
  * Retrieves computed CSS props from the cache with LRU tracking.
37
51
  * Access time and hit count are tracked for smarter eviction.
38
- * @method getCachedCssProps
52
+ * Falls back to direct computation if no signature is provided or running on server.
53
+ * @param cacheableProps The props to compute CSS properties from.
54
+ * @param signature The cache signature to use for lookup.
55
+ * @returns An object containing the CSS props.
39
56
  */static getCachedCssProps(a,b){if(NodeUtil.isServer||!b)return{cssProps:getCSSProps(a)};const c=BaseNode.propProcessingCache.get(b);if(c)return c.lastAccess=Date.now(),c.hitCount++,{cssProps:c.cssProps};const d=getCSSProps(a);return BaseNode.propProcessingCache.set(b,{cssProps:d,signature:b,lastAccess:Date.now(),hitCount:1}),BaseNode.propProcessingCache.size>NodeUtil.CACHE_SIZE_LIMIT&&!BaseNode.scheduledCleanup&&(BaseNode.scheduledCleanup=!0,"undefined"==typeof requestIdleCallback?setTimeout(()=>{NodeUtil._evictLRUEntries(),BaseNode.scheduledCleanup=!1},100):requestIdleCallback(()=>{NodeUtil._evictLRUEntries(),BaseNode.scheduledCleanup=!1},{timeout:2e3})),{cssProps:d}}/**
40
57
  * Implements an LRU eviction strategy that removes multiple entries at once.
41
58
  * It uses a scoring system where older and less frequently used entries have a higher eviction priority.
42
- * @method _evictLRUEntries
59
+ * This batch eviction approach improves performance by avoiding frequent cache cleanup operations.
43
60
  */static _evictLRUEntries(){const a=Date.now(),b=new MinHeap((c,a)=>a.score-c.score);// Create max-heap (using min-heap with inverted comparison) to get highest scores first
44
61
  for(const[c,d]of BaseNode.propProcessingCache.entries()){const e=this._calculateEvictionScore(d,a);b.push({key:c,score:e})}// O(log n) eviction of top N entries
45
62
  for(let a=0;a<NodeUtil.CACHE_CLEANUP_BATCH;a++){const a=b.pop();if(a)BaseNode.propProcessingCache.delete(a.key);else// No more items to evict
46
63
  break}}/**
47
64
  * Calculates an eviction score based on age and frequency of access.
48
65
  * Higher scores mean more likelihood to be evicted.
49
- * @method _calculateEvictionScore
66
+ * The scoring system uses weighted factors: 30% recency and 70% frequency.
67
+ * @param value The cache entry to score.
68
+ * @param now The current timestamp for calculating age.
69
+ * @returns A numeric score representing how likely the entry should be evicted.
50
70
  */static _calculateEvictionScore(a,b){const c=b-a.lastAccess,d=a.hitCount;// Weighted scoring: recency 30%, frequency 70% - favors frequently accessed items
51
71
  return .3*(c/1e3)+.7*(1e3/(d+1))}/**
52
72
  * The main prop processing pipeline. It separates cacheable and non-cacheable props,
53
73
  * generates a signature for caching, and assembles the final props object.
54
- * @method processProps
74
+ * This method applies optimizations like fast-path for simple props and hybrid caching strategy.
75
+ * @param element The element type for which props are being processed.
76
+ * @param rawProps The original props to process.
77
+ * @param stableKey The stable key used for child normalization (optional).
78
+ * @returns The processed props object ready for rendering.
55
79
  */static processProps(a,b={},c){const{ref:d,key:e,children:f,css:g,props:i={},disableEmotion:h}=b,j=_objectWithoutProperties(b,_excluded);// --- Fast Path Optimization ---
56
80
  if(0===Object.keys(j).length&&!g)return omitUndefined({ref:d,key:e,disableEmotion:h,nativeProps:omitUndefined(i),children:NodeUtil._processChildren(f,h)});// --- Hybrid Caching Strategy ---
57
- const k={},l={};// 1. Categorize props into cacheable (primitives) and non-cacheable (objects/functions).
58
- for(const d in j)if(Object.prototype.hasOwnProperty.call(j,d)){const a=j[d],b=typeof a;"string"===b||"number"===b||"boolean"===b?k[d]=a:l[d]=a}// 2. Pass element type to signature generation
59
- const m=NodeUtil.createPropSignature(a,k),{cssProps:n}=NodeUtil.getCachedCssProps(k,m),o=getCSSProps(l),p=getDOMProps(j),q=_objectSpread(_objectSpread(_objectSpread({},n),o),g),r=NodeUtil._processChildren(f,h,c);// 3. Process non-cacheable props on every render to ensure correctness for functions and objects.
81
+ const k={},l={},m=Object.keys(j);// 1. Categorize props into cacheable (primitives) and non-cacheable (objects/functions).
82
+ // Optimization: Use Object.keys loop instead of for..in for better performance and safety
83
+ for(let d=0;d<m.length;d++){const a=m[d],b=j[a],c=typeof b;"string"===c||"number"===c||"boolean"===c?k[a]=b:l[a]=b}// 2. Pass element type to signature generation
84
+ const n=NodeUtil.createPropSignature(a,k),{cssProps:o}=NodeUtil.getCachedCssProps(k,n),p=getCSSProps(l),q=getDOMProps(j),r=_objectSpread(_objectSpread(_objectSpread({},o),p),g),s=NodeUtil._processChildren(f,h,c);// 3. Process non-cacheable props on every render to ensure correctness for functions and objects.
60
85
  // DOM props are always processed fresh.
61
86
  // 4. Assemble the final CSS object.
62
87
  // --- Child Normalization ---
63
88
  // --- Final Assembly ---
64
- return omitUndefined(_objectSpread(_objectSpread({ref:d,key:e,css:q},p),{},{disableEmotion:h,nativeProps:omitUndefined(i),children:r}))}/**
89
+ return omitUndefined(_objectSpread(_objectSpread({ref:d,key:e,css:r},q),{},{disableEmotion:h,nativeProps:omitUndefined(i),children:s}))}/**
65
90
  * Processes and normalizes children of the node.
66
91
  * Converts raw children (React elements, primitives, or other BaseNodes) into a consistent format.
92
+ * Applies optimizations for single and multiple children scenarios.
67
93
  * @param children The raw children to process.
68
94
  * @param disableEmotion If true, emotion styling will be disabled for these children.
69
95
  * @param parentStableKey The stable key of the parent node, used for generating unique keys for children.
70
- */static _processChildren(a,b,c){return a?"function"==typeof a?a:Array.isArray(a)?a.map((a,d)=>NodeUtil.processRawNode(a,b,`${c}_${d}`)):NodeUtil.processRawNode(a,b,c):void 0}/**
96
+ * @returns The processed children in normalized format.
97
+ */static _processChildren(a,b,c){return a?"function"==typeof a?a:Array.isArray(a)?1===a.length?NodeUtil.processRawNode(a[0],b,`${c}_0`):a.map((a,d)=>NodeUtil.processRawNode(a,b,`${c}_${d}`)):NodeUtil.processRawNode(a,b,c):void 0;// Fast path for non-array (single child)
98
+ // Fast path for single element array
99
+ // General case: multiple children
100
+ }/**
71
101
  * Determines if a node should update based on its dependency array.
72
102
  * Uses a shallow comparison, similar to React's `useMemo` and `useCallback`.
73
- * @method shouldNodeUpdate
103
+ * On server environments, always returns true since SSR has no concept of re-renders.
104
+ * @param prevDeps Previous dependency array to compare.
105
+ * @param newDeps New dependency array to compare.
106
+ * @param parentBlocked Flag indicating if the parent is blocked from updating.
107
+ * @returns True if the node should update, false otherwise.
74
108
  */static shouldNodeUpdate(a,b,c){// SSR has no concept of re-renders, so deps system doesn't apply
75
109
  return!!NodeUtil.isServer||!c&&(!(void 0!==b)||!(void 0!==a)||b.length!==a.length||!!b.some((b,c)=>!Object.is(b,a[c])));// No deps array means always update.
76
110
  // First render for this keyed component, or no previous deps.
@@ -81,7 +115,12 @@ return!!NodeUtil.isServer||!c&&(!(void 0!==b)||!(void 0!==a)||b.length!==a.lengt
81
115
  * The core normalization function for a single child. It takes any valid `NodeElement`
82
116
  * (primitive, React element, function, `BaseNode` instance) and converts it into a standardized `BaseNode`
83
117
  * instance if it isn't one already. This ensures a consistent structure for the iterative renderer.
84
- * @method processRawNode
118
+ * Handles various node types including primitives, BaseNode instances, function-as-children, React elements,
119
+ * component classes, and component instances.
120
+ * @param node The node element to process and normalize.
121
+ * @param disableEmotion If true, emotion styling will be disabled for this node.
122
+ * @param stableKey The stable key for positional information in parent-child relationships.
123
+ * @returns The normalized node element in BaseNode format.
85
124
  */static processRawNode(a,b,c){// Primitives and null/undefined are returned as-is.
86
125
  if(null===a||a===void 0||"string"==typeof a||"number"==typeof a||"boolean"==typeof a)return a;// If it's already a BaseNode, clone it with a positional key if available.
87
126
  if(NodeUtil.isNodeInstance(a)){const d=c||b&&!a.rawProps.disableEmotion;if(d){// Create a new BaseNode instance.
@@ -94,7 +133,9 @@ return isReactClassComponent(a)||isMemo(a)||isForwardRef(a)?new BaseNode(a,{disa
94
133
  }/**
95
134
  * A helper to reliably identify if a given function is a "function-as-a-child" (render prop)
96
135
  * rather than a standard Function Component.
97
- * @method isFunctionChild
136
+ * Distinguishes between render prop functions and component functions by checking for React component signatures.
137
+ * @param node The node to check.
138
+ * @returns True if the node is a function-as-a-child, false otherwise.
98
139
  */static isFunctionChild(a){if("function"!=typeof a||isReactClassComponent(a)||isMemo(a)||isForwardRef(a))return!1;try{return!(a.prototype&&"function"==typeof a.prototype.render)}catch(a){return __DEBUG__&&console.error("MeoNode: Error checking if a node is a function child.",a),!0}}/**
99
140
  * A special internal React component used to render "function-as-a-child" (render prop) patterns.
100
141
  * When a `BaseNode` receives a function as its `children` prop, it wraps that function
@@ -103,11 +144,9 @@ return isReactClassComponent(a)||isMemo(a)||isForwardRef(a)?new BaseNode(a,{disa
103
144
  *
104
145
  * This allows `BaseNode` to support render props while maintaining its internal processing
105
146
  * and normalization logic for the dynamically generated content.
106
- * @method functionRenderer
107
- * @param {Object} props The properties passed to the renderer.
108
- * @param {Function} props.render The function-as-a-child to execute.
109
- * @param {boolean} [props.disableEmotion] Inherited flag to disable Emotion styling for children.
110
- * @returns {ReactNode | null | undefined} The processed and rendered output of the render function.
147
+ * @param render The function-as-a-child to execute.
148
+ * @param disableEmotion Inherited flag to disable Emotion styling for children.
149
+ * @returns The processed and rendered output of the render function, or null if an error occurs.
111
150
  */static functionRenderer({render:a,disableEmotion:b}){let c;try{// Execute the render prop function to get its output.
112
151
  c=a()}catch(a){// If the render function throws, treat its output as null to prevent crashes.
113
152
  __DEBUG__&&console.error("MeoNode: Error executing function-as-a-child.",a),c=null}// Handle null or undefined results directly, as they are valid React render outputs.
@@ -133,7 +172,10 @@ return d?NodeUtil.renderProcessedNode({processedElement:d,disableEmotion:b}):c;/
133
172
  *
134
173
  * This method is part of the child processing pipeline, converting internal `NodeElement` representations
135
174
  * into actual React elements that can be rendered by React.
136
- * @method renderProcessedNode
175
+ * @param processedElement The processed node element to render.
176
+ * @param passedKey Optional key to apply to the rendered element.
177
+ * @param disableEmotion Flag to disable emotion styling if needed.
178
+ * @returns The rendered ReactNode.
137
179
  */static renderProcessedNode({processedElement:a,passedKey:b,disableEmotion:c}){// Initialize an object to hold common props that might be applied to the new BaseNode.
138
180
  const d={};// If a `passedKey` is provided, add it to `commonBaseNodeProps`.
139
181
  // This key is typically used for React's reconciliation process.
@@ -153,12 +195,47 @@ return isReactClassComponent(a)?new BaseNode(a,_objectSpread(_objectSpread({},d)
153
195
  }/**
154
196
  * Ensures that the necessary DOM element and React root are available for portal rendering.
155
197
  * This is only executed on the client-side.
156
- * @method ensurePortalInfrastructure
198
+ * Handles cleanup of stale infrastructure and creates new infrastructure as needed.
199
+ * @param node The node instance that requires portal infrastructure.
200
+ * @returns True if portal infrastructure is ready, false on server or if setup fails.
157
201
  */static ensurePortalInfrastructure(a){if(NodeUtil.isServer)return!1;let b=NodeUtil.portalInfrastructure.get(a);// Check if infrastructure exists and is still connected
158
202
  if(b?.domElement?.isConnected&&b?.reactRoot)return!0;// Clean up stale or disconnected infrastructure
159
203
  if(b&&(!b.domElement?.isConnected||!b.reactRoot)){try{b.reactRoot?.unmount?.()}catch(a){__DEBUG__&&console.error("MeoNode: Error unmounting stale portal root.",a)}NodeUtil.cleanupPortalInfra(b),NodeUtil.portalInfrastructure.delete(a),b=void 0}// Create new infrastructure
160
204
  const c=document.createElement("div");document.body.appendChild(c);const d=createRoot(c),e={render:d.render.bind(d),unmount:d.unmount.bind(d),update:()=>{}// Placeholder, will be overridden
161
- };return b={domElement:c,reactRoot:e},NodeUtil.portalInfrastructure.set(a,b),BaseNode.portalCleanupRegistry.register(a,{domElement:c,reactRoot:e},a),!0}static cleanupPortalInfra(a){try{a.reactRoot?.unmount&&a.reactRoot.unmount()}catch(a){__DEBUG__&&console.error("Portal cleanup error:",a)}try{a.domElement?.isConnected&&a.domElement.remove()}catch(a){__DEBUG__&&console.error("DOM removal error:",a)}}}/**
205
+ };return b={domElement:c,reactRoot:e},NodeUtil.portalInfrastructure.set(a,b),BaseNode.portalCleanupRegistry.register(a,{domElement:c,reactRoot:e},a),!0}/**
206
+ * Cleans up portal infrastructure by unmounting the React root and removing the DOM element.
207
+ * This ensures proper memory cleanup and prevents memory leaks.
208
+ * @param infra The infrastructure object containing the DOM element and React root to clean up.
209
+ */static cleanupPortalInfra(a){try{a.reactRoot?.unmount&&a.reactRoot.unmount()}catch(a){__DEBUG__&&console.error("Portal cleanup error:",a)}try{a.domElement?.isConnected&&a.domElement.remove()}catch(a){__DEBUG__&&console.error("DOM removal error:",a)}}}/**
162
210
  * A min-heap implementation for efficient priority queue operations.
163
211
  * Used for O(log n) eviction in the LRU cache system.
164
- */_NodeUtil=NodeUtil,_defineProperty(NodeUtil,"isServer","undefined"==typeof window),_defineProperty(NodeUtil,"_functionSignatureCache",new WeakMap),_defineProperty(NodeUtil,"CACHE_SIZE_LIMIT",500),_defineProperty(NodeUtil,"CACHE_CLEANUP_BATCH",50),_defineProperty(NodeUtil,"_cssCache",new WeakMap),_defineProperty(NodeUtil,"CRITICAL_PROPS",new Set(["css","className","disableEmotion","props"])),_defineProperty(NodeUtil,"portalInfrastructure",new WeakMap),_defineProperty(NodeUtil,"isNodeInstance",a=>"object"==typeof a&&null!==a&&"element"in a&&"function"==typeof a.render&&"function"==typeof a.toPortal&&"isBaseNode"in a),_defineProperty(NodeUtil,"isStyleProp",_NodeUtil.isServer||"undefined"==typeof document?()=>!1:a=>a in document.body.style);class MinHeap{constructor(a){_defineProperty(this,"heap",[]),this.comparator=a}size(){return this.heap.length}isEmpty(){return 0===this.size()}push(a){this.heap.push(a),this.bubbleUp()}pop(){if(!this.isEmpty()){this.swap(0,this.size()-1);const a=this.heap.pop();return this.bubbleDown(),a}}peek(){return this.isEmpty()?void 0:this.heap[0]}bubbleUp(a=this.size()-1){for(;0<a;){const b=Math.floor((a-1)/2);if(0>=this.comparator(this.heap[b],this.heap[a]))break;this.swap(b,a),a=b}}bubbleDown(a=0){for(const b=this.size()-1;;){const c=2*a+1,d=2*a+2;let e=a;if(c<=b&&0>this.comparator(this.heap[c],this.heap[e])&&(e=c),d<=b&&0>this.comparator(this.heap[d],this.heap[e])&&(e=d),e===a)break;this.swap(a,e),a=e}}swap(a,b){[this.heap[a],this.heap[b]]=[this.heap[b],this.heap[a]]}}
212
+ */_NodeUtil=NodeUtil,_defineProperty(NodeUtil,"isServer","undefined"==typeof window),_defineProperty(NodeUtil,"_functionSignatureCache",new WeakMap),_defineProperty(NodeUtil,"CACHE_SIZE_LIMIT",500),_defineProperty(NodeUtil,"CACHE_CLEANUP_BATCH",50),_defineProperty(NodeUtil,"_cssCache",new WeakMap),_defineProperty(NodeUtil,"CRITICAL_PROPS",new Set(["css","className","disableEmotion","props"])),_defineProperty(NodeUtil,"portalInfrastructure",new WeakMap),_defineProperty(NodeUtil,"isNodeInstance",a=>"object"==typeof a&&null!==a&&"element"in a&&"function"==typeof a.render&&"function"==typeof a.toPortal&&"isBaseNode"in a),_defineProperty(NodeUtil,"isStyleProp",_NodeUtil.isServer||"undefined"==typeof document?()=>!1:a=>a in document.body.style);class MinHeap{/**
213
+ * Constructs a new MinHeap with the provided comparator function.
214
+ * @param comparator A function that compares two elements and returns a negative value if the first is smaller,
215
+ * zero if they are equal, or a positive value if the first is larger.
216
+ */constructor(a){_defineProperty(this,"heap",[]),this.comparator=a}/**
217
+ * Returns the number of elements in the heap.
218
+ * @returns The current size of the heap.
219
+ */size(){return this.heap.length}/**
220
+ * Checks if the heap is empty.
221
+ * @returns True if the heap has no elements, false otherwise.
222
+ */isEmpty(){return 0===this.size()}/**
223
+ * Adds a new value to the heap and maintains the heap property by bubbling it up to the correct position.
224
+ * @param value The value to add to the heap.
225
+ */push(a){this.heap.push(a),this.bubbleUp()}/**
226
+ * Removes and returns the smallest element from the heap (the root).
227
+ * After removal, it maintains the heap property by bubbling down the new root.
228
+ * @returns The smallest element in the heap, or undefined if the heap is empty.
229
+ */pop(){if(!this.isEmpty()){this.swap(0,this.size()-1);const a=this.heap.pop();return this.bubbleDown(),a}}/**
230
+ * Moves the element at the specified index up the heap until the heap property is restored.
231
+ * This is used after inserting a new element to maintain the heap structure.
232
+ * @param index The index of the element to bubble up. Defaults to the last element in the heap.
233
+ */bubbleUp(a=this.size()-1){for(;0<a;){const b=Math.floor((a-1)/2);if(0>=this.comparator(this.heap[b],this.heap[a]))break;this.swap(b,a),a=b}}/**
234
+ * Moves the element at the specified index down the heap until the heap property is restored.
235
+ * This is used after removing the root element to maintain the heap structure.
236
+ * @param index The index of the element to bubble down. Defaults to the root element (index 0).
237
+ */bubbleDown(a=0){for(const b=this.size()-1;;){const c=2*a+1,d=2*a+2;let e=a;if(c<=b&&0>this.comparator(this.heap[c],this.heap[e])&&(e=c),d<=b&&0>this.comparator(this.heap[d],this.heap[e])&&(e=d),e===a)break;this.swap(a,e),a=e}}/**
238
+ * Swaps the elements at the two specified indices in the heap array.
239
+ * @param i The index of the first element to swap.
240
+ * @param j The index of the second element to swap.
241
+ */swap(a,b){[this.heap[a],this.heap[b]]=[this.heap[b],this.heap[a]]}}
@@ -1,20 +1,13 @@
1
1
  import type { CSSProperties } from '@emotion/serialize';
2
2
  import type { CssProp, Theme } from '../types/node.type.js';
3
- /**
4
- * Parsed flex shorthand components for CSS flex property
5
- * @interface FlexComponents
6
- * @property grow - The flex-grow value (how much the item should grow)
7
- * @property shrink - The flex-shrink value (how much the item should shrink)
8
- * @property basis - The flex-basis value (initial main size before free space is distributed)
9
- */
10
3
  interface FlexComponents {
11
4
  grow: number;
12
5
  shrink: number;
13
6
  basis: string | number;
14
7
  }
15
8
  export declare class ThemeUtil {
16
- private constructor();
17
9
  private static themeCache;
10
+ private constructor();
18
11
  /**
19
12
  * Parses a CSS flex shorthand property into its individual components.
20
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"theme.util.d.ts","sourceRoot":"","sources":["../../src/util/theme.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAe,MAAM,yBAAyB,CAAA;AAiG1E;;;;;;GAMG;AACH,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AACD,qBAAa,SAAS;IACpB,OAAO,eAAiB;IAExB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAmC;IAE5D;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAc,kBAAkB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,cAAc,GAAG,IAAI,CA2BnF;IAED,OAAc,aAAa,uDAM1B;IAED;;;;;;;;OAQG;IACH,OAAc,mBAAmB,GAAI,CAAC;;YA0HrC;IAED,OAAc,eAAe,aAE5B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;IACH,OAAc,mBAAmB,yBAmEhC;CACF"}
1
+ {"version":3,"file":"theme.util.d.ts","sourceRoot":"","sources":["../../src/util/theme.util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAe,MAAM,yBAAyB,CAAA;AA+F1E,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACvB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,UAAU,CAAmC;IAE5D,OAAO,eAAiB;IAExB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAc,kBAAkB,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,cAAc,GAAG,IAAI,CA2BnF;IAED,OAAc,aAAa,uDAM1B;IAED;;;;;;;;OAQG;IACH,OAAc,mBAAmB,GAAI,CAAC;;YA0HrC;IAED,OAAc,eAAe,aAE5B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqDG;IACH,OAAc,mBAAmB,yBAmEhC;CACF"}
@@ -1,15 +1,9 @@
1
1
  const _excluded=["flex"];var _ThemeUtil;function _objectWithoutProperties(a,b){if(null==a)return{};var c,d,e=_objectWithoutPropertiesLoose(a,b);if(Object.getOwnPropertySymbols){var f=Object.getOwnPropertySymbols(a);for(d=0;d<f.length;d++)c=f[d],-1===b.indexOf(c)&&{}.propertyIsEnumerable.call(a,c)&&(e[c]=a[c])}return e}function _objectWithoutPropertiesLoose(a,b){if(null==a)return{};var c={};for(var d in a)if({}.hasOwnProperty.call(a,d)){if(-1!==b.indexOf(d))continue;c[d]=a[d]}return c}function ownKeys(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);b&&(d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable})),c.push.apply(c,d)}return c}function _objectSpread(a){for(var b,c=1;c<arguments.length;c++)b=null==arguments[c]?{}:arguments[c],c%2?ownKeys(Object(b),!0).forEach(function(c){_defineProperty(a,c,b[c])}):Object.getOwnPropertyDescriptors?Object.defineProperties(a,Object.getOwnPropertyDescriptors(b)):ownKeys(Object(b)).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))});return a}function _defineProperty(a,b,c){return(b=_toPropertyKey(b))in a?Object.defineProperty(a,b,{value:c,enumerable:!0,configurable:!0,writable:!0}):a[b]=c,a}function _toPropertyKey(a){var b=_toPrimitive(a,"string");return"symbol"==typeof b?b:b+""}function _toPrimitive(a,b){if("object"!=typeof a||!a)return a;var c=a[Symbol.toPrimitive];if(void 0!==c){var d=c.call(a,b||"default");if("object"!=typeof d)return d;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===b?String:Number)(a)}import{ObjHelper}from"../helper/obj.helper.js";import{getValueByPath}from"../helper/common.helper.js";/**
2
2
  * Cache manager for theme resolution operations.
3
- */class ThemeResolverCache{constructor(){_defineProperty(this,"CACHE_SIZE_LIMIT",500),_defineProperty(this,"CACHE_EVICTION_BATCH_SIZE",50),_defineProperty(this,"_resolutionCache",new Map),_defineProperty(this,"_pathLookupCache",new Map),_defineProperty(this,"_themeRegex",/theme\.([a-zA-Z0-9_.-]+)/g)}static getInstance(){return ThemeResolverCache._instance||(ThemeResolverCache._instance=new ThemeResolverCache),ThemeResolverCache._instance}/**
3
+ */class ThemeResolverCache{constructor(){_defineProperty(this,"CACHE_SIZE_LIMIT",500),_defineProperty(this,"CACHE_EVICTION_BATCH_SIZE",50),_defineProperty(this,"_resolutionCache",new Map),_defineProperty(this,"_pathLookupCache",new Map),_defineProperty(this,"_themeRegex",/theme\.([a-zA-Z0-9_.-]+)/g)}static getInstance(){return ThemeResolverCache._instance||(ThemeResolverCache._instance=new ThemeResolverCache),ThemeResolverCache._instance}getResolution(a,b){const c=this._generateCacheKey(a,b),d=this._resolutionCache.get(c);return d&&(this._resolutionCache.delete(c),this._resolutionCache.set(c,d)),d||null}setResolution(a,b,c){const d=this._generateCacheKey(a,b);this._resolutionCache.set(d,c),this._resolutionCache.size>this.CACHE_SIZE_LIMIT&&this._evict(this._resolutionCache)}getPathLookup(a,b){const c=`${ObjHelper.stringify(a)}_${b}`,d=this._pathLookupCache.get(c);return d&&(this._pathLookupCache.delete(c),this._pathLookupCache.set(c,d)),d??null}setPathLookup(a,b,c){const d=`${ObjHelper.stringify(a)}_${b}`;this._pathLookupCache.set(d,c),this._pathLookupCache.size>this.CACHE_SIZE_LIMIT&&this._evict(this._pathLookupCache)}getThemeRegex(){return this._themeRegex.lastIndex=0,this._themeRegex}shouldCache(){return"undefined"==typeof window}clear(){this._resolutionCache.clear(),this._pathLookupCache.clear()}/**
4
4
  * Generate a stable cache key from object and theme, including the theme mode.
5
5
  */_generateCacheKey(a,b){// Including theme.mode is critical for cache correctness.
6
- return`${ObjHelper.stringify(a)}_${b.mode}_${ObjHelper.stringify(b.system)}`}getResolution(a,b){const c=this._generateCacheKey(a,b),d=this._resolutionCache.get(c);return d&&(this._resolutionCache.delete(c),this._resolutionCache.set(c,d)),d||null}setResolution(a,b,c){const d=this._generateCacheKey(a,b);this._resolutionCache.set(d,c),this._resolutionCache.size>this.CACHE_SIZE_LIMIT&&this._evict(this._resolutionCache)}getPathLookup(a,b){const c=`${ObjHelper.stringify(a)}_${b}`,d=this._pathLookupCache.get(c);return d&&(this._pathLookupCache.delete(c),this._pathLookupCache.set(c,d)),d??null}setPathLookup(a,b,c){const d=`${ObjHelper.stringify(a)}_${b}`;this._pathLookupCache.set(d,c),this._pathLookupCache.size>this.CACHE_SIZE_LIMIT&&this._evict(this._pathLookupCache)}_evict(a){const b=a.keys();for(let c=0;c<this.CACHE_EVICTION_BATCH_SIZE;c++){const c=b.next().value;if(c)a.delete(c);else break}}getThemeRegex(){return this._themeRegex.lastIndex=0,this._themeRegex}shouldCache(){return"undefined"==typeof window}clear(){this._resolutionCache.clear(),this._pathLookupCache.clear()}}/**
7
- * Parsed flex shorthand components for CSS flex property
8
- * @interface FlexComponents
9
- * @property grow - The flex-grow value (how much the item should grow)
10
- * @property shrink - The flex-shrink value (how much the item should shrink)
11
- * @property basis - The flex-basis value (initial main size before free space is distributed)
12
- */_defineProperty(ThemeResolverCache,"_instance",null);export class ThemeUtil{constructor(){}/**
6
+ return`${ObjHelper.stringify(a)}_${b.mode}_${ObjHelper.stringify(b.system)}`}_evict(a){const b=a.keys();for(let c=0;c<this.CACHE_EVICTION_BATCH_SIZE;c++){const c=b.next().value;if(c)a.delete(c);else break}}}_defineProperty(ThemeResolverCache,"_instance",null);export class ThemeUtil{constructor(){}/**
13
7
  * Parses a CSS flex shorthand property into its individual components.
14
8
  *
15
9
  * The CSS flex property is a shorthand for flex-grow, flex-shrink, and flex-basis.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meonode/ui",
3
3
  "description": "A structured approach to component composition, direct CSS-first prop styling, built-in theming, smart prop handling (including raw property pass-through), and dynamic children.",
4
- "version": "0.4.9",
4
+ "version": "0.4.11",
5
5
  "type": "module",
6
6
  "main": "./dist/main.js",
7
7
  "types": "./dist/main.d.ts",
@@ -31,9 +31,9 @@
31
31
  "scripts": {
32
32
  "watch:build": "yarn dlx nodemon --watch src --ext ts,tsx,js,json --exec \"yarn build\"",
33
33
  "lint": "eslint --fix",
34
- "test": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --experimental-vm-modules node_modules/jest/bin/jest.js --ci --verbose --testPathIgnorePatterns=\"tests/performance.test.ts\"",
35
- "test:perf": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --experimental-vm-modules node_modules/jest/bin/jest.js --ci --verbose tests/performance.test.ts",
36
- "test:all": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --experimental-vm-modules node_modules/jest/bin/jest.js --ci --verbose",
34
+ "test": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --max-old-space-size=8192 --experimental-vm-modules $(yarn bin jest) --ci --verbose --testPathIgnorePatterns=\"tests/performance.test.ts\" --testPathIgnorePatterns=\"tests/react-createelement-comparison.test.ts\"",
35
+ "test:perf": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --max-old-space-size=8192 --experimental-vm-modules $(yarn bin jest) --ci --verbose tests/performance.test.ts tests/react-createelement-comparison.test.ts",
36
+ "test:all": "NODE_OPTIONS='--expose-gc' node --stack-size=10000 --max-old-space-size=8192 --experimental-vm-modules $(yarn bin jest) --ci --verbose",
37
37
  "prebuild": "yarn lint && yarn test:all",
38
38
  "build": "yarn prebuild && rm -rf ./dist && babel src --out-dir dist --extensions \".ts,.tsx,.js\" && tsgo -p tsconfig.build.json --diagnostics && tsc-alias -p tsconfig.build.json",
39
39
  "publish:pre": "./prepublish.sh && yarn build && yarn version -i prerelease && yarn npm publish --tag next",
@@ -52,7 +52,9 @@
52
52
  "@babel/preset-typescript": "^7.28.5",
53
53
  "@emotion/cache": "^11.14.0",
54
54
  "@emotion/jest": "^11.14.2",
55
+ "@emotion/styled": "^11.14.1",
55
56
  "@eslint/js": "^9.39.1",
57
+ "@mui/material": "^7.3.5",
56
58
  "@testing-library/dom": "^10.4.1",
57
59
  "@testing-library/jest-dom": "^6.9.1",
58
60
  "@testing-library/react": "^16.3.0",
@@ -81,7 +83,7 @@
81
83
  "typescript": "^5.9.3",
82
84
  "typescript-eslint": "^8.47.0"
83
85
  },
84
- "packageManager": "yarn@4.10.2",
86
+ "packageManager": "yarn@4.11.0",
85
87
  "peerDependencies": {
86
88
  "@emotion/cache": ">=11.14.0",
87
89
  "react": ">=19.2.0",