@meonode/ui 0.4.10 → 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,48 @@
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
+
5
47
  ## 0.4.10
6
48
 
7
49
  ### Fix
@@ -887,4 +929,4 @@ All notable changes to this project will be documented in this file.
887
929
  - This changelog covers the most recent development history available
888
930
  - The project focuses on building React UIs with type-safe fluency without JSX syntax
889
931
  - Recent development has emphasized Emotion integration, type safety improvements, and enhanced flexbox support
890
- - 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,CAsBpH"}
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),BaseNode.cacheCleanupRegistry.unregister(a)),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}
@@ -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,18 +6,28 @@ 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
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.
21
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
22
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
23
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
@@ -27,6 +37,9 @@ const b=Object.keys(a).sort();d=`${c}:{${b.join(",")}};`}e.push(d)}return NodeUt
27
37
  * `aria-*` attributes, `data-*` attributes, `css`, `className`, and `style`.
28
38
  * This method is used to optimize prop processing by focusing on props that are
29
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.
30
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))
31
44
  if(NodeUtil.CRITICAL_PROPS.has(e)){c[e]=a[e],d++;continue}// Inline prefix checks using charCode (faster than startsWith for short prefixes)
32
45
  const f=e.charCodeAt(0);// Check 'on' prefix (111 = 'o', 110 = 'n')
