@meonode/ui 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -3,284 +3,294 @@
3
3
  [![NPM version](https://img.shields.io/npm/v/@meonode/ui.svg?style=flat)](https://www.npmjs.com/package/@meonode/ui)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- `@meonode/ui` is a lightweight yet powerful utility for the programmatic creation and manipulation of React elements. It
7
- offers an enhanced, structured way to define components, manage props (separating CSS from DOM attributes), handle
8
- theming, and compose children *before* they are rendered by React. This provides greater control and flexibility,
9
- especially for dynamic UIs and design systems.
10
-
11
- ---
6
+ **Build React UIs with Type-Safe Fluency**
7
+ A structured approach to component composition with built-in theming, prop separation, and dynamic children handling.
8
+
9
+ ```tsx
10
+ // Quick Start Example
11
+ import { Component, Div, H1, Button } from '@meonode/ui';
12
+
13
+ const BlueButton = Component((props) =>
14
+ Button({
15
+ padding: '12px 24px',
16
+ borderRadius: '8px',
17
+ backgroundColor: 'dodgerblue',
18
+ color: 'white',
19
+ ...props
20
+ })
21
+ );
22
+
23
+ const App = Component(() =>
24
+ Div({
25
+ padding: '40px',
26
+ children: [
27
+ H1({ fontSize: '2rem' }, 'Welcome to Meonode'),
28
+ BlueButton({
29
+ onClick: () => alert('Hello World!'),
30
+ children: 'Get Started'
31
+ })
32
+ ]
33
+ })
34
+ );
35
+ ```
12
36
 
13
- ## Key Features
37
+ ## Why @meonode/ui?
14
38
 
15
- * **Programmatic React Element Construction:** Create complex React element trees using a fluent and intuitive API.
16
- * **Advanced Prop Handling:** Automatically separates CSS style properties from other DOM attributes, simplifying
17
- component logic.
18
- * **Integrated Theming System:** Pass theme objects down the tree and reference theme values (e.g.,
19
- `theme.colors.primary`) directly in style properties.
20
- * **Flexible Children Management:** Supports various child types, including primitives, other `@meonode/ui` nodes,
21
- standard React elements, and functions for dynamic rendering (function-as-child pattern).
22
- * **Type-Safe:** Written entirely in TypeScript, providing excellent autocompletion and compile-time safety.
23
- * **Seamless Integration:** Works with existing React components and fits naturally into any React workflow.
24
- * **`Component` HOC:** A higher-order component to easily wrap functions that return `@meonode/ui` instances, making
25
- them standard React components.
26
- * **Pre-built HTML Element Components:** Offers a suite of convenience functions (e.g., `Div`, `Span`, `H1`, `Button`) that wrap `Node()` for common HTML tags, streamlining development.
39
+ - 🎯 **Type-Safe Design** - Full TypeScript support with autocomplete for styles and themes
40
+ - 🎨 **CSS-in-JS Without Runtime** - Write styles directly in props with theme references
41
+ - 🧩 **Component-First Architecture** - Compose UIs from structured nodes instead of JSX
42
+ - 🌐 **Theme Propagation** - Contextual theming that works with any component structure
43
+ - **Zero Dependencies** - Lightweight core (under 15kb gzipped)
27
44
 
28
45
  ## Installation
29
46
 
30
- First, ensure you have `react` installed as a dependency.
31
-
32
-
33
- ```shell
34
- yarn add react @meonode/ui
47
+ ```bash
48
+ npm install @meonode/ui react
49
+ # or
50
+ yarn add @meonode/ui react
35
51
  ```
36
52
 
37
- To use the built-in integration with Material UI, install the following:
38
-
39
- ```shell
40
- yarn add react @mui/material @meonode/ui @meonode/mui
41
- ```
42
-
43
- ---
44
-
45
53
  ## Core Concepts
46
54
 
47
- ### `Node(element, props)`
48
-
49
- The primary factory function to create `@meonode/ui` instances (internally `BaseNode`).
50
-
51
- * `element`: The React element type (e.g., `'div'`, `MyReactComponent`, another `Node` instance).
52
- * `props`: An object containing properties for the element, including standard HTML attributes, event handlers, `children`, `theme`, and direct CSS style properties.
53
-
54
- ### `BaseNode`
55
-
56
- 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.
57
-
58
- ### `Component(componentFunction)`
59
-
60
- 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.
61
-
62
- ### Theming
63
-
64
- 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:
65
-
66
- ---
67
-
68
- ## Usage Examples
69
-
70
- ### 1. Basic Usage with `Node()`
71
-
72
- ### 2. Applying Styles Directly root Prop
73
-
74
- `@meonode/ui` intelligently separates CSS properties from other props. You can provide CSS properties directly at the root of the `props` object.
75
-
76
-
77
- ### 3. Using Themes
78
-
79
- Themes allow for centralized styling and easy reuse of design tokens.
80
-
81
- ### 4. Handling Children
82
-
83
- `@meonode/ui` offers flexible ways to define children:
84
-
85
- **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'`.
55
+ ### 1. Component Creation
86
56
 
87
- ### 5. Creating Reusable Components with `Component` HOC
57
+ Create elements using the `Node` factory or pre-built components:
88
58
 
89
- The `Component` HOC simplifies creating standard React components from functions that return `@meonode/ui` nodes.
59
+ ```tsx
60
+ import { Node, Div, H1 } from '@meonode/ui';
90
61
 
91
- ### 6. Using with Existing React Components
92
-
93
- You can easily incorporate existing React components into your `@meonode/ui` structures.
94
-
95
-
96
- ### 7. Using Pre-built HTML Components
62
+ // Using Node factory
63
+ const Card = Node('div', {
64
+ padding: '20px',
65
+ borderRadius: '8px',
66
+ boxShadow: '0 2px 12px rgba(0,0,0,0.1)'
67
+ });
97
68
 
98
- `@meonode/ui` includes a set of pre-built components for common HTML elements, making it even quicker to construct your UI. These are essentially convenience wrappers around the `Node()` factory, accepting the same props (including direct CSS styles, `theme` references, and `children`).
69
+ // Using pre-built components
70
+ const Header = () =>
71
+ Div({
72
+ padding: '20px',
73
+ backgroundColor: 'navy',
74
+ children: H1({ color: 'white' }, 'App Header')
75
+ });
76
+ ```
99
77
 
100
- Examples include: `Div`, `Span`, `P`, `H1`-`H6`, `Img`, `Button`, `Input`, `Form`, layout components like `Column`, `Row`, `Grid`, `Center`, and many more.
78
+ ### 2. Theming System
101
79
 
102
- ```ts
103
- import { Component, Div, H1, P, Button } from '@meonode/ui';
80
+ Define and consume themes with dot-notation:
104
81
 
105
- // Define a simple theme (for example purposes)
106
- const myTheme = {
82
+ ```tsx
83
+ const theme = {
107
84
  colors: {
108
- primary: 'dodgerblue',
109
- secondary: 'lightgray',
110
- surface: '#ffffff',
111
- text: '#333333',
112
- textOnPrimary: 'white',
85
+ primary: '#2196F3',
86
+ text: {
87
+ primary: '#1A237E',
88
+ secondary: '#455A64'
89
+ }
113
90
  },
114
91
  spacing: {
115
- small: '8px',
116
- medium: '16px',
117
- large: '24px',
118
- },
119
- typography: {
120
- h1Size: '2.5rem',
121
- pSize: '1rem',
122
- },
123
- borders: {
124
- radius: '4px',
125
- thin: '1px solid #cccccc',
92
+ md: '16px',
93
+ lg: '24px'
126
94
  }
127
95
  };
128
96
 
129
- const MyStyledCard = Component(() => {
130
- return Div({
131
- theme: myTheme, // Apply the theme to this node and its descendants
132
- padding: 'theme.spacing.large',
133
- backgroundColor: 'theme.colors.surface',
134
- borderRadius: 'theme.borders.radius',
135
- boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
136
- maxWidth: '400px',
137
- margin: 'theme.spacing.medium auto', // Center the card
138
- border: 'theme.borders.thin',
97
+ const ThemedCard = Component(() =>
98
+ Div({
99
+ theme,
100
+ padding: 'theme.spacing.lg',
101
+ backgroundColor: 'theme.colors.primary',
139
102
  children: [
140
- H1({
141
- fontSize: 'theme.typography.h1Size',
142
- color: 'theme.colors.primary',
143
- marginBottom: 'theme.spacing.medium',
144
- children: 'Interactive Card',
145
- }),
146
- P({
147
- fontSize: 'theme.typography.pSize',
148
- color: 'theme.colors.text',
149
- lineHeight: '1.6',
150
- marginBottom: 'theme.spacing.large',
151
- children: 'This card is built using pre-built HTML components from @meonode/ui, styled with a custom theme.',
152
- }),
153
- Button({
154
- backgroundColor: 'theme.colors.primary',
155
- color: 'theme.colors.textOnPrimary',
156
- padding: 'theme.spacing.small theme.spacing.medium',
157
- border: 'none',
158
- borderRadius: 'theme.borders.radius',
159
- fontSize: 'theme.typography.pSize',
160
- cursor: 'pointer',
161
- children: 'Learn More',
162
- onClick: () => alert('Button clicked!'),
163
- // Example of hover style (though direct CSS-in-JS hover is more complex without a helper)
164
- // For simple cases, you might rely on global CSS or a more advanced styling solution.
165
- // This is a placeholder to show where you might think about interactions.
166
- // Real hover effects would typically be handled by CSS classes or a more robust styling library.
167
- }),
168
- ],
169
- });
170
- });
103
+ H1({ color: 'theme.colors.text.primary' }, 'Themed Title'),
104
+ P({ color: 'theme.colors.text.secondary' }, 'Content...')
105
+ ]
106
+ })
107
+ );
171
108
  ```
172
109
 
173
- To use it in a React application (example):
174
- ```ts
175
- import React from 'react';
176
- import ReactDOM from 'react-dom/client';
177
-
178
- const root = ReactDOM.createRoot(document.getElementById('root'));
179
- root.render(MyStyledCard());
110
+ ### 3. Prop Handling
111
+
112
+ Automatic separation of CSS props from DOM attributes:
113
+
114
+ ```tsx
115
+ const ProfileCard = Component(({ user }) =>
116
+ Div({
117
+ // CSS Props
118
+ padding: '20px',
119
+ borderRadius: '8px',
120
+ // DOM Props
121
+ ariaRole: 'article',
122
+ tabIndex: 0,
123
+ // Children
124
+ children: `Welcome ${user.name}!`
125
+ })
126
+ );
180
127
  ```
181
128
 
182
- ---
183
-
184
- ## Usage Implementation
185
-
186
- The example implementation can be seen in the docs folder:
187
- 1. [Basic Usage](./docs/basic-usage.md)
188
- 2. [Conditional Component With Hook](./docs/conditional-component-with-hook.md)
189
-
190
- ---
191
-
192
- ## API Overview
193
-
194
- ### `Node<E extends NodeElement>(element: E, props: Partial<NodeProps<E>> = {}): BaseNodeInstance<E>`
129
+ ## Key Features
195
130
 
196
- * The main factory function to create `BaseNode` instances.
197
- * `element`: A string (e.g., 'div'), a React component, or another `BaseNodeInstance`.
198
- * `props`: Object containing element properties, styles, `children`, and `theme`.
199
- * Returns: A `BaseNodeInstance`. Call `.render()` on it to get a renderable React element.
131
+ | Feature | Description |
132
+ |------------------------|-----------------------------------------------------------------------------|
133
+ | **Smart Prop Merge** | CSS properties are automatically merged with style object |
134
+ | **Theme Resolution** | `theme.` references resolve through component hierarchy |
135
+ | **Type Safety** | Autocomplete for CSS properties and theme paths |
136
+ | **HOC Support** | Wrap existing components with `Component()` for seamless integration |
137
+ | **Dynamic Children** | Function-as-child pattern with automatic theme propagation |
200
138
 
201
- ### `Component<T extends Record<string, any>>(component: (props: T) => BaseNodeInstance<any> | ReactNode): (props: T) => ReactNode`
139
+ ## Advanced Usage
202
140
 
203
- * A Higher-Order Component.
204
- * `component`: A function that accepts props and returns a `BaseNodeInstance` or any `ReactNode`.
205
- * Returns: A standard React functional component.
141
+ ### Component Composition
206
142
 
207
- ### `BaseNodeInstance.render(): ReactNode`
143
+ ```tsx
144
+ const Dashboard = Component(() =>
145
+ Div({
146
+ display: 'grid',
147
+ gridTemplateColumns: '1fr 3fr',
148
+ gap: '20px',
149
+ children: [
150
+ Sidebar({
151
+ width: '240px',
152
+ items: navItems
153
+ }),
154
+ MainContent({
155
+ padding: '40px',
156
+ children: AnalyticsChart({ dataset })
157
+ })
158
+ ]
159
+ })
160
+ );
161
+ ```
208
162
 
209
- * A method on `BaseNodeInstance` (the object returned by `Node()`).
210
- * Converts the internal `BaseNode` representation into a standard, renderable React Node tree using `React.createElement`.
163
+ ### With Conditional Children That Contains Hook
211
164
 
212
- ---
165
+ also add this
213
166
 
214
- ## How It Works (Briefly)
167
+ ```ts
215
168
 
216
- 1. **Node Creation:**
217
- - When you call `Node(element, props)`, a `BaseNode` instance is created.
169
+ // Wraps a hook-capable component into a BaseNode-compatible Client Component
170
+ import { Component, Column, Row, Div, P } from '@meonode/ui'
171
+ import { useState, useEffect } from 'react'
172
+
173
+ // Shared theme object passed into components. This may be written in a different file and imported.
174
+ const theme = {
175
+ background: { primary: 'lightgreen', secondary: 'lightyellow' },
176
+ }
177
+
178
+ // Exported component rendered via <Component /> (client wrapper)
179
+ export default Component(() => {
180
+ // React hook for conditional UI
181
+ const [showDetails, setShowDetails] = useState(false)
182
+
183
+ // Declarative layout using Column as root container
184
+ return Column({
185
+ theme,
186
+ padding: 20,
187
+ gap: 15,
188
+ children: [
189
+ // Header row with a toggle button
190
+ Row({
191
+ gap: 10,
192
+ children: [
193
+ Div({
194
+ onClick: () => setShowDetails(prev => !prev),
195
+ style: {
196
+ cursor: 'pointer',
197
+ userSelect: 'none',
198
+ padding: '10px 20px',
199
+ backgroundColor: 'theme.background.primary', // Node engine will handle this
200
+ borderRadius: 5,
201
+ fontWeight: 'bold',
202
+ },
203
+ children: showDetails ? 'Hide Details' : 'Show Details',
204
+ }),
205
+ ],
206
+ }),
218
207
 
219
- 2. **Props Processing:**
220
- - The `BaseNode` constructor analyzes the `props`
221
- - It uses helper functions (`getCSSProps`, `getDOMProps`) to separate valid CSS style properties from other DOM
222
- attributes
223
- - If a `theme` (or `nodeTheme`) is provided, style values like `'theme.colors.primary'` are resolved against this
224
- theme object using `getValueByPath`
208
+ // Conditionally render DetailComponent via function wrapper
209
+ // Ensures it's treated as a renderable function (deferred React class or element that is NOT called directly)
210
+ // Node engine will handle this like magic
211
+ showDetails && (() => DetailComponent({ info: 'Here are some details!' })), // Works like `Component(() => DetailComponent({ info: 'Here some details!' }))`,
212
+ showDetails && DetailComponent({ info: 'Here are some details!' })).render() // Works
213
+ ],
214
+ })
215
+ })
216
+
217
+ // A stateful detail section using useEffect and styled Div
218
+ const DetailComponent = ({ info }: { info: string }) => {
219
+ useEffect(() => {
220
+ console.log('DetailComponent mounted')
221
+ return () => {
222
+ console.log('DetailComponent unmounted')
223
+ }
224
+ }, [])
225
225
 
226
- 3. **Children Processing:**
227
- - Children are recursively processed
228
- - If a child is a primitive, React element, or another `BaseNode`, it's adapted
229
- - Function children are wrapped in a special internal `_functionRenderer` `BaseNode`. This renderer calls the function
230
- during the render phase and ensures that if the function returns a `BaseNode`, the parent's theme is correctly
231
- propagated to it
226
+ return Div({
227
+ padding: 15,
228
+ border: '1px solid green',
229
+ borderRadius: 6,
230
+ backgroundColor: 'theme.background.secondary', // Node engine will handle this
231
+ children: P({ children: info }),
232
+ })
233
+ }
232
234
 
233
- 4. **Rendering:**
234
- - The `render()` method on a `BaseNode` instance recursively traverses its structure
235
- - Calls `render()` on any child `BaseNode`s
236
- - Ultimately uses `React.createElement` to construct the final tree of React elements
237
- - The `nodeTheme` prop is removed before passing props to `createElement`
235
+ ```
238
236
 
239
- ---
237
+ ### Material UI Integration
240
238
 
241
- ## TypeScript Support
239
+ ```bash
240
+ yarn add @meonode/mui @mui/material
241
+ ```
242
242
 
243
- `@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.
243
+ ```ts
244
+ import { MuiButton, MuiTextField } from '@meonode/mui';
244
245
 
245
- Key types like `NodeElement`, `NodeProps`, and `BaseNodeInstance` are available if you need to work with them directly, though typically `Node` and `Component` are sufficient.
246
+ const MuiLoginForm = Component(() =>
247
+ Div({
248
+ maxWidth: '400px',
249
+ margin: '0 auto',
250
+ children: [
251
+ MuiTextField({
252
+ label: 'Email',
253
+ fullWidth: true,
254
+ margin: 'normal'
255
+ }),
256
+ MuiTextField({
257
+ label: 'Password',
258
+ type: 'password',
259
+ fullWidth: true,
260
+ margin: 'normal'
261
+ }),
262
+ MuiButton({
263
+ variant: 'contained',
264
+ color: 'primary',
265
+ children: 'Sign In'
266
+ })
267
+ ]
268
+ })
269
+ );
270
+ ```
246
271
 
247
- ---
272
+ ## API Reference
248
273
 
249
- ## When to Use `@meonode/ui`?
274
+ ### Core Functions
250
275
 
251
- * Perfect for design systems and UI libraries requiring consistent structure, theming, and maintainable patterns
252
- * Ideal for generating dynamic UIs from configurations, metadata, schemas or API responses
253
- * Powerful solution for centralized styling logic, prop transformations and runtime customization
254
- * Excellent choice for complex component hierarchies needing programmatic manipulation
255
- * Great alternative to JSX when you prefer a more functional programming approach
276
+ | Function | Parameters | Description |
277
+ |----------------|-----------------------------------------|-------------------------------------------------|
278
+ | `Node` | `element: string \| Component`, `props` | Creates a new UI node |
279
+ | `Component` | `(props) => Node \| ReactNode` | Converts node trees to React components |
256
280
 
257
- ---
258
281
 
259
282
  ## Contributing
260
283
 
261
- Contributions are welcome! Please feel free to contact me on discord: **[l7aromeo](https://discordapp.com/users/704803255561224264)**.
284
+ We welcome contributions! Please follow these steps:
285
+ 1. Fork the repository
286
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
287
+ 3. Commit your changes
288
+ 4. Push to the branch
289
+ 5. Open a Pull Request
262
290
 
263
- ---
264
-
265
- ## [License](https://github.com/l7aromeo/meonode-ui/blob/main/LICENSE)
266
-
267
- The MIT License (MIT)
268
- Copyright (c) 2025 Ukasyah Rahmatullah Zada
291
+ Contact me on [Discord](https://discordapp.com/users/704803255561224264) for discussions.
269
292
 
270
- Permission is hereby granted, free of charge, to any person obtaining a copy
271
- of this software and associated documentation files (the "Software"), to deal
272
- in the Software without restriction, including without limitation the rights
273
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
274
- copies of the Software, and to permit persons to whom the Software is
275
- furnished to do so, subject to the following conditions:
276
-
277
- The above copyright notice and this permission notice shall be included in all
278
- copies or substantial portions of the Software.
293
+ ---
279
294
 
280
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
281
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
282
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
283
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
284
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
285
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
286
- SOFTWARE.
295
+ **MIT Licensed** | Copyright © 2024 Ukasyah Rahmatullah Zada
296
+ *Empowering developers to build better UIs*
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meonode/ui",
3
- "description": "`@meonode/ui` is a lightweight yet powerful utility for the programmatic creation and manipulation of React elements. It offers an enhanced, structured way to define components, manage props (separating CSS from DOM attributes), handle theming, and compose children *before* they are rendered by React. This provides greater control and flexibility, especially for dynamic UIs and design systems.",
4
- "version": "0.1.2",
3
+ "description": "A structured approach to component composition with built-in theming, prop separation, and dynamic children handling.",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "main": "./dist/main.js",
7
7
  "types": "./dist/main.d.ts",
@@ -13,7 +13,6 @@
13
13
  },
14
14
  "files": [
15
15
  "dist",
16
- "docs",
17
16
  "package.json",
18
17
  "LICENSE",
19
18
  "README.md"
@@ -1,63 +0,0 @@
1
- ```ts
2
- // Component wraps a React Server Component into a Client Component
3
- // Think of it like a factory that transforms JSX-like node definitions into actual React components
4
- import { Component, Column, Row, Div, Img, P } from '@meonode/ui'
5
-
6
- const theme = { background: { primary: 'red', secondary: 'blue' } }
7
-
8
- // This is the actual exported component
9
- export default Component(() => {
10
- return Card({
11
- title: 'Genshin Impact',
12
- subtitle: 'Adventure awaits!',
13
- imageUrl: 'https://upload-os-bbs.mihoyo.com/upload/2021/03/05/75387538/f37ce39baf72ffb84cb5c0040bdcbf10_2126420710320647353.jpg',
14
- })
15
- })
16
-
17
- // This function returns a structured layout using html.node helpers only
18
- const Card = ({ title, subtitle, imageUrl }: { title: string; subtitle: string; imageUrl: string }) =>
19
- Column({
20
- theme,
21
- // Column is just a <div> with `display: flex; flex-direction: column`
22
- borderRadius: 10,
23
- overflow: 'hidden',
24
- border: '1px solid theme.background.primary', // Can use theme references
25
- width: 300,
26
- children: [
27
- // Img translates to a real <img> tag
28
- Img({
29
- src: imageUrl,
30
- width: '100%',
31
- height: 180,
32
- style: {
33
- objectFit: 'cover', // Ensures the image fills the area without distortion
34
- },
35
- }),
36
- // Div is a basic <div> wrapper
37
- Div({
38
- padding: 10,
39
- backgroundColor: 'theme.background.secondary',
40
- children: Column({
41
- gap: 5,
42
- children: [
43
- // P maps directly to <p>, with styling
44
- P({
45
- style: {
46
- fontSize: 18,
47
- fontWeight: 600,
48
- },
49
- children: title,
50
- }),
51
- P({
52
- style: {
53
- fontSize: 14,
54
- color: 'gray',
55
- },
56
- children: subtitle,
57
- }),
58
- ],
59
- }),
60
- }),
61
- ],
62
- })
63
- ```
@@ -1,68 +0,0 @@
1
- ```ts
2
-
3
- // Wraps a hook-capable component into a BaseNode-compatible Client Component
4
- import { Component, Column, Row, Div, P } from '@meonode/ui'
5
- import { useState, useEffect } from 'react'
6
-
7
- // Shared theme object passed into components. This may be written in a different file and imported.
8
- const theme = {
9
- background: { primary: 'lightgreen', secondary: 'lightyellow' },
10
- }
11
-
12
- // Exported component rendered via <Component /> (client wrapper)
13
- export default Component(() => {
14
- // React hook for conditional UI
15
- const [showDetails, setShowDetails] = useState(false)
16
-
17
- // Declarative layout using Column as root container
18
- return Column({
19
- theme,
20
- padding: 20,
21
- gap: 15,
22
- children: [
23
- // Header row with a toggle button
24
- Row({
25
- gap: 10,
26
- children: [
27
- Div({
28
- onClick: () => setShowDetails(prev => !prev),
29
- style: {
30
- cursor: 'pointer',
31
- userSelect: 'none',
32
- padding: '10px 20px',
33
- backgroundColor: 'theme.background.primary', // Node engine will handle this
34
- borderRadius: 5,
35
- fontWeight: 'bold',
36
- },
37
- children: showDetails ? 'Hide Details' : 'Show Details',
38
- }),
39
- ],
40
- }),
41
-
42
- // Conditionally render DetailComponent via function wrapper
43
- // Ensures it's treated as a renderable function (deferred React class or element that is NOT called directly)
44
- // Node engine will handle this like magic
45
- showDetails ? () => DetailComponent({ info: 'Here are some details!' }) : null,
46
- ],
47
- })
48
- })
49
-
50
- // A stateful detail section using useEffect and styled Div
51
- const DetailComponent = ({ info }: { info: string }) => {
52
- useEffect(() => {
53
- console.log('DetailComponent mounted')
54
- return () => {
55
- console.log('DetailComponent unmounted')
56
- }
57
- }, [])
58
-
59
- return Div({
60
- padding: 15,
61
- border: '1px solid green',
62
- borderRadius: 6,
63
- backgroundColor: 'theme.background.secondary', // Node engine will handle this
64
- children: P({ children: info }),
65
- })
66
- }
67
-
68
- ```