@base-framework/atoms 1.0.64 → 1.0.66
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 +146 -0
- package/copilot.md +103 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -207,6 +207,152 @@ The callback function will be called when the data property changes. The callbac
|
|
|
207
207
|
}
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
+
### OnLoad and OnStateLoad Atoms
|
|
211
|
+
The OnLoad and OnStateLoad atoms are specialized versions that automatically watch for a 'loaded' property. OnLoad watches component data/context/state, while OnStateLoad specifically watches component state.
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
// OnLoad - watches for 'loaded' property in component data/context/state
|
|
215
|
+
Div({ class: "content-container" }, [
|
|
216
|
+
H1('My Content'),
|
|
217
|
+
|
|
218
|
+
// Shows content when loaded is true, nothing when false
|
|
219
|
+
OnLoad((loaded, element, parent) =>
|
|
220
|
+
Div({ class: "loaded-content" }, [
|
|
221
|
+
P('Content has been loaded!')
|
|
222
|
+
])
|
|
223
|
+
),
|
|
224
|
+
|
|
225
|
+
// With a fallback for when not loaded
|
|
226
|
+
OnLoad(
|
|
227
|
+
(loaded, element, parent) =>
|
|
228
|
+
Div({ class: "loaded-content" }, [
|
|
229
|
+
P('Content loaded successfully!')
|
|
230
|
+
]),
|
|
231
|
+
// Fallback content when not loaded
|
|
232
|
+
Div({ class: "loading-spinner" }, 'Loading...')
|
|
233
|
+
)
|
|
234
|
+
])
|
|
235
|
+
|
|
236
|
+
// OnStateLoad - specifically watches component state
|
|
237
|
+
Div({ class: "dashboard" }, [
|
|
238
|
+
OnStateLoad((loaded, element, parent) =>
|
|
239
|
+
Dashboard({ data: parent.state.dashboardData })
|
|
240
|
+
)
|
|
241
|
+
])
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### OnOpen and OnStateOpen Atoms
|
|
245
|
+
The OnOpen and OnStateOpen atoms watch for an 'open' property to show/hide content. Useful for modals, dropdowns, and collapsible content.
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
// OnOpen - watches for 'open' property in component data/context/state
|
|
249
|
+
Div({ class: "modal-container" }, [
|
|
250
|
+
Button({
|
|
251
|
+
click: (e, parent) => parent.data.open = true
|
|
252
|
+
}, 'Open Modal'),
|
|
253
|
+
|
|
254
|
+
// Modal only shows when open is true
|
|
255
|
+
OnOpen((open, element, parent) =>
|
|
256
|
+
Div({ class: "modal-overlay" }, [
|
|
257
|
+
Div({ class: "modal-content" }, [
|
|
258
|
+
H2('Modal Title'),
|
|
259
|
+
P('Modal content goes here'),
|
|
260
|
+
Button({
|
|
261
|
+
click: (e, parent) => parent.data.open = false
|
|
262
|
+
}, 'Close')
|
|
263
|
+
])
|
|
264
|
+
])
|
|
265
|
+
)
|
|
266
|
+
])
|
|
267
|
+
|
|
268
|
+
// OnStateOpen - specifically watches component state
|
|
269
|
+
Nav({ class: "navigation" }, [
|
|
270
|
+
Button({
|
|
271
|
+
click: (e, parent) => parent.state.open = !parent.state.open
|
|
272
|
+
}, 'Toggle Menu'),
|
|
273
|
+
|
|
274
|
+
OnStateOpen((open, element, parent) =>
|
|
275
|
+
Ul({ class: "nav-menu" }, [
|
|
276
|
+
Li(A({ href: "/home" }, 'Home')),
|
|
277
|
+
Li(A({ href: "/about" }, 'About')),
|
|
278
|
+
Li(A({ href: "/contact" }, 'Contact'))
|
|
279
|
+
])
|
|
280
|
+
)
|
|
281
|
+
])
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### If and IfState Atoms
|
|
285
|
+
The If and IfState atoms allow conditional rendering based on exact value matches. They take a property name, expected value, and callback function.
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
// If - watches component data/context/state for exact value match
|
|
289
|
+
Div({ class: "user-profile" }, [
|
|
290
|
+
H1('User Profile'),
|
|
291
|
+
|
|
292
|
+
// Show admin panel only when role equals 'admin'
|
|
293
|
+
If('role', 'admin', (role, element, parent) =>
|
|
294
|
+
Div({ class: "admin-panel" }, [
|
|
295
|
+
H2('Admin Controls'),
|
|
296
|
+
Button('Manage Users'),
|
|
297
|
+
Button('System Settings')
|
|
298
|
+
])
|
|
299
|
+
),
|
|
300
|
+
|
|
301
|
+
// Show different content based on subscription status
|
|
302
|
+
If('subscription', 'premium', (subscription, element, parent) =>
|
|
303
|
+
Div({ class: "premium-features" }, [
|
|
304
|
+
P('Premium Features Available'),
|
|
305
|
+
Button('Advanced Analytics'),
|
|
306
|
+
Button('Priority Support')
|
|
307
|
+
])
|
|
308
|
+
),
|
|
309
|
+
|
|
310
|
+
If('subscription', 'basic', (subscription, element, parent) =>
|
|
311
|
+
Div({ class: "upgrade-prompt" }, [
|
|
312
|
+
P('Upgrade to Premium for more features'),
|
|
313
|
+
Button('Upgrade Now')
|
|
314
|
+
])
|
|
315
|
+
)
|
|
316
|
+
])
|
|
317
|
+
|
|
318
|
+
// IfState - specifically watches component state for exact matches
|
|
319
|
+
Div({ class: "game-interface" }, [
|
|
320
|
+
IfState('gameStatus', 'playing', (status, element, parent) =>
|
|
321
|
+
Div({ class: "game-controls" }, [
|
|
322
|
+
Button('Pause Game'),
|
|
323
|
+
Button('Save Progress')
|
|
324
|
+
])
|
|
325
|
+
),
|
|
326
|
+
|
|
327
|
+
IfState('gameStatus', 'paused', (status, element, parent) =>
|
|
328
|
+
Div({ class: "pause-menu" }, [
|
|
329
|
+
Button('Resume Game'),
|
|
330
|
+
Button('Main Menu'),
|
|
331
|
+
Button('Quit Game')
|
|
332
|
+
])
|
|
333
|
+
),
|
|
334
|
+
|
|
335
|
+
IfState('gameStatus', 'gameOver', (status, element, parent) =>
|
|
336
|
+
Div({ class: "game-over" }, [
|
|
337
|
+
H2('Game Over!'),
|
|
338
|
+
P(`Final Score: ${parent.state.score}`),
|
|
339
|
+
Button('Play Again'),
|
|
340
|
+
Button('Main Menu')
|
|
341
|
+
])
|
|
342
|
+
)
|
|
343
|
+
])
|
|
344
|
+
|
|
345
|
+
// If with custom data source
|
|
346
|
+
Div({ class: "weather-widget" }, [
|
|
347
|
+
If(parent.weatherData, 'condition', 'sunny', (condition, element, parent) =>
|
|
348
|
+
Div({ class: "sunny-weather" }, [
|
|
349
|
+
Icon('sun'),
|
|
350
|
+
P('Perfect weather for outdoor activities!')
|
|
351
|
+
])
|
|
352
|
+
)
|
|
353
|
+
])
|
|
354
|
+
```
|
|
355
|
+
|
|
210
356
|
### Use Parent Atom
|
|
211
357
|
|
|
212
358
|
The UseParent atom allows for the parent component to be accessed in a child atom. This atom is useful when a child atom needs to access the parent component.
|
package/copilot.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Base Atoms - AI Coding Instructions
|
|
2
|
+
|
|
3
|
+
## Architecture Overview
|
|
4
|
+
This is an npm package that provides atomic HTML components for the Base Framework. It exports reusable, composable atoms that serve as building blocks for component-based architecture.
|
|
5
|
+
|
|
6
|
+
**Key Dependencies:**
|
|
7
|
+
- `@base-framework/base`: Core framework providing `Atom`, `Builder`, and `dataBinder`
|
|
8
|
+
- Built as ESM module with TypeScript declarations generated from JSDoc
|
|
9
|
+
|
|
10
|
+
## Core Patterns
|
|
11
|
+
|
|
12
|
+
### Atom Creation Patterns
|
|
13
|
+
Two primary patterns for creating atoms:
|
|
14
|
+
|
|
15
|
+
1. **Simple Function Atoms** (for basic HTML elements):
|
|
16
|
+
```javascript
|
|
17
|
+
const Meta = (props) => ({ ...props, tag: 'meta' });
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. **Atom Wrapper Functions** (for composable atoms):
|
|
21
|
+
```javascript
|
|
22
|
+
const Div = Atom((props, children) => Tag(props, children));
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Component Composition
|
|
26
|
+
Atoms use composition over inheritance. Children are passed as arrays:
|
|
27
|
+
```javascript
|
|
28
|
+
const SecondaryButton = Atom((props, children) => Button({
|
|
29
|
+
...props,
|
|
30
|
+
class: 'secondary-btn',
|
|
31
|
+
children
|
|
32
|
+
}));
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Special Atoms Architecture
|
|
36
|
+
Located in `/src/on/` and `/src/use/` directories:
|
|
37
|
+
|
|
38
|
+
- **On Atoms**: Conditional rendering based on data binding (`On`, `OnState`, `OnRoute`)
|
|
39
|
+
- **UseParent**: Provides access to parent component context
|
|
40
|
+
- Use **comment placeholders** to maintain DOM position during dynamic updates
|
|
41
|
+
|
|
42
|
+
## Development Workflows
|
|
43
|
+
|
|
44
|
+
### Build Process
|
|
45
|
+
```bash
|
|
46
|
+
npm run build # Builds dist/ with esbuild + generates TypeScript declarations
|
|
47
|
+
npm run prepublishOnly # Pre-publish build step
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### File Structure
|
|
51
|
+
- `src/atoms.js`: Main export file with all HTML element atoms
|
|
52
|
+
- `src/on/on.js`: Dynamic conditional rendering atoms
|
|
53
|
+
- `src/use/use.js`: Parent component access utilities
|
|
54
|
+
- `src/comment.js`: Comment placeholder utility
|
|
55
|
+
|
|
56
|
+
## Code Conventions
|
|
57
|
+
|
|
58
|
+
### JSDoc Documentation
|
|
59
|
+
All atoms require comprehensive JSDoc with proper type annotations:
|
|
60
|
+
```javascript
|
|
61
|
+
/**
|
|
62
|
+
* Creates a button element.
|
|
63
|
+
*
|
|
64
|
+
* @param {object} props - Properties for the element.
|
|
65
|
+
* @param {array} children - Children elements.
|
|
66
|
+
* @returns {object} - Returns an object representing the element.
|
|
67
|
+
*/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Event Handling Pattern
|
|
71
|
+
Event callbacks receive `(event, parent)` parameters for parent component access:
|
|
72
|
+
```javascript
|
|
73
|
+
Button({
|
|
74
|
+
click(event, parent) {
|
|
75
|
+
// Access parent component here
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Flexible Argument Handling
|
|
81
|
+
Atoms support multiple call patterns:
|
|
82
|
+
- Props only: `Div({class: 'text'})`
|
|
83
|
+
- Children only: `Div('text')` or `Div([childrenArray])`
|
|
84
|
+
- Both: `Div({class: 'text'}, children)`
|
|
85
|
+
|
|
86
|
+
## Critical Implementation Details
|
|
87
|
+
|
|
88
|
+
### Dynamic Rendering (On Atoms)
|
|
89
|
+
- Use comment placeholders to maintain DOM insertion points
|
|
90
|
+
- Handle previous element cleanup in `updateLayout` functions
|
|
91
|
+
- Support data binding to component data, context, or state
|
|
92
|
+
|
|
93
|
+
### Base Framework Integration
|
|
94
|
+
- Always import `Atom` from `@base-framework/base`
|
|
95
|
+
- Use `Builder.build()` and `Builder.removeNode()` for DOM manipulation
|
|
96
|
+
- Leverage `dataBinder` for reactive data connections
|
|
97
|
+
|
|
98
|
+
### TypeScript Support
|
|
99
|
+
- Enable `allowJs: true` and `checkJs: true` in tsconfig.json
|
|
100
|
+
- Generate declarations with `emitDeclarationOnly: true`
|
|
101
|
+
- Map Base Framework types in `paths` configuration
|
|
102
|
+
|
|
103
|
+
When working with this codebase, focus on maintaining the established patterns for atom creation, JSDoc documentation, and the flexible argument handling that allows atoms to work seamlessly within the Base Framework ecosystem.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@base-framework/atoms",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.66",
|
|
4
4
|
"description": "This will add default atoms to the base framework.",
|
|
5
5
|
"main": "./dist/atoms.js",
|
|
6
6
|
"scripts": {
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"files": [
|
|
36
36
|
"package.json",
|
|
37
37
|
"readme.md",
|
|
38
|
-
"dist"
|
|
38
|
+
"dist",
|
|
39
|
+
"copilot.md"
|
|
39
40
|
],
|
|
40
41
|
"exports": {
|
|
41
42
|
"./package.json": "./package.json",
|