@@ -36,23 +49,33 @@ if(100===f&&97===e.charCodeAt(1)&&116===e.charCodeAt(2)&&97===e.charCodeAt(3)){c
36
49
  100>=b.length&&NodeUtil.isStyleProp(e)&&(c[e]=a[e],d++)}return c}/**
37
50
  * Retrieves computed CSS props from the cache with LRU tracking.
38
51
  * Access time and hit count are tracked for smarter eviction.
39
- * @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.
40
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}}/**
41
57
  * Implements an LRU eviction strategy that removes multiple entries at once.
42
58
  * It uses a scoring system where older and less frequently used entries have a higher eviction priority.
43
- * @method _evictLRUEntries
59
+ * This batch eviction approach improves performance by avoiding frequent cache cleanup operations.
44
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
45
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
46
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
47
63
  break}}/**
48
64
  * Calculates an eviction score based on age and frequency of access.
49
65
  * Higher scores mean more likelihood to be evicted.
50
- * @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.
51
70
  */static _calculateEvictionScore(a,b){const c=b-a.lastAccess,d=a.hitCount;// Weighted scoring: recency 30%, frequency 70% - favors frequently accessed items
52
71
  return .3*(c/1e3)+.7*(1e3/(d+1))}/**
53
72
  * The main prop processing pipeline. It separates cacheable and non-cacheable props,
54
73
  * generates a signature for caching, and assembles the final props object.
55
- * @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.
56
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 ---
57
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 ---
58
81
  const k={},l={},m=Object.keys(j);// 1. Categorize props into cacheable (primitives) and non-cacheable (objects/functions).
@@ -66,16 +89,22 @@ const n=NodeUtil.createPropSignature(a,k),{cssProps:o}=NodeUtil.getCachedCssProp
66
89
  return omitUndefined(_objectSpread(_objectSpread({ref:d,key:e,css:r},q),{},{disableEmotion:h,nativeProps:omitUndefined(i),children:s}))}/**
67
90
  * Processes and normalizes children of the node.
68
91
  * Converts raw children (React elements, primitives, or other BaseNodes) into a consistent format.
92
+ * Applies optimizations for single and multiple children scenarios.
69
93
  * @param children The raw children to process.
70
94
  * @param disableEmotion If true, emotion styling will be disabled for these children.
71
95
  * @param parentStableKey The stable key of the parent node, used for generating unique keys for children.
96
+ * @returns The processed children in normalized format.
72
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)
73
98
  // Fast path for single element array
74
99
  // General case: multiple children
75
100
  }/**
76
101
  * Determines if a node should update based on its dependency array.
77
102
  * Uses a shallow comparison, similar to React's `useMemo` and `useCallback`.
78
- * @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.
79
108
  */static shouldNodeUpdate(a,b,c){// SSR has no concept of re-renders, so deps system doesn't apply
80
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.
81
110
  // First render for this keyed component, or no previous deps.
@@ -86,7 +115,12 @@ return!!NodeUtil.isServer||!c&&(!(void 0!==b)||!(void 0!==a)||b.length!==a.lengt
86
115
  * The core normalization function for a single child. It takes any valid `NodeElement`
87
116
  * (primitive, React element, function, `BaseNode` instance) and converts it into a standardized `BaseNode`
88
117
  * instance if it isn't one already. This ensures a consistent structure for the iterative renderer.
89
- * @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.
90
124
  */static processRawNode(a,b,c){// Primitives and null/undefined are returned as-is.
91
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.
92
126
  if(NodeUtil.isNodeInstance(a)){const d=c||b&&!a.rawProps.disableEmotion;if(d){// Create a new BaseNode instance.
@@ -99,7 +133,9 @@ return isReactClassComponent(a)||isMemo(a)||isForwardRef(a)?new BaseNode(a,{disa
99
133
  }/**
100
134
  * A helper to reliably identify if a given function is a "function-as-a-child" (render prop)
101
135
  * rather than a standard Function Component.
102
- * @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.
103
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}}/**
104
140
  * A special internal React component used to render "function-as-a-child" (render prop) patterns.
105
141
  * When a `BaseNode` receives a function as its `children` prop, it wraps that function
@@ -108,11 +144,9 @@ return isReactClassComponent(a)||isMemo(a)||isForwardRef(a)?new BaseNode(a,{disa
108
144
  *
109
145
  * This allows `BaseNode` to support render props while maintaining its internal processing
110
146
  * and normalization logic for the dynamically generated content.
111
- * @method functionRenderer
112
- * @param {Object} props The properties passed to the renderer.
113
- * @param {Function} props.render The function-as-a-child to execute.
114
- * @param {boolean} [props.disableEmotion] Inherited flag to disable Emotion styling for children.
115
- * @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.
116
150
  */static functionRenderer({render:a,disableEmotion:b}){let c;try{// Execute the render prop function to get its output.
117
151
  c=a()}catch(a){// If the render function throws, treat its output as null to prevent crashes.
118
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.
@@ -138,7 +172,10 @@ return d?NodeUtil.renderProcessedNode({processedElement:d,disableEmotion:b}):c;/
138
172
  *
139
173
  * This method is part of the child processing pipeline, converting internal `NodeElement` representations
140
174
  * into actual React elements that can be rendered by React.
141
- * @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.
142
179
  */static renderProcessedNode({processedElement:a,passedKey:b,disableEmotion:c}){// Initialize an object to hold common props that might be applied to the new BaseNode.
143
180
  const d={};// If a `passedKey` is provided, add it to `commonBaseNodeProps`.
144
181
  // This key is typically used for React's reconciliation process.
@@ -158,12 +195,47 @@ return isReactClassComponent(a)?new BaseNode(a,_objectSpread(_objectSpread({},d)
158
195
  }/**
159
196
  * Ensures that the necessary DOM element and React root are available for portal rendering.
160
197
  * This is only executed on the client-side.
161
- * @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.
162
201
  */static ensurePortalInfrastructure(a){if(NodeUtil.isServer)return!1;let b=NodeUtil.portalInfrastructure.get(a);// Check if infrastructure exists and is still connected
163
202
  if(b?.domElement?.isConnected&&b?.reactRoot)return!0;// Clean up stale or disconnected infrastructure
164
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
165
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
166
- };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)}}}/**
167
210
  * A min-heap implementation for efficient priority queue operations.
168
211
  * Used for O(log n) eviction in the LRU cache system.
169
- */_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.10",
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",