@meonode/ui 0.0.1-alpha.1
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/LICENSE +20 -0
- package/README.md +188 -0
- package/dist/core.node.d.ts +25 -0
- package/dist/core.node.d.ts.map +1 -0
- package/dist/core.node.js +105 -0
- package/dist/html.node.d.ts +596 -0
- package/dist/html.node.d.ts.map +1 -0
- package/dist/html.node.js +408 -0
- package/dist/json/css-properties.json +1311 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +1 -0
- package/dist/node.helper.d.ts +71 -0
- package/dist/node.helper.d.ts.map +1 -0
- package/dist/node.helper.js +76 -0
- package/dist/node.type.d.ts +108 -0
- package/dist/node.type.d.ts.map +1 -0
- package/dist/node.type.js +1 -0
- package/dist/react-is.helper.d.ts +139 -0
- package/dist/react-is.helper.d.ts.map +1 -0
- package/dist/react-is.helper.js +84 -0
- package/docs/basic-usage.md +66 -0
- package/docs/conditional-component-with-hook.md +71 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @meonode/ui
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@meonode/ui)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
<!-- Add other badges as needed: build status, coverage, etc. -->
|
|
6
|
+
|
|
7
|
+
`@meonode/ui` is a lightweight yet powerful utility for the programmatic creation and manipulation of React elements. It
|
|
8
|
+
offers an enhanced, structured way to define components, manage props (separating CSS from DOM attributes), handle
|
|
9
|
+
theming, and compose children *before* they are rendered by React. This provides greater control and flexibility,
|
|
10
|
+
especially for dynamic UIs and design systems.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Key Features
|
|
15
|
+
|
|
16
|
+
* **Programmatic React Element Construction:** Create complex React element trees using a fluent and intuitive API.
|
|
17
|
+
* **Advanced Prop Handling:** Automatically separates CSS style properties from other DOM attributes, simplifying
|
|
18
|
+
component logic.
|
|
19
|
+
* **Integrated Theming System:** Pass theme objects down the tree and reference theme values (e.g.,
|
|
20
|
+
`theme.colors.primary`) directly in style properties.
|
|
21
|
+
* **Flexible Children Management:** Supports various child types, including primitives, other `@meonode/ui` nodes,
|
|
22
|
+
standard React elements, and functions for dynamic rendering (function-as-child pattern).
|
|
23
|
+
* **Type-Safe:** Written entirely in TypeScript, providing excellent autocompletion and compile-time safety.
|
|
24
|
+
* **Seamless Integration:** Works with existing React components and fits naturally into any React workflow.
|
|
25
|
+
* **`Component` HOC:** A higher-order component to easily wrap functions that return `@meonode/ui` instances, making
|
|
26
|
+
them standard React components.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
You'll also need `react` as a peer dependency.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Core Concepts
|
|
35
|
+
|
|
36
|
+
### `Node(element, props)`
|
|
37
|
+
|
|
38
|
+
The primary factory function to create `@meonode/ui` instances (internally `BaseNode`).
|
|
39
|
+
|
|
40
|
+
* `element`: The React element type (e.g., `'div'`, `MyReactComponent`, another `Node` instance).
|
|
41
|
+
* `props`: An object containing properties for the element, including standard HTML attributes, event handlers, `children`, `theme`, and direct CSS style properties.
|
|
42
|
+
|
|
43
|
+
### `BaseNode`
|
|
44
|
+
|
|
45
|
+
The internal representation of a React element within `@meonode/ui`. It holds the element type, processed props (with styles and DOM attributes separated), and processed children. You typically don't interact with `BaseNode` directly but through the `Node` factory. Each `BaseNode` instance has a `render()` method to convert it into a renderable React element.
|
|
46
|
+
|
|
47
|
+
### `Component(componentFunction)`
|
|
48
|
+
|
|
49
|
+
A Higher-Order Component (HOC) that wraps a function. This function receives props and should return either a `@meonode/ui` instance (created via `Node()`) or a standard `ReactNode`. The `Component` HOC ensures that if a `@meonode/ui` instance is returned, its `render()` method is called, making it renderable by React.
|
|
50
|
+
|
|
51
|
+
### Theming
|
|
52
|
+
|
|
53
|
+
Pass a `theme` object via the `theme` prop to any `Node`. This theme becomes available to that `Node` and its descendants. Style properties can then reference theme values using a dot-path string:
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Usage Examples
|
|
58
|
+
|
|
59
|
+
### 1. Basic Usage with `Node()`
|
|
60
|
+
|
|
61
|
+
### 2. Applying Styles Directly root Prop
|
|
62
|
+
|
|
63
|
+
`@meonode/ui` intelligently separates CSS properties from other props. You can provide CSS properties directly at the root of the `props` object.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
### 3. Using Themes
|
|
67
|
+
|
|
68
|
+
Themes allow for centralized styling and easy reuse of design tokens.
|
|
69
|
+
|
|
70
|
+
### 4. Handling Children
|
|
71
|
+
|
|
72
|
+
`@meonode/ui` offers flexible ways to define children:
|
|
73
|
+
|
|
74
|
+
**Note on Function Children and Themes:** When a function child returns a `BaseNode` instance (e.g., `() => Node(...)`), `@meonode/ui` ensures that the parent's theme is propagated to this returned `BaseNode` if it doesn't already have its own theme. This allows `BaseNode`s created within the function to resolve theme-based styles like `color: 'theme.colors.highlight'`.
|
|
75
|
+
|
|
76
|
+
### 5. Creating Reusable Components with `Component` HOC
|
|
77
|
+
|
|
78
|
+
The `Component` HOC simplifies creating standard React components from functions that return `@meonode/ui` nodes.
|
|
79
|
+
|
|
80
|
+
### 6. Using with Existing React Components
|
|
81
|
+
|
|
82
|
+
You can easily incorporate existing React components into your `@meonode/ui` structures.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Usage Implementation
|
|
87
|
+
|
|
88
|
+
The example implementation can be seen in the docs folder:
|
|
89
|
+
1. [Basic Usage](./docs/basic-usage.md)
|
|
90
|
+
2. [Conditional Component With Hook](./docs/conditional-component-with-hook.md)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## API Overview
|
|
95
|
+
|
|
96
|
+
### `Node<E extends NodeElement>(element: E, props: Partial<NodeProps<E>> = {}): BaseNodeInstance<E>`
|
|
97
|
+
|
|
98
|
+
* The main factory function to create `BaseNode` instances.
|
|
99
|
+
* `element`: A string (e.g., 'div'), a React component, or another `BaseNodeInstance`.
|
|
100
|
+
* `props`: Object containing element properties, styles, `children`, and `theme`.
|
|
101
|
+
* Returns: A `BaseNodeInstance`. Call `.render()` on it to get a renderable React element.
|
|
102
|
+
|
|
103
|
+
### `Component<T extends Record<string, any>>(component: (props: T) => BaseNodeInstance<any> | ReactNode): (props: T) => ReactNode`
|
|
104
|
+
|
|
105
|
+
* A Higher-Order Component.
|
|
106
|
+
* `component`: A function that accepts props and returns a `BaseNodeInstance` or any `ReactNode`.
|
|
107
|
+
* Returns: A standard React functional component.
|
|
108
|
+
|
|
109
|
+
### `BaseNodeInstance.render(): ReactNode`
|
|
110
|
+
|
|
111
|
+
* A method on `BaseNodeInstance` (the object returned by `Node()`).
|
|
112
|
+
* Converts the internal `BaseNode` representation into a standard, renderable React Node tree using `React.createElement`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## How It Works (Briefly)
|
|
117
|
+
|
|
118
|
+
1. **Node Creation:**
|
|
119
|
+
- When you call `Node(element, props)`, a `BaseNode` instance is created.
|
|
120
|
+
|
|
121
|
+
2. **Props Processing:**
|
|
122
|
+
- The `BaseNode` constructor analyzes the `props`
|
|
123
|
+
- It uses helper functions (`getCSSProps`, `getDOMProps`) to separate valid CSS style properties from other DOM
|
|
124
|
+
attributes
|
|
125
|
+
- If a `theme` (or `nodeTheme`) is provided, style values like `'theme.colors.primary'` are resolved against this
|
|
126
|
+
theme object using `getValueByPath`
|
|
127
|
+
|
|
128
|
+
3. **Children Processing:**
|
|
129
|
+
- Children are recursively processed
|
|
130
|
+
- If a child is a primitive, React element, or another `BaseNode`, it's adapted
|
|
131
|
+
- Function children are wrapped in a special internal `_functionRenderer` `BaseNode`. This renderer calls the function
|
|
132
|
+
during the render phase and ensures that if the function returns a `BaseNode`, the parent's theme is correctly
|
|
133
|
+
propagated to it
|
|
134
|
+
|
|
135
|
+
4. **Rendering:**
|
|
136
|
+
- The `render()` method on a `BaseNode` instance recursively traverses its structure
|
|
137
|
+
- Calls `render()` on any child `BaseNode`s
|
|
138
|
+
- Ultimately uses `React.createElement` to construct the final tree of React elements
|
|
139
|
+
- The `nodeTheme` prop is removed before passing props to `createElement`
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## TypeScript Support
|
|
144
|
+
|
|
145
|
+
`@meonode/ui` is written in TypeScript and exports all necessary types for a robust development experience. You'll get autocompletion for props, style properties, and theme usage.
|
|
146
|
+
|
|
147
|
+
Key types like `NodeElement`, `NodeProps`, and `BaseNodeInstance` are available if you need to work with them directly, though typically `Node` and `Component` are sufficient.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## When to Use `@meonode/ui`?
|
|
152
|
+
|
|
153
|
+
* Perfect for design systems and UI libraries requiring consistent structure, theming, and maintainable patterns
|
|
154
|
+
* Ideal for generating dynamic UIs from configurations, metadata, schemas or API responses
|
|
155
|
+
* Powerful solution for centralized styling logic, prop transformations and runtime customization
|
|
156
|
+
* Excellent choice for complex component hierarchies needing programmatic manipulation
|
|
157
|
+
* Great alternative to JSX when you prefer a more functional programming approach
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Contributing
|
|
162
|
+
|
|
163
|
+
Contributions are welcome! Please feel free to contact me on discord: **[l7aromeo](https://discordapp.com/users/704803255561224264)**.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## [License](./LICENSE)
|
|
168
|
+
|
|
169
|
+
The MIT License (MIT)
|
|
170
|
+
Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
171
|
+
|
|
172
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
173
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
174
|
+
in the Software without restriction, including without limitation the rights
|
|
175
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
176
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
177
|
+
furnished to do so, subject to the following conditions:
|
|
178
|
+
|
|
179
|
+
The above copyright notice and this permission notice shall be included in all
|
|
180
|
+
copies or substantial portions of the Software.
|
|
181
|
+
|
|
182
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
183
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
184
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
185
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
186
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
187
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
188
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { BaseNodeInstance, NodeElement, NodeProps } from './node.type.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Factory function to create a BaseNode instance.
|
|
5
|
+
* @param element The React element type.
|
|
6
|
+
* @param props The props for the node.
|
|
7
|
+
* @returns BaseNodeInstance<E> - A new BaseNode instance.
|
|
8
|
+
*/
|
|
9
|
+
export default function Node<E extends NodeElement>(element: E, props?: Partial<NodeProps<E>>): BaseNodeInstance<E>;
|
|
10
|
+
/**
|
|
11
|
+
* Higher-order component wrapper that converts BaseNode components into React components.
|
|
12
|
+
*
|
|
13
|
+
* This function takes a component function that may return either a BaseNode instance
|
|
14
|
+
* or a ReactNode, and wraps it to ensure the output is always a renderable ReactNode.
|
|
15
|
+
* BaseNode instances are automatically converted using render().
|
|
16
|
+
* @template T - The type of props accepted by the component
|
|
17
|
+
* @param component The component function that returns either a BaseNode or ReactNode
|
|
18
|
+
* @returns A React function component that takes the same props and returns a ReactNode
|
|
19
|
+
* @example
|
|
20
|
+
* const MyComponent = Component((props) => {
|
|
21
|
+
* return Node('div', { ...props })
|
|
22
|
+
* })
|
|
23
|
+
*/
|
|
24
|
+
export declare function Component<T extends Record<string, any>>(component: (props: T) => BaseNodeInstance<any> | ReactNode): (props: T) => string | number | bigint | boolean | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | BaseNodeInstance<any> | null | undefined;
|
|
25
|
+
//# sourceMappingURL=core.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.node.d.ts","sourceRoot":"","sources":["../src/core.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAkF,SAAS,EAAE,MAAM,OAAO,CAAA;AACjH,OAAO,EACL,gBAAgB,EAIhB,WAAW,EACX,SAAS,EAIV,MAAM,mBAAmB,CAAA;AAkS1B;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,GAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAStH;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,gBAAgB,CAAC,GAAG,CAAC,GAAG,SAAS,IACzG,OAAO,CAAC,wZAOjB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";var _excluded=["children","nodeTheme"],_excluded2=["children","key"];function _typeof(a){"@babel/helpers - typeof";return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},_typeof(a)}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 _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 _classCallCheck(b,a){if(!(b instanceof a))throw new TypeError("Cannot call a class as a function")}function _defineProperties(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,"value"in c&&(c.writable=!0),Object.defineProperty(a,_toPropertyKey(c.key),c)}function _createClass(a,b,c){return b&&_defineProperties(a.prototype,b),c&&_defineProperties(a,c),Object.defineProperty(a,"prototype",{writable:!1}),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{createElement,isValidElement}from"react";import{getComponentType,getCSSProps,getDOMProps,getElementTypeName,getValueByPath}from"./node.helper.ts";import{isForwardRef,isMemo,isReactClassComponent,isValidElementType}from"./react-is.helper.ts";/**
|
|
2
|
+
* Represents a node in a React component tree, providing a structured way to define and manipulate
|
|
3
|
+
* React elements before they are rendered. Handles props processing, theme application, and child node management.
|
|
4
|
+
* @template E The type of the React element this node represents (e.g., 'div', a custom component).
|
|
5
|
+
*/var BaseNode=/*#__PURE__*/function(){/** The React element type for this node. *//** The original, unprocessed props passed to this node during construction. *//** The processed props for this node, including styles, DOM attributes, and children. *//**
|
|
6
|
+
* Constructs a new BaseNode instance.
|
|
7
|
+
* @param element The React element type.
|
|
8
|
+
* @param rawProps The raw props for the node.
|
|
9
|
+
*/function BaseNode(a,b){var c=this;_classCallCheck(this,BaseNode),this.element=a,this.initialRawProps=b;var d=b||{},e=d.children,f=d.nodeTheme,g=_objectWithoutProperties(d,_excluded),h=getCSSProps(g),i=this._resolveStyleWithTheme(h,f);// 1. Resolve styles and DOM props for this node
|
|
10
|
+
i=0<Object.keys(i).length?i:{};var j=getDOMProps(g),k=void 0;// 2. Process rawChildren into BaseNode instances or primitives, passing down currentTheme
|
|
11
|
+
if(e!==void 0&&null!==e)if(Array.isArray(e)){k=e.map(function(a,b){return c._processRawChild(a,f,b)}// Pass index for array children
|
|
12
|
+
)}else// For a single child, no index is passed; existing key logic in _processRawChild will apply
|
|
13
|
+
k=this._processRawChild(e,f);// 3. Construct final this.props
|
|
14
|
+
this.props=_objectSpread(_objectSpread({},j),{},{style:i,nodeTheme:f,children:k})}/**
|
|
15
|
+
* Resolves style properties by replacing theme path placeholders with actual theme values.
|
|
16
|
+
* Handles complex strings like '1px solid theme.background.primary' and iterative resolution.
|
|
17
|
+
* @param initialCssProps The initial CSS properties object.
|
|
18
|
+
* @param theme The theme object to use for resolving paths.
|
|
19
|
+
* @returns A new CSSProperties object with theme values resolved.
|
|
20
|
+
*/return _createClass(BaseNode,[{key:"_resolveStyleWithTheme",value:function _resolveStyleWithTheme(a,b){// If no theme is provided or there are no initial CSS props to process, return the initial props.
|
|
21
|
+
if(!b||0===Object.keys(a).length)return a;var c=_objectSpread({},a);// Create a mutable copy
|
|
22
|
+
for(var d in c)if(Object.prototype.hasOwnProperty.call(c,d)){var e=c[d];if("string"==typeof e&&e.includes("theme.")){var f=e;// Iteratively resolve theme references within the string
|
|
23
|
+
f=f.replace(/theme\.([a-zA-Z0-9_.-]+)/g,function(a,c){var d=getValueByPath(b,c);// Use 'theme' passed to the function
|
|
24
|
+
// Replace if themeValue is found and is a string or number.
|
|
25
|
+
// null is explicitly excluded to avoid 'null' string in output unless intended.
|
|
26
|
+
return void 0!==d&&null!==d&&("string"==typeof d||"number"==typeof d)?d+"":a;// If themeValue is not a string/number, or is undefined/null, keep the original placeholder
|
|
27
|
+
}),c[d]=f}}return c}/**
|
|
28
|
+
* React component that renders the result of a function child, supporting theme propagation.
|
|
29
|
+
*
|
|
30
|
+
* This component is used to render children that are functions (i.e., `() => Children`).
|
|
31
|
+
* It ensures that if the returned value is a `BaseNode` instance without an explicit theme,
|
|
32
|
+
* the theme from the parent is injected. Otherwise, the result is rendered as-is.
|
|
33
|
+
* @param props The props for the renderer.
|
|
34
|
+
* @param props.render The function to invoke for rendering the child.
|
|
35
|
+
* @param props.passedTheme The theme to provide to the child, if applicable.
|
|
36
|
+
* @returns The rendered ReactNode, with theme applied if necessary.
|
|
37
|
+
*/},{key:"_functionRenderer",value:function _functionRenderer(a){var b=a.render,c=a.passedTheme,d=a.passedKey,e=b();// Call the user-provided render function to get the child.
|
|
38
|
+
if(e instanceof BaseNode){var f,g=e;// If the returned BaseNode does not have its own theme, but a theme is provided,
|
|
39
|
+
// re-create the node with the provided theme to ensure correct theme propagation.
|
|
40
|
+
return void 0===(null===(f=g.initialRawProps)||void 0===f?void 0:f.nodeTheme)&&void 0!==c?new BaseNode(g.element,_objectSpread(_objectSpread({},g.initialRawProps||{}),{},{nodeTheme:c,theme:c,// Also pass theme for consistency if it was used in initialRawProps
|
|
41
|
+
key:d})).render():g.render();// If the node already has a theme or no theme is provided, render as-is.
|
|
42
|
+
}// If the result is not a BaseNode (e.g., JSX, string, etc.), return it directly.
|
|
43
|
+
// Note: Non-BaseNode results will not automatically receive the theme.
|
|
44
|
+
return e}/**
|
|
45
|
+
* Processes a single raw child element, converting it into a ProcessedChild.
|
|
46
|
+
* If the child is part of an array and lacks an explicit key, a stable indexed key
|
|
47
|
+
* (`elementName_child_index`) is generated for new BaseNode instances.
|
|
48
|
+
* @param rawChild The raw child element to process.
|
|
49
|
+
* @param parentTheme The theme inherited from the parent node.
|
|
50
|
+
* @param childIndex Optional index of the child if it's part of an array.
|
|
51
|
+
* @returns The processed child.
|
|
52
|
+
*/},{key:"_processRawChild",value:function _processRawChild(a,b,c// Index for generating stable keys for array children
|
|
53
|
+
){var d=getComponentType(a),e=function generateIndexedKeyIfNeeded(a,b){if(b!==void 0&&null!==b)return b;if(void 0!==c){var d=getElementTypeName(a);return"".concat(d,"_child_").concat(c)}// No explicit key, and not an array child, so BaseNode constructor will handle.
|
|
54
|
+
};// Helper to generate an indexed key if no explicit key is present and an index is available.
|
|
55
|
+
// Case 1: Child is already a BaseNode instance
|
|
56
|
+
if(a instanceof BaseNode||"object"===_typeof(a)&&null!==a&&!0===a._isBaseNode){var f=a,g=f.initialRawProps||{},h=g.nodeTheme,i=e(f.element,g.key);// Prefer child's own theme
|
|
57
|
+
return new BaseNode(f.element,_objectSpread(_objectSpread({},g),{},{nodeTheme:h||b||{},key:i}))}// Case 2: Child is a primitive (string, number, boolean, null, undefined)
|
|
58
|
+
if("string"===d||"number"===d||"boolean"===d||null===a||void 0===a)return a;// Case 3: Child is a function that needs to be called during render (FunctionRenderer).
|
|
59
|
+
if("function"===d&&!isReactClassComponent(a)&&!isMemo(a)&&!isForwardRef(a)){// The key is for the BaseNode that wraps the _functionRenderer component.
|
|
60
|
+
// Functions themselves don't have a .key prop that we can access here.
|
|
61
|
+
var j=e(this._functionRenderer,void 0);return new BaseNode(this._functionRenderer,{render:a,passedTheme:b,key:j})}// Case 4: Child is a React Element (JSX element)
|
|
62
|
+
if(isValidElement(a)){// Extract props from the JSX element
|
|
63
|
+
var k=a.props,l=(null===k||void 0===k?void 0:k.nodeTheme)||b,m=e(a.type,a.key);// Prefer nodeTheme from child's props, fallback to parent theme
|
|
64
|
+
// Generate a stable key based on element type and index if needed
|
|
65
|
+
// Remove original key since we'll be using the generated/existing key
|
|
66
|
+
// Create new BaseNode with props from JSX element
|
|
67
|
+
return delete k.key,new BaseNode(a.type,_objectSpread(_objectSpread({},k),{},{nodeTheme:l,key:m}))}// Case 5: Child is an ElementType (string tag, class component, Memo/ForwardRef)
|
|
68
|
+
if(isReactClassComponent(a)||"object"===d&&(isMemo(a)||isForwardRef(a))){// ElementTypes don't have an intrinsic key from the rawChild itself.
|
|
69
|
+
var n=e(a,void 0);return new BaseNode(a,{nodeTheme:b,key:n})}// Case 6: Fallback for other ReactNode types (e.g., Fragments, Portals if not caught by isValidElement)
|
|
70
|
+
// These are returned as-is. If they are elements within an array, React expects them to have keys.
|
|
71
|
+
// This logic primarily adds keys to BaseNode instances we create.
|
|
72
|
+
return a}/**
|
|
73
|
+
* Converts this BaseNode instance into a renderable React node.
|
|
74
|
+
* Recursively processes child nodes and uses `React.createElement` to construct the final React element.
|
|
75
|
+
* @returns A ReactNode representing the rendered element.
|
|
76
|
+
*/},{key:"render",value:function render(){if(!isValidElementType(this.element))throw new Error("Invalid element type: ".concat(this.element," provided!"));var a=this.props,b=a.children,c=a.key,d=_objectWithoutProperties(a,_excluded2),e=function normalizeChild(a){// Changed NodeElement to ProcessedChild for accuracy
|
|
77
|
+
return a instanceof BaseNode||"object"===_typeof(a)&&null!==a&&"render"in a?a.render():a;// Primitives, other ReactNodes
|
|
78
|
+
},f=void 0;// More accurate type
|
|
79
|
+
if(void 0!==b&&null!==b)if(!Array.isArray(b))f=e(b);else if(0<b.length){var g=b.map(e);// Check if all children are null/undefined (e.g. conditional rendering resulted in nothing)
|
|
80
|
+
f=g.every(function(a){return null===a||void 0===a})?void 0:g}else f=void 0;// Prepare props for React.createElement
|
|
81
|
+
var h=_objectSpread(_objectSpread({},d),{},{// Cast otherProps
|
|
82
|
+
key:c// This is the key of the current BaseNode itself
|
|
83
|
+
});// Delete key `nodeTheme` as it's not a valid DOM/React prop for the element
|
|
84
|
+
return delete h.nodeTheme,createElement(this.element,h,f)}}])}();/**
|
|
85
|
+
* Factory function to create a BaseNode instance.
|
|
86
|
+
* @param element The React element type.
|
|
87
|
+
* @param props The props for the node.
|
|
88
|
+
* @returns BaseNodeInstance<E> - A new BaseNode instance.
|
|
89
|
+
*/export default function Node(a){var b=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},c=_objectSpread({},b);// Ensure we are working with a mutable copy
|
|
90
|
+
// 'theme' prop itself is not directly used by BaseNode after this, nodeTheme is.
|
|
91
|
+
// We can keep `theme` in initialRawProps if needed for cloning or inspection.
|
|
92
|
+
return c.theme&&void 0===c.nodeTheme&&(c.nodeTheme=c.theme),new BaseNode(a,c)}/**
|
|
93
|
+
* Higher-order component wrapper that converts BaseNode components into React components.
|
|
94
|
+
*
|
|
95
|
+
* This function takes a component function that may return either a BaseNode instance
|
|
96
|
+
* or a ReactNode, and wraps it to ensure the output is always a renderable ReactNode.
|
|
97
|
+
* BaseNode instances are automatically converted using render().
|
|
98
|
+
* @template T - The type of props accepted by the component
|
|
99
|
+
* @param component The component function that returns either a BaseNode or ReactNode
|
|
100
|
+
* @returns A React function component that takes the same props and returns a ReactNode
|
|
101
|
+
* @example
|
|
102
|
+
* const MyComponent = Component((props) => {
|
|
103
|
+
* return Node('div', { ...props })
|
|
104
|
+
* })
|
|
105
|
+
*/export function Component(a){return function(b){var d=a(b);return d instanceof BaseNode||"object"===_typeof(d)&&null!==d&&!0===d._isBaseNode?d.render():d}}
|