@meonode/ui 0.4.14 → 1.0.0
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 +52 -2
- package/README.md +233 -87
- package/dist/cjs/components/meonode-unmounter.client.js +1 -1
- package/dist/cjs/components/theme-provider.client.js +1 -1
- package/dist/cjs/core.node.js +1 -1
- package/dist/cjs/helper/common.helper.js +1 -1
- package/dist/cjs/util/mount-tracker.util.js +1 -1
- package/dist/cjs/util/navigation-cache-manager.util.js +1 -1
- package/dist/cjs/util/node.util.js +1 -1
- package/dist/cjs/util/theme.util.js +1 -1
- package/dist/esm/components/meonode-unmounter.client.d.ts.map +1 -1
- package/dist/esm/components/meonode-unmounter.client.js +1 -1
- package/dist/esm/components/theme-provider.client.d.ts +1 -2
- package/dist/esm/components/theme-provider.client.d.ts.map +1 -1
- package/dist/esm/components/theme-provider.client.js +1 -1
- package/dist/esm/core.node.d.ts +8 -10
- package/dist/esm/core.node.d.ts.map +1 -1
- package/dist/esm/core.node.js +1 -1
- package/dist/esm/helper/common.helper.d.ts +9 -0
- package/dist/esm/helper/common.helper.d.ts.map +1 -1
- package/dist/esm/helper/common.helper.js +1 -1
- package/dist/esm/types/node.type.d.ts +2 -9
- package/dist/esm/types/node.type.d.ts.map +1 -1
- package/dist/esm/util/mount-tracker.util.d.ts +9 -5
- package/dist/esm/util/mount-tracker.util.d.ts.map +1 -1
- package/dist/esm/util/mount-tracker.util.js +1 -1
- package/dist/esm/util/navigation-cache-manager.util.d.ts.map +1 -1
- package/dist/esm/util/navigation-cache-manager.util.js +1 -1
- package/dist/esm/util/node.util.d.ts +15 -32
- package/dist/esm/util/node.util.d.ts.map +1 -1
- package/dist/esm/util/node.util.js +1 -1
- package/dist/esm/util/theme.util.d.ts +0 -2
- package/dist/esm/util/theme.util.d.ts.map +1 -1
- package/dist/esm/util/theme.util.js +1 -1
- package/package.json +7 -3
- package/dist/cjs/helper/obj.helper.js +0 -1
- package/dist/esm/helper/obj.helper.d.ts +0 -16
- package/dist/esm/helper/obj.helper.d.ts.map +0 -1
- package/dist/esm/helper/obj.helper.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,12 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.0] - 2025-11-28
|
|
6
|
+
|
|
7
|
+
### Perf
|
|
8
|
+
|
|
9
|
+
- **cache**: Remove props, CSS, and theme caching to improve performance and reduce overhead. ([`206361d`](https://github.com/l7aromeo/meonode-ui/commit/206361d)), ([`d7baa16`](https://github.com/l7aromeo/meonode-ui/commit/d7baa16))
|
|
10
|
+
|
|
11
|
+
### Fix
|
|
12
|
+
|
|
13
|
+
- **theme-provider**: Allow `setTheme` to accept an updater function for more flexible state management. ([`be8d261`](https://github.com/l7aromeo/meonode-ui/commit/be8d261))
|
|
14
|
+
- **core**: Improve mount tracking for cached elements by ensuring `MeoNodeUnmounter` wraps all renderable nodes. ([`d0ca27e`](https://github.com/l7aromeo/meonode-ui/commit/d0ca27e))
|
|
15
|
+
- **theme-provider**: Remove incorrect `@private` JSDoc tag from `ThemeProvider` component. ([`816e398`](https://github.com/l7aromeo/meonode-ui/commit/816e398))
|
|
16
|
+
|
|
17
|
+
### Test
|
|
18
|
+
|
|
19
|
+
- **performance**: Add controlled input performance tests to simulate human typing and measure `deps` memoization effectiveness. ([`bba48b8`](https://github.com/l7aromeo/meonode-ui/commit/bba48b8))
|
|
20
|
+
|
|
21
|
+
### Docs
|
|
22
|
+
|
|
23
|
+
- **readme**: Update `README.md` to reflect the removal of automatic caching and emphasize `deps`-based memoization. ([`2600d9c`](https://github.com/l7aromeo/meonode-ui/commit/2600d9c))
|
|
24
|
+
|
|
25
|
+
## [1.0.0-0] - 2025-11-27
|
|
26
|
+
|
|
27
|
+
### Fix
|
|
28
|
+
|
|
29
|
+
- **core**: Overhaul mount tracking, caching, and fix stableKey generation to prevent memory leaks ([`af1b707`](https://github.com/l7aromeo/meonode-ui/commit/af1b707187b66cdbf9fe88f791aee30cfc7d2835))
|
|
30
|
+
- Replaced the simple `Set` in `MountTrackerUtil` with a reference-counting system (`Map`) to ensure a node is only considered unmounted when all its instances are gone.
|
|
31
|
+
- The root element of a render cycle is now wrapped with a `MeoNodeUnmounter` component before being cached to guarantee that the unmount logic is always present, even for cached elements.
|
|
32
|
+
- Improved `stableKey` generation in `NodeUtil.createPropSignature` to correctly differentiate function props by hashing their string representation, preventing cache collisions for components with different `onClick` or similar handlers.
|
|
33
|
+
- Added new test suites (`leak-repro.test.ts`, `props-caching-leak.test.ts`) to specifically target and verify the leak fixes.
|
|
34
|
+
|
|
35
|
+
### Perf
|
|
36
|
+
|
|
37
|
+
- **cache**: Improve props cache eviction strategy ([`ce2f561`](https://github.com/l7aromeo/meonode-ui/commit/ce2f5616b21d68873dff0f1c4466bf9a2a40ce4d))
|
|
38
|
+
- Adjusted the `propProcessingCache` eviction logic in `NodeUtil` to be more aggressive, removing enough items to get back to the `CACHE_SIZE_LIMIT` plus an additional buffer batch, preventing unbounded growth under high load.
|
|
39
|
+
|
|
40
|
+
### Feat
|
|
41
|
+
|
|
42
|
+
- **deps**: Add react-router-dom and test polyfills ([`29dcf13`](https://github.com/l7aromeo/meonode-ui/commit/29dcf137b5ebcba0e09e5acf13aadac6a0a0f513))
|
|
43
|
+
- Introduced `react-router-dom` as a new development dependency to enable integration testing with React Router.
|
|
44
|
+
- Added `whatwg-fetch` and Node.js `util` polyfills to `jest.setup.ts` for compatibility in the Jest environment.
|
|
45
|
+
|
|
46
|
+
### Test
|
|
47
|
+
|
|
48
|
+
- **react-router**: Add integration tests for react-router-dom ([`8478623`](https://github.com/l7aromeo/meonode-ui/commit/8478623add6bc66b9805a3ec9c0661f4df223f63))
|
|
49
|
+
- Introduced a new test suite to verify the proper functioning and caching behavior of MeoNode components when used within a React Router environment.
|
|
50
|
+
- Includes tests for declarative and programmatic navigation, ensuring that component lifecycles and caching mechanisms interact correctly with React Router's dynamic rendering.
|
|
51
|
+
|
|
52
|
+
### Chore
|
|
53
|
+
- **package**: Rename publish:pre script to publish:prerelease and add publish:premajor script in package.json ([`a98ba69`](https://github.com/l7aromeo/meonode-ui/commit/a98ba697a6e024126256a0e2517c839bbecd8058))
|
|
54
|
+
|
|
5
55
|
## [0.4.14] - 2025-11-23
|
|
6
56
|
|
|
7
57
|
### Perf
|
|
8
58
|
|
|
9
59
|
- **cache**: enforce dependency-based caching with shouldCacheElement helper ([
|
|
10
|
-
`
|
|
60
|
+
`fab5525`](https://github.com/l7aromeo/meonode-ui/commit/fab55253093fbd2958ad84bcc98b1f0d1a07349c))
|
|
11
61
|
- Introduces NodeUtil.shouldCacheElement() helper to centralize and enforce the opt-in caching strategy where only
|
|
12
62
|
nodes with explicit dependencies are cached
|
|
13
63
|
- Completes the memory optimization by closing loopholes where nodes without dependencies were still being cached
|
|
@@ -27,7 +77,7 @@ All notable changes to this project will be documented in this file.
|
|
|
27
77
|
|
|
28
78
|
### Chore
|
|
29
79
|
|
|
30
|
-
- **type**: remove src/types/env.d.ts as it is no longer needed
|
|
80
|
+
- **type**: remove src/types/env.d.ts as it is no longer needed ([aab4299](https://github.com/l7aromeo/meonode-ui/commit/aab429944bf12269d5e6116d3460ff354a42f673))
|
|
31
81
|
|
|
32
82
|
## [0.4.13] - 2025-11-23
|
|
33
83
|
|
package/README.md
CHANGED
|
@@ -4,75 +4,261 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://bundlephobia.com/package/@meonode/ui)
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Type-safe React components without JSX**
|
|
8
8
|
|
|
9
|
-
A
|
|
9
|
+
A production-ready component library that replaces JSX with function-based composition, featuring direct CSS prop
|
|
10
|
+
styling, context-based theming, automatic memoization, and full React Server Components support—powered by
|
|
11
|
+
@emotion/react.
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Core Concept
|
|
14
|
+
|
|
15
|
+
MeoNode UI eliminates JSX while maintaining full React compatibility through functional composition. Style components
|
|
16
|
+
with CSS properties as props, leverage automatic theme resolution via React Context, and benefit from intelligent
|
|
17
|
+
caching without manual optimization.
|
|
18
|
+
|
|
19
|
+
**JSX Pattern:**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<div style={{ padding: '20px', borderRadius: '12px' }}>
|
|
23
|
+
<h2 style={{ fontSize: '1.5rem', marginBottom: '8px' }}>{title}</h2>
|
|
24
|
+
{children}
|
|
25
|
+
</div>
|
|
26
|
+
```
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
**MeoNode Pattern:**
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
Div({
|
|
32
|
+
padding: '20px',
|
|
33
|
+
borderRadius: '12px',
|
|
34
|
+
backgroundColor: 'theme.primary',
|
|
35
|
+
children: [H2(title, { fontSize: '1.5rem', marginBottom: '8px' }), ...children],
|
|
36
|
+
})
|
|
15
37
|
```
|
|
16
38
|
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
### Function-Based Composition
|
|
42
|
+
|
|
43
|
+
Plain JavaScript functions replace JSX—no build transforms, no syntax extensions. Compose UIs as first-class function
|
|
44
|
+
trees with full TypeScript inference.
|
|
45
|
+
|
|
46
|
+
### Direct CSS-in-Props
|
|
47
|
+
|
|
48
|
+
Pass CSS properties directly to components. No separate styled-components declarations, no className juggling. All valid
|
|
49
|
+
CSS properties work as props with full type safety.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
Button('Submit', {
|
|
53
|
+
padding: '12px 24px',
|
|
54
|
+
backgroundColor: 'theme.primary',
|
|
55
|
+
borderRadius: 8,
|
|
56
|
+
transition: 'all 0.2s ease',
|
|
57
|
+
css: {
|
|
58
|
+
':hover': { transform: 'scale(1.05)' },
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Context-Based Theming
|
|
64
|
+
|
|
65
|
+
Theme values resolve automatically through React Context. Reference semantic tokens anywhere without prop drilling.
|
|
66
|
+
Supports nested themes and dynamic switching.
|
|
67
|
+
|
|
17
68
|
```typescript
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
69
|
+
ThemeProvider({
|
|
70
|
+
theme: {
|
|
71
|
+
mode: 'dark',
|
|
72
|
+
system: {
|
|
73
|
+
primary: { default: '#FF6B6B', content: '#4A0000' },
|
|
74
|
+
spacing: { sm: 8, md: 16, lg: 24 },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
children: [
|
|
78
|
+
/* your app */
|
|
79
|
+
],
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Surgical Memoization
|
|
84
|
+
|
|
85
|
+
Memoize at node-level granularity—not just entire components. Control re-renders with precision by specifying dependency
|
|
86
|
+
arrays directly on individual nodes.
|
|
87
|
+
|
|
88
|
+
**Node-Level Memoization:**
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const UserCard = ({ user }) =>
|
|
92
|
+
Div(
|
|
93
|
+
{
|
|
94
|
+
padding: 16,
|
|
95
|
+
children: [
|
|
96
|
+
H2(user.name), // Re-renders on any prop change
|
|
97
|
+
Text(user.bio),
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
[user.id],
|
|
101
|
+
).render() // Only re-render when user.id changes
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Component-Level Memoization:**
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
Node(ExpensiveComponent, { data }, [data.id]).render()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### React Server Components Compatible
|
|
111
|
+
|
|
112
|
+
Full RSC support with proper client/server component boundaries. Use in Next.js App Router, Remix, or any RSC-enabled
|
|
113
|
+
environment without configuration.
|
|
114
|
+
|
|
115
|
+
### Emotion-Powered Styling
|
|
116
|
+
|
|
117
|
+
Built on @emotion/react for:
|
|
118
|
+
|
|
119
|
+
- Automatic critical CSS extraction
|
|
120
|
+
- Vendor prefixing
|
|
121
|
+
- Dead code elimination
|
|
122
|
+
- Server-side rendering support
|
|
123
|
+
- Zero-runtime overhead in production
|
|
124
|
+
|
|
125
|
+
### Smart Prop Differentiation
|
|
126
|
+
|
|
127
|
+
Automatically separates style props from DOM attributes. Pass `onClick`, `aria-*`, `data-*` alongside CSS props—MeoNode
|
|
128
|
+
routes them correctly.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
Button('Click Me', {
|
|
132
|
+
padding: '12px', // → style
|
|
133
|
+
color: 'theme.primary', // → style
|
|
134
|
+
onClick: handleClick, // → DOM attribute
|
|
135
|
+
'aria-label': 'Submit', // → DOM attribute
|
|
136
|
+
disabled: isLoading, // → DOM attribute
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Performance Benchmarks
|
|
141
|
+
|
|
142
|
+
MeoNode is built for high-performance applications, featuring an optimized caching system and iterative rendering
|
|
143
|
+
engine.
|
|
144
|
+
|
|
145
|
+
### Layout Rendering
|
|
146
|
+
|
|
147
|
+
| Metric | Value | Description |
|
|
148
|
+
|:------------------------|:--------|:----------------------------------------------------|
|
|
149
|
+
| **Single-Page Layout** | ~9ms | Full SPA layout with header, hero, features, etc. |
|
|
150
|
+
| **10,000 Flat Nodes** | ~304ms | Rendering 10k nodes at the same level |
|
|
151
|
+
| **10,000 Nested Nodes** | ~1604ms | Deeply nested structure (single parent-child chain) |
|
|
152
|
+
|
|
153
|
+
### Memory Management
|
|
154
|
+
|
|
155
|
+
| Metric | Value | Description |
|
|
156
|
+
|:---------------------------|:-------------|:-------------------------------------------------|
|
|
157
|
+
| **Navigation Memory Leak** | **-7.24 MB** | Memory is efficiently reclaimed after navigation |
|
|
158
|
+
| **Mount/Unmount Cycles** | Stable | No leaks detected over 200 cycles |
|
|
159
|
+
| **State Updates** | Efficient | Handles heavy state changes without bloating |
|
|
160
|
+
|
|
161
|
+
### Form Input Performance
|
|
162
|
+
|
|
163
|
+
| Metric | Value | Description |
|
|
164
|
+
|:----------------------|:------------|:------------------------------------------------|
|
|
165
|
+
| **Avg Response Time** | **2.54 ms** | 100 controlled inputs with simulated typing |
|
|
166
|
+
| **Max Response Time** | 4.09 ms | Worst-case scenario remains instant |
|
|
167
|
+
| **Optimization** | `deps` | Granular updates prevent unnecessary re-renders |
|
|
168
|
+
|
|
169
|
+
### React Comparison (10k Flat Nodes)
|
|
170
|
+
|
|
171
|
+
| Implementation | Time (ms) | Initial Mem |
|
|
172
|
+
|:------------------------|:----------|:------------|
|
|
173
|
+
| **React.createElement** | ~90ms | ~230 MB |
|
|
174
|
+
| **MeoNode** | ~186ms | ~344 MB |
|
|
175
|
+
|
|
176
|
+
> **Note**: While slightly slower in raw micro-benchmarks due to the feature-rich object syntax, MeoNode excels in
|
|
177
|
+
> real-world scenarios with its intelligent caching and memory management.
|
|
178
|
+
|
|
179
|
+
## Quick Start
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { ThemeProvider, Center, Column, H1, Button, Text } from '@meonode/ui'
|
|
27
183
|
|
|
28
184
|
const theme = {
|
|
29
|
-
mode:
|
|
185
|
+
mode: 'light',
|
|
30
186
|
system: {
|
|
31
|
-
primary: { default: '#FF6B6B', content: '#
|
|
187
|
+
primary: { default: '#FF6B6B', content: '#FFFFFF' },
|
|
32
188
|
base: { default: '#F8F8F8', content: '#333333' },
|
|
33
|
-
}
|
|
34
|
-
}
|
|
189
|
+
},
|
|
190
|
+
}
|
|
35
191
|
|
|
36
|
-
const App =
|
|
192
|
+
const App = () =>
|
|
37
193
|
ThemeProvider({
|
|
38
194
|
theme,
|
|
39
|
-
children:
|
|
40
|
-
|
|
41
|
-
children: Center({
|
|
195
|
+
children: [
|
|
196
|
+
Center({
|
|
42
197
|
padding: 40,
|
|
198
|
+
backgroundColor: 'theme.base',
|
|
43
199
|
children: Column({
|
|
44
200
|
gap: 24,
|
|
45
|
-
textAlign: "center",
|
|
46
201
|
children: [
|
|
47
|
-
H1(
|
|
48
|
-
fontSize:
|
|
49
|
-
color:
|
|
202
|
+
H1('MeoNode UI', {
|
|
203
|
+
fontSize: '3rem',
|
|
204
|
+
color: 'theme.primary',
|
|
205
|
+
}),
|
|
206
|
+
Text('Type-safe React without JSX', {
|
|
207
|
+
fontSize: '1.2rem',
|
|
208
|
+
color: 'theme.base.content',
|
|
50
209
|
}),
|
|
51
|
-
Button(
|
|
52
|
-
backgroundColor:
|
|
53
|
-
color:
|
|
54
|
-
padding:
|
|
210
|
+
Button('Get Started', {
|
|
211
|
+
backgroundColor: 'theme.primary',
|
|
212
|
+
color: 'theme.primary.content',
|
|
213
|
+
padding: '12px 24px',
|
|
55
214
|
borderRadius: 8,
|
|
56
|
-
cursor:
|
|
57
|
-
onClick: () =>
|
|
215
|
+
cursor: 'pointer',
|
|
216
|
+
onClick: () => console.log('Started!'),
|
|
58
217
|
}),
|
|
59
218
|
],
|
|
60
219
|
}),
|
|
61
220
|
}),
|
|
62
|
-
|
|
63
|
-
})
|
|
64
|
-
);
|
|
221
|
+
],
|
|
222
|
+
}).render()
|
|
65
223
|
```
|
|
66
224
|
|
|
67
|
-
##
|
|
225
|
+
## Architecture
|
|
226
|
+
|
|
227
|
+
**Component Factory System**
|
|
228
|
+
`Node` factory + `Component` wrapper + semantic elements (Div, Button, etc.) enable both rapid prototyping and
|
|
229
|
+
sophisticated component architectures.
|
|
230
|
+
|
|
231
|
+
**Theme Resolution Engine**
|
|
232
|
+
Context-based theme propagation with automatic value resolution. Nested theme objects inherit and override parent values
|
|
233
|
+
without explicit passing.
|
|
234
|
+
|
|
235
|
+
**CSS Engine**
|
|
236
|
+
@emotion/react provides CSS-in-JS with automatic optimization, critical CSS extraction for SSR, and zero-runtime
|
|
237
|
+
overhead in production builds.
|
|
238
|
+
|
|
239
|
+
## Why MeoNode UI?
|
|
240
|
+
|
|
241
|
+
**For Teams Building Design Systems:**
|
|
242
|
+
|
|
243
|
+
- Context-based theme propagation
|
|
244
|
+
- Semantic token system ensures visual consistency
|
|
245
|
+
- Component composition patterns scale naturally
|
|
246
|
+
- Full TypeScript support catches design token errors
|
|
247
|
+
|
|
248
|
+
**For Performance-Critical Applications:**
|
|
68
249
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
250
|
+
- Emotion's CSS optimization and caching
|
|
251
|
+
- Surgical memoization at node granularity
|
|
252
|
+
- SSR-ready with critical CSS extraction
|
|
253
|
+
- RSC compatibility for modern React architectures
|
|
254
|
+
|
|
255
|
+
**For Developer Productivity:**
|
|
256
|
+
|
|
257
|
+
- No JSX compilation overhead
|
|
258
|
+
- Direct CSS-in-props reduces context switching
|
|
259
|
+
- Intelligent prop routing (style vs DOM attributes)
|
|
260
|
+
- Full autocomplete for all CSS properties
|
|
261
|
+
- Composable function trees with first-class JavaScript
|
|
76
262
|
|
|
77
263
|
## Documentation
|
|
78
264
|
|
|
@@ -80,51 +266,10 @@ const App = Component(() =>
|
|
|
80
266
|
|
|
81
267
|
🎮 **[Interactive Playground](https://codesandbox.io/p/github/l7aromeo/nextjs-meonode/main?import=true)**
|
|
82
268
|
|
|
83
|
-
## Core API
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
// Create reusable components
|
|
87
|
-
const Card = Component<{ title: string }>(({ title }) =>
|
|
88
|
-
Div({
|
|
89
|
-
padding: '20px',
|
|
90
|
-
borderRadius: '8px',
|
|
91
|
-
backgroundColor: 'white',
|
|
92
|
-
children: H2(title)
|
|
93
|
-
})
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// Advanced styling with css prop
|
|
97
|
-
const AnimatedBox = Div({
|
|
98
|
-
padding: '20px',
|
|
99
|
-
css: {
|
|
100
|
-
'&:hover': { transform: 'scale(1.05)' },
|
|
101
|
-
'@media (max-width: 768px)': { padding: '12px' }
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Portal for modals/overlays
|
|
106
|
-
const Modal = Portal(({ portal, message }) =>
|
|
107
|
-
Center({
|
|
108
|
-
position: 'fixed',
|
|
109
|
-
top: 0, left: 0, right: 0, bottom: 0,
|
|
110
|
-
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
111
|
-
onClick: portal.unmount,
|
|
112
|
-
children: Div({
|
|
113
|
-
backgroundColor: 'white',
|
|
114
|
-
padding: '24px',
|
|
115
|
-
borderRadius: '12px',
|
|
116
|
-
children: [
|
|
117
|
-
Text(message),
|
|
118
|
-
Button('Close', { onClick: portal.unmount })
|
|
119
|
-
]
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
);
|
|
123
|
-
```
|
|
124
|
-
|
|
125
269
|
## Contributing
|
|
126
270
|
|
|
127
|
-
We welcome contributions! Please see
|
|
271
|
+
We welcome contributions! Please see
|
|
272
|
+
our [contributing guidelines](https://github.com/l7aromeo/meonode-ui/blob/main/CONTRIBUTING.md).
|
|
128
273
|
|
|
129
274
|
## License
|
|
130
275
|
|
|
@@ -132,4 +277,5 @@ MIT © [Ukasyah Rahmatullah Zada](https://github.com/l7aromeo)
|
|
|
132
277
|
|
|
133
278
|
---
|
|
134
279
|
|
|
135
|
-
**[📖 Full Documentation](https://ui.meonode.com)** • **[🐛 Issues](https://github.com/l7aromeo/meonode-ui/issues)** •
|
|
280
|
+
**[📖 Full Documentation](https://ui.meonode.com)** • **[🐛 Issues](https://github.com/l7aromeo/meonode-ui/issues)** • *
|
|
281
|
+
*[💬 Discussions](https://github.com/l7aromeo/meonode-ui/discussions)**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../util/mount-tracker.util.js"),r=require("../core.node.js");exports.default=function({children:n,...
|
|
2
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../util/mount-tracker.util.js"),r=require("../core.node.js");exports.default=function({children:n,...a}){const{node:l,...s}=a,u=e.useEffectEvent(()=>{l.stableKey&&(r.BaseNode.elementCache.delete(l.stableKey),t.MountTrackerUtil.isMounted(l.stableKey)&&t.MountTrackerUtil.untrackMount(l.stableKey),r.BaseNode.cacheCleanupRegistry.unregister(l)),l.lastSignature=void 0});return e.useEffect(()=>(l.stableKey&&t.MountTrackerUtil.trackMount(l.stableKey),()=>u()),[]),e.isValidElement(n)&&Object.keys(s).length>0?e.cloneElement(n,s):n};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../core.node.js");const r=e.createContext(null);exports.ThemeContext=r,exports.default=function({children:o,theme:n}){const[c,
|
|
2
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../core.node.js");const r=e.createContext(null);exports.ThemeContext=r,exports.default=function({children:o,theme:n}){const[c,u]=e.useState(n);if(!n)throw new Error("`theme` prop must be defined");const d={theme:c,setTheme:e=>{"function"==typeof e&&(e=e(c)),document.cookie=`theme=${e.mode}; path=/;`,u(e)}};return t.Node(r.Provider,{value:d,children:o}).render()};
|
package/dist/cjs/core.node.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("react"),t=require("./helper/react-is.helper.js"),
|
|
1
|
+
"use strict";var e=require("react"),t=require("./helper/react-is.helper.js"),n=require("./helper/common.helper.js"),r=require("./components/styled-renderer.client.js"),o=require("./constant/common.const.js"),s=require("./util/mount-tracker.util.js"),a=require("./components/meonode-unmounter.client.js"),l=require("./util/navigation-cache-manager.util.js"),i=require("./util/node.util.js");const c=Symbol.for("@meonode/ui/BaseNode/elementCache"),d=Symbol.for("@meonode/ui/BaseNode/navigationStarted"),u=Symbol.for("@meonode/ui/BaseNode/renderContextPool"),h=Symbol.for("@meonode/ui/BaseNode/cacheCleanupRegistry"),p=Symbol.for("@meonode/ui/BaseNode/portalCleanupRegistry");class m{instanceId=Math.random().toString(36).slice(2)+Date.now().toString(36);element;rawProps={};isBaseNode=!0;_props;_deps;stableKey;lastPropsObj;lastSignature;static get elementCache(){return n.getGlobalState(c,()=>new Map)}static get _navigationStarted(){return n.getGlobalState(d,()=>({value:!1})).value}static set _navigationStarted(e){n.getGlobalState(d,()=>({value:!1})).value=e}static get renderContextPool(){return n.getGlobalState(u,()=>[])}static acquireRenderContext(){const e=m.renderContextPool;return e.length>0?e.pop():{workStack:new Array(512),renderedElements:new Map}}static releaseRenderContext(e){m.renderContextPool.length<50&&e.workStack.length<2048&&(e.workStack.length=0,e.renderedElements.clear(),m.renderContextPool.push(e))}constructor(e,r={},o){if(!t.isValidElementType(e)){const t=n.getComponentType(e);throw new Error(`Invalid element type: ${t} provided!`)}this.element=e,this.rawProps=r,this._deps=o;const{ref:s,children:a,...c}=r;this.stableKey=this._getStableKey(c),i.NodeUtil.isServer||m._navigationStarted||(l.NavigationCacheManagerUtil.getInstance().start(),m._navigationStarted=!0)}get props(){return this._props||(this._props=i.NodeUtil.processProps(this.element,this.rawProps,this.stableKey)),this._props}get dependencies(){return this._deps}_getStableKey({key:e,...t}){if(i.NodeUtil.isServer)return;if(this.lastPropsObj===t)return this.lastSignature;this.lastPropsObj=t;const r=Object.keys(t),s=r.length;if(s>100){const e=i.NodeUtil.extractCriticalProps(t,r);this.lastSignature=i.NodeUtil.createPropSignature(this.element,e),o.__DEBUG__&&s>200&&console.warn(`MeoNode: Large props (${s} keys) on "${n.getElementTypeName(this.element)}". Consider splitting.`)}else this.lastSignature=i.NodeUtil.createPropSignature(this.element,t);return null!=e?`${String(e)}:${this.lastSignature}`:this.lastSignature}static get cacheCleanupRegistry(){return n.getGlobalState(h,()=>new FinalizationRegistry(e=>{const{cacheKey:t,instanceId:n}=e,r=m.elementCache.get(t);r?.instanceId===n&&m.elementCache.delete(t),s.MountTrackerUtil.isMounted(t)&&s.MountTrackerUtil.untrackMount(t)}))}static get portalCleanupRegistry(){return n.getGlobalState(p,()=>new FinalizationRegistry(e=>{const{domElement:t,reactRoot:n}=e;o.__DEBUG__&&console.log("[MeoNode] FinalizationRegistry auto-cleaning portal");try{n&&"function"==typeof n.unmount&&n.unmount()}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal auto-cleanup unmount error:",e)}try{t?.isConnected&&t.remove()}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal auto-cleanup DOM removal error:",e)}}))}render(o=!1){const s=i.NodeUtil.shouldCacheElement(this)?m.elementCache.get(this.stableKey):void 0,l=i.NodeUtil.shouldNodeUpdate(s?.prevDeps,this._deps,o);if(!l&&s?.renderedElement)return s.accessCount+=1,s.renderedElement;const c=!l,d=m.acquireRenderContext();let{workStack:u}=d;const{renderedElements:h}=d;let p=0;try{const o=e=>{if(e>u.length){const t=Math.max(e,u.length<<1),n=new Array(t);for(let e=0;e<p;e++)n[e]=u[e];u=n}};for(u[p++]={node:this,isProcessed:!1,blocked:c};p>0;){const s=u[p-1];if(!s){p--;continue}const{node:a,isProcessed:l,blocked:c}=s;if(l){p--;const{children:o,key:s,css:l,nativeProps:c,disableEmotion:d,...u}=a.props;let g=[];if(o){const t=Array.isArray(o)?o:[o],n=t.length;g=new Array(n);for(let r=0;r<n;r++){const n=t[r];if(i.NodeUtil.isNodeInstance(n)){const e=h.get(n);if(!e)throw new Error(`[MeoNode] Missing rendered element for child node: ${n.stableKey}`);g[r]=e}else e.isValidElement(n),g[r]=n}}const _={...u,key:s,...c};let y;if(a.element===e.Fragment||t.isFragment(a.element))y=e.createElement(a.element,{key:s},...g);else{y=!d&&(l||!n.hasNoStyleTag(a.element))?e.createElement(r.default,{element:a.element,..._,css:l,suppressHydrationWarning:!0},...g):e.createElement(a.element,_,...g)}if(a!==this&&i.NodeUtil.shouldCacheElement(a)){const e=m.elementCache.get(a.stableKey);if(e)e.prevDeps=a._deps,e.renderedElement=y,e.accessCount+=1;else{const e={prevDeps:a._deps,renderedElement:y,nodeRef:new WeakRef(a),createdAt:Date.now(),accessCount:1,instanceId:a.instanceId};m.elementCache.set(a.stableKey,e),m.cacheCleanupRegistry.register(a,{cacheKey:a.stableKey,instanceId:a.instanceId},a)}}h.set(a,y)}else{s.isProcessed=!0;const e=a.props.children;if(e){const t=(Array.isArray(e)?e:[e]).filter(i.NodeUtil.isNodeInstance);o(p+t.length);for(let e=t.length-1;e>=0;e--){const n=t[e],r=i.NodeUtil.shouldCacheElement(n)?m.elementCache.get(n.stableKey):void 0,o=i.NodeUtil.shouldNodeUpdate(r?.prevDeps,n._deps,c);if(!o&&r?.renderedElement){h.set(n,r.renderedElement);continue}const s=c||!o;u[p++]={node:n,isProcessed:!1,blocked:s}}}}}let s=h.get(this);if(!i.NodeUtil.isServer&&this.stableKey&&(s=e.createElement(a.default,{node:this},s)),i.NodeUtil.shouldCacheElement(this)){const e=m.elementCache.get(this.stableKey);if(e)e.prevDeps=this._deps,e.renderedElement=s,e.accessCount+=1;else{const e={prevDeps:this._deps,renderedElement:s,nodeRef:new WeakRef(this),createdAt:Date.now(),accessCount:1,instanceId:this.instanceId};m.elementCache.set(this.stableKey,e),m.cacheCleanupRegistry.register(this,{cacheKey:this.stableKey,instanceId:this.instanceId},this)}}return s}finally{for(let e=0;e<p;e++)u[e]=null;m.releaseRenderContext({workStack:u,renderedElements:h})}}toPortal(){if(!i.NodeUtil.ensurePortalInfrastructure(this))throw new Error("toPortal() can only be called in a client-side environment");const e=i.NodeUtil.portalInfrastructure.get(this),{domElement:t,reactRoot:n}=e;(()=>{try{n.render(this.render())}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal render error:",e)}})();let r=!1;const s=n.unmount.bind(n);return n.update=e=>{if(r)o.__DEBUG__&&console.warn("[MeoNode] Attempt to update already-unmounted portal");else try{const t=i.NodeUtil.isNodeInstance(e)?e.render():e;n.render(t)}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal update error:",e)}},n.unmount=()=>{if(r)o.__DEBUG__&&console.warn("[MeoNode] Portal already unmounted");else{r=!0;try{m.portalCleanupRegistry.unregister(this)}catch(e){o.__DEBUG__&&console.warn("[MeoNode] Portal unregister warning:",e)}i.NodeUtil.portalInfrastructure.delete(this);try{t?.isConnected&&s()}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal unmount error:",e)}try{t?.isConnected&&t.remove()}catch(e){o.__DEBUG__&&console.error("[MeoNode] Portal DOM cleanup error:",e)}}},n}static clearCaches(){const e=Array.from(m.elementCache.keys());o.__DEBUG__&&console.log(`[MeoNode] clearCaches: Clearing ${e.length} entries`);for(const t of e){const e=m.elementCache.get(t);if(e){const n=e.nodeRef?.deref();if(n)try{m.cacheCleanupRegistry.unregister(n),n.lastSignature=void 0,n.lastPropsObj=void 0}catch{o.__DEBUG__&&console.warn(`[MeoNode] Could not unregister ${t} from FinalizationRegistry`)}}}m.elementCache.clear(),s.MountTrackerUtil.cleanup(),o.__DEBUG__&&console.log("[MeoNode] All caches cleared")}}function g(e,t={},n){return new m(e,t,n)}g.clearCaches=m.clearCaches,exports.BaseNode=m,exports.Node=g,exports.createChildrenFirstNode=function(e,t){const n=(n,r,o)=>g(e,{...t,...r,children:n},o);return n.element=e,n},exports.createNode=function(e,t){const n=(n,r)=>g(e,{...t,...n},r);return n.element=e,n};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./react-is.helper.js"),t=require("../constant/css-properties.const.js"),
|
|
1
|
+
"use strict";var e=require("./react-is.helper.js"),t=require("../constant/css-properties.const.js"),n=require("../constant/common.const.js");const r=t=>e.isForwardRef(t)?"forwardRef":e.isMemo(t)?"memo":e.isFragment(t)?"fragment":e.isPortal(t)?"portal":e.isProfiler(t)?"profiler":e.isStrictMode(t)?"strict-mode":e.isSuspense(t)?"suspense":e.isSuspenseList(t)?"suspense-list":e.isContextConsumer(t)?"context-consumer":e.isContextProvider(t)?"context-provider":e.isLazy(t)?"lazy":e.isElement(t)?"element":e.isReactClassComponent(t)?"class":typeof t;const o=new Set(t.default);exports.CSSPropertySet=o,exports.getCSSProps=function(e){const t={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&o.has(n)&&(t[n]=e[n]);return t},exports.getComponentType=r,exports.getDOMProps=function(e){const t={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&!o.has(n)&&(t[n]=e[n]);return t},exports.getElementTypeName=function e(t){function n(e,t){const n=e?.displayName||e?.name;return n&&"render"!==n?n:t}if(null==t)return"UnknownElementType";const o=t,s=r(o);switch(s){case"string":return t;case"class":return n(o,"ClassComponent");case"function":return n(o,"AnonymousFunctionComponent");case"forwardRef":return n(o,"")||n(o.render,"")||"ForwardRefComponent";case"memo":return n(o,"")||(o.type?e(o.type):"MemoComponent");case"element":return e(o.type);case"fragment":return"Fragment";case"portal":return"Portal";case"profiler":return n(o,"Profiler");case"strict-mode":return"StrictMode";case"suspense":return n(o,"Suspense");case"suspense-list":return"SuspenseList";case"context-consumer":return o._context?.displayName?`${o._context.displayName}.Consumer`:"ContextConsumer";case"context-provider":return o._context?.displayName?`${o._context.displayName}.Provider`:"ContextProvider";case"lazy":return n(o,"LazyComponent");case"object":return n(o,"")?n(o,""):"function"==typeof o.render?n(o.render,"ObjectWithRender"):o.type&&o.type!==t?`Wrapped<${e(o.type)}>`:n(o,"ObjectComponent");case"symbol":return"symbol"==typeof t?t.description?.replace(/^react\./,"").split(".").map(e=>e[0]?.toUpperCase()+e.slice(1)).join("")||t.toString():"SymbolComponent";case"unknown":return"UnknownElementType";default:return`UnsupportedType<${s}>`}},exports.getGlobalState=function(e,t){const n="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{};return Object.prototype.hasOwnProperty.call(n,e)||(n[e]=t()),n[e]},exports.getValueByPath=(e,t)=>t.split(".").reduce((e,t)=>e&&void 0!==e[t]?e[t]:void 0,e),exports.hasNoStyleTag=function(e){return!(!e||"string"!=typeof e)&&n.noStyleTagsSet.has(e.toLowerCase())},exports.omitUndefined=function(e){const t={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&void 0!==e[n]&&(t[n]=e[n]);return t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=require("../constant/common.const.js");class n{constructor(){}static
|
|
1
|
+
"use strict";var t=require("../constant/common.const.js");class n{constructor(){}static _mountedCounts=new Map;static _unmountCallCount=new Map;static isMounted(t){return(this._mountedCounts.get(t)||0)>0}static trackMount(n){const o=this._mountedCounts.get(n)||0;this._mountedCounts.set(n,o+1),t.__DEBUG__&&this._unmountCallCount.delete(n)}static untrackMount(n){const o=this._mountedCounts.get(n)||0;if(o>0){const t=o-1;return 0===t?this._mountedCounts.delete(n):this._mountedCounts.set(n,t),t>0}if(t.__DEBUG__){const t=(this._unmountCallCount.get(n)||0)+1;this._unmountCallCount.set(n,t),t>1&&console.warn(`[MeoNode] untrackMount called ${t} times for an already unmounted node: ${n}. This could indicate a memory leak or a bug in a component's lifecycle.`)}return!1}static cleanup(){this._mountedCounts.clear(),t.__DEBUG__&&this._unmountCallCount.clear()}}exports.MountTrackerUtil=n;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("../constant/common.const.js"),t=require("../core.node.js"),i=require("./mount-tracker.util.js");class a{constructor(){}static _instance=null;static _originalPushState=null;static _originalReplaceState=null;static _isPatched=!1;_isListening=!1;_cleanupTimeout=null;static getInstance(){return this._instance||(this._instance=new a),this._instance}start(){this._isListening||"undefined"==typeof window||(this._isListening=!0,window.addEventListener("popstate",this._handleNavigation),this._patchHistoryMethods(),this._setupAutoCleanup(),e.__DEBUG__&&console.log("[MeoNode] NavigationCacheManagerUtil started"))}_stop(){this._isListening&&"undefined"!=typeof window&&(window.removeEventListener("popstate",this._handleNavigation),this._cleanupTimeout&&(clearTimeout(this._cleanupTimeout),this._cleanupTimeout=null),this._isListening=!1,e.__DEBUG__&&console.log("[MeoNode] NavigationCacheManagerUtil stopped"))}_handleNavigation=()=>{this._cleanupTimeout&&clearTimeout(this._cleanupTimeout);const a=t.BaseNode.elementCache.size,
|
|
1
|
+
"use strict";var e=require("../constant/common.const.js"),t=require("../core.node.js"),i=require("./mount-tracker.util.js");class a{constructor(){}static _instance=null;static _originalPushState=null;static _originalReplaceState=null;static _isPatched=!1;_isListening=!1;_cleanupTimeout=null;static getInstance(){return this._instance||(this._instance=new a),this._instance}start(){this._isListening||"undefined"==typeof window||(this._isListening=!0,window.addEventListener("popstate",this._handleNavigation),this._patchHistoryMethods(),this._setupAutoCleanup(),e.__DEBUG__&&console.log("[MeoNode] NavigationCacheManagerUtil started"))}_stop(){this._isListening&&"undefined"!=typeof window&&(window.removeEventListener("popstate",this._handleNavigation),this._cleanupTimeout&&(clearTimeout(this._cleanupTimeout),this._cleanupTimeout=null),this._isListening=!1,e.__DEBUG__&&console.log("[MeoNode] NavigationCacheManagerUtil stopped"))}_handleNavigation=()=>{this._cleanupTimeout&&clearTimeout(this._cleanupTimeout);const a=t.BaseNode.elementCache.size,n=a<100?50:a<500?100:200;this._cleanupTimeout=setTimeout(()=>{let a=0;t.BaseNode.elementCache.keys().forEach(e=>{i.MountTrackerUtil.isMounted(e)||(t.BaseNode.elementCache.delete(e),a++)}),e.__DEBUG__&&console.log(`[MeoNode] Navigation: cleared ${a} unmounted elements`)},n)};_patchHistoryMethods(){a._isPatched||(a._originalPushState=history.pushState,a._originalReplaceState=history.replaceState,history.pushState=(...e)=>{a._originalPushState.apply(history,e),this._handleNavigation()},history.replaceState=(...e)=>{a._originalReplaceState.apply(history,e),this._handleNavigation()},a._isPatched=!0)}_setupAutoCleanup(){window.__MEONODE_CLEANUP_REGISTERED||(window.addEventListener("beforeunload",()=>{this._stop(),t.BaseNode.clearCaches()}),window.__MEONODE_CLEANUP_REGISTERED=!0)}}exports.NavigationCacheManagerUtil=a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("react"),t=require("../helper/react-is.helper.js"),o=require("../helper/common.helper.js"),r=require("../constant/common.const.js"),
|
|
1
|
+
"use strict";var e=require("react"),t=require("../helper/react-is.helper.js"),o=require("../helper/common.helper.js"),r=require("../constant/common.const.js"),n=require("../core.node.js"),s=require("react-dom/client");const i=Symbol.for("@meonode/ui/NodeUtil/functionSignatureCache"),a=Symbol.for("@meonode/ui/NodeUtil/portalInfrastructure");class c{constructor(){}static isServer="undefined"==typeof window;static get _functionSignatureCache(){return o.getGlobalState(i,()=>new WeakMap)}static CRITICAL_PROPS=new Set(["css","className","disableEmotion","props"]);static get portalInfrastructure(){return o.getGlobalState(a,()=>new WeakMap)}static isNodeInstance=e=>"object"==typeof e&&null!==e&&"element"in e&&"function"==typeof e.render&&"function"==typeof e.toPortal&&"isBaseNode"in e;static isStyleProp=c.isServer||"undefined"==typeof document?()=>!1:e=>e in document.body.style;static hashString(e){let t=2166136261,o=5381;for(let r=0;r<e.length;r++){const n=e.charCodeAt(r);t^=n,t=Math.imul(t,16777619),o=33*o^n}return`${(t>>>0).toString(36)}_${(o>>>0).toString(36)}`}static hashCSS(e){const t=Object.keys(e);let o=t.length;for(let r=0;r<Math.min(t.length,10);r++){const n=t[r],s=e[n];o=(o<<5)-o+n.charCodeAt(0),o&=o,"string"==typeof s&&(o=(o<<5)-o+s.length)}return o.toString(36)}static createPropSignature(e,t){if(c.isServer)return;const r=o.getElementTypeName(e),n=Object.keys(t);n.length>1&&n.sort();const s=[`${r}:`];if("function"==typeof e){let t=c._functionSignatureCache.get(e);t||(t=c.hashString(e.toString()),c._functionSignatureCache.set(e,t)),s.push(t)}for(const e of n){const o=t[e];let r;const n=typeof o;if("string"===n||"number"===n||"boolean"===n)r=`${e}:${o};`;else if(null===o)r=`${e}:null;`;else if(void 0===o)r=`${e}:undefined;`;else if("css"===e&&"object"==typeof o)r=`css:${this.hashCSS(o)};`;else if(Array.isArray(o)){const t=o.filter(e=>{const t=typeof e;return"string"===t||"number"===t||"boolean"===t||null===e});r=t.length===o.length?`${e}:[${t.join(",")}];`:`${e}:[${o.length}];`}else if(o&&o.isBaseNode)r=`${e}:${o.stableKey};`;else if("function"===n)r=`${e}:${c.hashString(o.toString())};`;else{r=`${e}:{${Object.keys(o).sort().join(",")}};`}s.push(r)}return c.hashString(s.join(","))}static extractCriticalProps(e,t){const o={_keyCount:t.length};let r=0;for(const n of t){if(r>=50)break;if(c.CRITICAL_PROPS.has(n)){o[n]=e[n],r++;continue}const s=n.charCodeAt(0);111!==s||110!==n.charCodeAt(1)?!(97===s&&114===n.charCodeAt(1)&&105===n.charCodeAt(2)&&97===n.charCodeAt(3)||100===s&&97===n.charCodeAt(1)&&116===n.charCodeAt(2)&&97===n.charCodeAt(3))?t.length<=100&&c.isStyleProp(n)&&(o[n]=e[n],r++):(o[n]=e[n],r++):(o[n]=e[n],r++)}return o}static processProps(e,t={},r){const{ref:n,key:s,children:i,css:a,props:d={},disableEmotion:l,...u}=t;if(0===Object.keys(u).length&&!a)return o.omitUndefined({ref:n,key:s,disableEmotion:l,nativeProps:o.omitUndefined(d),children:c._processChildren(i,l)});const p={},f={},m=Object.keys(u);for(let e=0;e<m.length;e++){const t=m[e],o=u[t],r=typeof o;"string"===r||"number"===r||"boolean"===r?p[t]=o:f[t]=o}const{cssProps:h}={cssProps:o.getCSSProps(p)},y=o.getCSSProps(f),g=o.getDOMProps(u),b={...h,...y,...a},C=c._processChildren(i,l,r);return o.omitUndefined({ref:n,key:s,css:b,...g,disableEmotion:l,nativeProps:o.omitUndefined(d),children:C})}static _processChildren(e,t,o){if(e)return"function"==typeof e?e:Array.isArray(e)?1===e.length?c.processRawNode(e[0],t,`${o}_0`):e.map((e,r)=>c.processRawNode(e,t,`${o}_${r}`)):c.processRawNode(e,t,o)}static shouldCacheElement(e){return!c.isServer&&!!e.stableKey&&!!e.dependencies}static shouldNodeUpdate(e,t,o){return!!c.isServer||!o&&(void 0===t||(void 0===e||(t.length!==e.length||!!t.some((t,o)=>!Object.is(t,e[o])))))}static processRawNode(o,r,s){if(null==o||"string"==typeof o||"number"==typeof o||"boolean"==typeof o)return o;if(c.isNodeInstance(o)){if(s||r&&!o.rawProps.disableEmotion){const e=new n.BaseNode(o.element,o.rawProps,o.dependencies);return e.stableKey=`${s}:${e.stableKey}`,r&&!e.rawProps.disableEmotion&&(e.rawProps.disableEmotion=!0),e}return o}if(c.isFunctionChild(o))return new n.BaseNode(c.functionRenderer,{props:{render:o,disableEmotion:r}},void 0);if(e.isValidElement(o)){const{style:e,...t}=o.props,s={...t,...e||{}};return new n.BaseNode(o.type,{...s,...null!==o.key&&void 0!==o.key?{key:o.key}:{},disableEmotion:r},void 0)}return t.isReactClassComponent(o)||t.isMemo(o)||t.isForwardRef(o)?new n.BaseNode(o,{disableEmotion:r},void 0):o instanceof e.Component?c.processRawNode(o.render(),r,s):o}static isFunctionChild(e){if("function"!=typeof e||t.isReactClassComponent(e)||t.isMemo(e)||t.isForwardRef(e))return!1;try{return!(e.prototype&&"function"==typeof e.prototype.render)}catch(e){return r.__DEBUG__&&console.error("MeoNode: Error checking if a node is a function child.",e),!0}}static functionRenderer({render:t,disableEmotion:s}){let i;try{i=t()}catch(e){r.__DEBUG__&&console.error("MeoNode: Error executing function-as-a-child.",e),i=null}if(null==i)return i;if(c.isNodeInstance(i))return s&&!i.rawProps.disableEmotion?new n.BaseNode(i.element,{...i.rawProps,disableEmotion:!0}).render():i.render();if(Array.isArray(i)){const e=(e,t)=>{try{return`${o.getElementTypeName(e)}-${t}`}catch(e){return r.__DEBUG__&&console.error("MeoNode: Could not determine element type name for key in function-as-a-child.",e),`item-${t}`}};return i.map((t,o)=>c.renderProcessedNode({processedElement:c.processRawNode(t,s),passedKey:e(t,o),disableEmotion:s}))}if(i instanceof e.Component)return c.renderProcessedNode({processedElement:c.processRawNode(i.render(),s),disableEmotion:s});if("string"==typeof i||"number"==typeof i||"boolean"==typeof i)return i;const a=c.processRawNode(i,s);return a?c.renderProcessedNode({processedElement:a,disableEmotion:s}):i}static renderProcessedNode({processedElement:o,passedKey:r,disableEmotion:s}){const i={};if(void 0!==r&&(i.key=r),c.isNodeInstance(o)){const e=o.rawProps?.key;return o.rawProps.disableEmotion=s,e===r?o.render():new n.BaseNode(o.element,{...o.rawProps,...i}).render()}return t.isReactClassComponent(o)?new n.BaseNode(o,{...i,disableEmotion:s}).render():o instanceof e.Component?o.render():"function"==typeof o?e.createElement(o,{key:r}):o}static ensurePortalInfrastructure(e){if(c.isServer)return!1;let t=c.portalInfrastructure.get(e);if(t?.domElement?.isConnected&&t?.reactRoot)return!0;if(t&&(!t.domElement?.isConnected||!t.reactRoot)){try{t.reactRoot?.unmount?.()}catch(e){r.__DEBUG__&&console.error("MeoNode: Error unmounting stale portal root.",e)}c.cleanupPortalInfra(t),c.portalInfrastructure.delete(e),t=void 0}const o=document.createElement("div");document.body.appendChild(o);const i=s.createRoot(o),a={render:i.render.bind(i),unmount:i.unmount.bind(i),update:()=>{}};return t={domElement:o,reactRoot:a,instanceId:e.instanceId},c.portalInfrastructure.set(e,t),n.BaseNode.portalCleanupRegistry.register(e,{domElement:o,reactRoot:a},e),!0}static cleanupPortalInfra(e){try{e.reactRoot?.unmount&&e.reactRoot.unmount()}catch(e){r.__DEBUG__&&console.error("Portal cleanup error:",e)}try{e.domElement?.isConnected&&e.domElement.remove()}catch(e){r.__DEBUG__&&console.error("DOM removal error:",e)}}}exports.NodeUtil=c;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("../helper/
|
|
1
|
+
"use strict";var e=require("../helper/common.helper.js");class t{constructor(){}static parseFlexShorthand(e){if(null==e)return null;if("number"==typeof e)return{grow:e,shrink:1,basis:"0%"};if("string"!=typeof e)return null;const t=e.trim().toLowerCase();if(!t)return null;switch(t){case"none":return{grow:0,shrink:0,basis:"auto"};case"auto":return{grow:1,shrink:1,basis:"auto"};case"initial":return{grow:0,shrink:1,basis:"auto"};default:return null}}static isPlainObject=e=>{if("object"!=typeof e||null===e)return!1;const t=Object.getPrototypeOf(e);return null===t||t===Object.prototype};static resolveObjWithTheme=(r,l,s={})=>{const{processFunctions:n=!1}=s;if(!l||!l.system||"object"!=typeof l.system||0===Object.keys(l.system).length||!r||0===Object.keys(r).length)return r;const i=l.system,o=[{value:r,isProcessed:!1}],a=new Map,u=new Set,c=/theme\.([a-zA-Z0-9_.-]+)/g,f=t=>{c.lastIndex=0;let r=!1;const l=t.replace(c,(t,l)=>{const s=e.getValueByPath(i,l);if(null!=s){if(r=!0,"object"==typeof s){if(!Array.isArray(s)&&"default"in s)return s.default;throw new Error("The provided theme path is invalid!")}return s}return t});return r?l:t};for(;o.length>0;){const e=o[o.length-1],r=e.value;if(t.isPlainObject(r)||Array.isArray(r))if(a.has(r))o.pop();else if(e.isProcessed){o.pop(),u.delete(r);let e=r;if(Array.isArray(r)){let t=null;for(let e=0;e<r.length;e++){const l=r[e],s=a.get(l)??l;s!==l&&(null===t&&(t=[...r]),t[e]=s)}null!==t&&(e=t)}else{let t=null;for(const e in r)if(Object.prototype.hasOwnProperty.call(r,e)){const s=r[e];let i=a.get(s)??s;if("function"==typeof i&&n){const e=i(l);i="string"==typeof e&&e.includes("theme.")?f(e):e}else"string"==typeof i&&i.includes("theme.")&&(i=f(i));i!==s&&(null===t&&(t={...r}),t[e]=i)}null!==t&&(e=t)}a.set(r,e)}else{e.isProcessed=!0,u.add(r);const l=Array.isArray(r)?r:Object.values(r);for(let e=l.length-1;e>=0;e--){const r=l[e];!t.isPlainObject(r)&&!Array.isArray(r)||u.has(r)||o.push({value:r,isProcessed:!1})}}else o.pop()}return a.get(r)??r};static resolveDefaultStyle=e=>{if(null==e||"string"==typeof e||"number"==typeof e||"boolean"==typeof e)return{};const{flex:r,...l}=e,s="flex"===l.display||"inline-flex"===l.display,n=!!(l.overflow||l.overflowY||l.overflowX),i=l.flexFlow?.includes("wrap")||"wrap"===l.flexWrap||"wrap-reverse"===l.flexWrap,o="flexShrink"in e&&void 0!==e.flexShrink,a=r?t.parseFlexShorthand(r):null;let u;if(!o)if(a)u=a.shrink;else if(s){if(!n){const e="column"===l.flexDirection||"column-reverse"===l.flexDirection,t="row"===l.flexDirection||"row-reverse"===l.flexDirection||!l.flexDirection;(e&&!i||t&&!i)&&(u=0)}}else u=0;return{flex:r,flexShrink:u,minHeight:0,minWidth:0,...l}}}exports.ThemeUtil=t;
|
|
@@ -1 +1 @@
|
|
|
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,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,
|
|
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,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,CA0CxH"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{useEffectEvent as e,useEffect as t,isValidElement as r,cloneElement as
|
|
2
|
+
import{useEffectEvent as e,useEffect as t,isValidElement as r,cloneElement as a}from"react";import{MountTrackerUtil as n}from"../util/mount-tracker.util.js";import{BaseNode as o}from"../core.node.js";function l({children:l,...s}){const{node:u,...c}=s,i=e(()=>{u.stableKey&&(o.elementCache.delete(u.stableKey),n.isMounted(u.stableKey)&&n.untrackMount(u.stableKey),o.cacheCleanupRegistry.unregister(u)),u.lastSignature=void 0});return t(()=>(u.stableKey&&n.trackMount(u.stableKey),()=>i()),[]),r(l)&&Object.keys(c).length>0?a(l,c):l}export{l as default};
|