@uistate/core 2.0.1 → 3.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/README.md +39 -103
- package/package.json +1 -1
- package/src/cssState.js +53 -9
- package/src/index.js +282 -40
- package/src/stateInspector.js +140 -0
- package/src/stateSerializer.js +204 -0
- package/src/telemetryPlugin.js +638 -0
- package/src/templateManager.js +119 -0
package/README.md
CHANGED
|
@@ -1,72 +1,35 @@
|
|
|
1
|
-
# @uistate/core
|
|
1
|
+
# @uistate/core v3.0.0
|
|
2
2
|
|
|
3
3
|
**author**: Ajdin Imsirovic <ajdika@live.com> (GitHub)
|
|
4
4
|
**maintainer**: uistate <ajdika.i@gmail.com> (npm)
|
|
5
5
|
|
|
6
|
-
High-performance UI state management using CSS custom properties and ADSI (Attribute-Driven State Inheritance). Focused heavily on DX and performance.
|
|
6
|
+
High-performance UI state management using CSS custom properties and ADSI (Attribute-Driven State Inheritance). Focused heavily on DX and performance with a fully declarative approach.
|
|
7
|
+
|
|
8
|
+
## What's New in v3.0.0
|
|
9
|
+
|
|
10
|
+
- 🔄 Fully declarative state management approach
|
|
11
|
+
- 🧩 Enhanced template system with CSS-based templates
|
|
12
|
+
- 🚀 Improved performance through optimized state propagation
|
|
13
|
+
- 📦 New state serialization and inspection capabilities
|
|
14
|
+
- 🔍 Telemetry plugin for better debugging
|
|
7
15
|
|
|
8
16
|
## Features
|
|
9
17
|
|
|
10
|
-
- 🚀
|
|
18
|
+
- 🚀 O(1) state updates using CSS custom properties
|
|
11
19
|
- 📉 Significant memory savings compared to virtual DOM approaches
|
|
12
20
|
- 🎯 Zero configuration
|
|
13
21
|
- 🔄 Automatic reactivity through CSS cascade
|
|
14
22
|
- 🎨 Framework agnostic
|
|
15
23
|
- 📦 Tiny bundle size (~2KB)
|
|
16
|
-
- 🧩 Modular architecture with dedicated modules for CSS state and
|
|
24
|
+
- 🧩 Modular architecture with dedicated modules for CSS state and templates
|
|
25
|
+
- 📝 Declarative HTML-in-CSS templates
|
|
17
26
|
|
|
18
27
|
## Installation
|
|
19
28
|
|
|
20
29
|
```bash
|
|
21
|
-
# Install the core package
|
|
22
30
|
npm install @uistate/core
|
|
23
31
|
```
|
|
24
32
|
|
|
25
|
-
## Quick Start
|
|
26
|
-
|
|
27
|
-
```javascript
|
|
28
|
-
import { cssState, eventState } from '@uistate/core';
|
|
29
|
-
|
|
30
|
-
// Initialize state
|
|
31
|
-
cssState.init();
|
|
32
|
-
|
|
33
|
-
// Set state via CSS variables
|
|
34
|
-
cssState.set('--counter-value', '0');
|
|
35
|
-
|
|
36
|
-
// Get state
|
|
37
|
-
const count = parseInt(cssState.get('--counter-value'));
|
|
38
|
-
|
|
39
|
-
// Subscribe to changes
|
|
40
|
-
const unsubscribe = eventState.on('counter:change', (newValue) => {
|
|
41
|
-
console.log('Counter changed:', newValue);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Set state with an attribute
|
|
45
|
-
document.documentElement.dataset.counterValue = count + 1;
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### HTML Usage Example
|
|
49
|
-
|
|
50
|
-
```html
|
|
51
|
-
<button data-counter-value="0" id="counter-btn">Count: 0</button>
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
```css
|
|
55
|
-
[data-counter-value] {
|
|
56
|
-
/* Style based on state */
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
document.getElementById('counter-btn').addEventListener('click', () => {
|
|
62
|
-
const btn = document.getElementById('counter-btn');
|
|
63
|
-
const currentValue = parseInt(btn.dataset.counterValue);
|
|
64
|
-
btn.dataset.counterValue = currentValue + 1;
|
|
65
|
-
btn.textContent = `Count: ${currentValue + 1}`;
|
|
66
|
-
eventState.emit('counter:change', currentValue + 1);
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
33
|
## Why @uistate/core?
|
|
71
34
|
|
|
72
35
|
### Performance
|
|
@@ -77,7 +40,7 @@ document.getElementById('counter-btn').addEventListener('click', () => {
|
|
|
77
40
|
|
|
78
41
|
### Developer Experience
|
|
79
42
|
|
|
80
|
-
- **
|
|
43
|
+
- **Declarative API**: Define UI structure in CSS templates
|
|
81
44
|
- **Framework Agnostic**: Works with any framework or vanilla JavaScript
|
|
82
45
|
- **Zero Config**: No store setup, no reducers, no actions
|
|
83
46
|
- **CSS-Native**: Leverages the power of CSS selectors and the cascade
|
|
@@ -85,21 +48,21 @@ document.getElementById('counter-btn').addEventListener('click', () => {
|
|
|
85
48
|
### Core Concepts
|
|
86
49
|
|
|
87
50
|
- **Attribute-Driven State Inheritance (ADSI)**: State represented both as CSS variables and data attributes
|
|
88
|
-
- **
|
|
89
|
-
- **
|
|
51
|
+
- **Declarative Templates**: Define UI components directly in CSS
|
|
52
|
+
- **Automatic State Propagation**: State changes automatically update the UI
|
|
90
53
|
|
|
91
54
|
## Project Structure
|
|
92
55
|
|
|
93
56
|
```
|
|
94
57
|
@uistate/core/
|
|
95
|
-
├── src/
|
|
96
|
-
│ ├── index.js
|
|
97
|
-
│ ├── cssState.js
|
|
98
|
-
│ ├──
|
|
99
|
-
│
|
|
100
|
-
└──
|
|
101
|
-
|
|
102
|
-
└──
|
|
58
|
+
├── src/ # Core library
|
|
59
|
+
│ ├── index.js # Main entry
|
|
60
|
+
│ ├── cssState.js # CSS variables management
|
|
61
|
+
│ ├── templateManager.js # Declarative template management
|
|
62
|
+
│ ├── stateInspector.js # State inspection tools
|
|
63
|
+
│ └── stateSerializer.js # State serialization
|
|
64
|
+
└── examples/ # Example applications
|
|
65
|
+
└── 001-slider-and-cards/ # Advanced slider example
|
|
103
66
|
```
|
|
104
67
|
|
|
105
68
|
## Browser Support
|
|
@@ -111,63 +74,36 @@ document.getElementById('counter-btn').addEventListener('click', () => {
|
|
|
111
74
|
|
|
112
75
|
# Core Ideas Behind UIstate
|
|
113
76
|
|
|
114
|
-
UIstate is a JavaScript-based UI state management system that leverages CSS custom properties and
|
|
77
|
+
UIstate is a JavaScript-based UI state management system that leverages CSS custom properties and HTML-in-CSS templates for a fully declarative approach to building UIs.
|
|
115
78
|
|
|
116
79
|
## Key Components
|
|
117
80
|
|
|
118
|
-
###
|
|
119
|
-
|
|
120
|
-
The `cssState` module provides methods to manage state through CSS custom properties:
|
|
121
|
-
|
|
122
|
-
```javascript
|
|
123
|
-
// Initialize CSS state management
|
|
124
|
-
cssState.init();
|
|
125
|
-
|
|
126
|
-
// Set a CSS custom property
|
|
127
|
-
cssState.set('--theme-mode', 'dark');
|
|
128
|
-
|
|
129
|
-
// Get a CSS custom property value
|
|
130
|
-
const theme = cssState.get('--theme-mode');
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### eventState
|
|
81
|
+
### UIstate Core
|
|
134
82
|
|
|
135
|
-
The
|
|
83
|
+
The main UIstate object provides methods to manage state and templates:
|
|
136
84
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
85
|
+
- **init()**: Initialize the UIstate system
|
|
86
|
+
- **setState()**: Set state values
|
|
87
|
+
- **getState()**: Get state values
|
|
88
|
+
- **subscribe()**: Subscribe to state changes
|
|
89
|
+
- **observe()**: Observe state paths for changes
|
|
142
90
|
|
|
143
|
-
|
|
144
|
-
eventState.emit('theme:change', 'light');
|
|
145
|
-
|
|
146
|
-
// Clean up listeners
|
|
147
|
-
eventState.off('theme:change');
|
|
148
|
-
```
|
|
91
|
+
### Template Manager
|
|
149
92
|
|
|
150
|
-
|
|
93
|
+
The template manager provides tools for declarative UI rendering:
|
|
151
94
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// Initialize components from templates
|
|
156
|
-
templateManager.init();
|
|
157
|
-
|
|
158
|
-
// Create a component from a template
|
|
159
|
-
const button = templateManager.createFromTemplate('button-template');
|
|
160
|
-
document.body.appendChild(button);
|
|
161
|
-
```
|
|
95
|
+
- **renderTemplateFromCss()**: Render UI components from CSS-defined templates
|
|
96
|
+
- **registerActions()**: Register event handlers for UI components
|
|
97
|
+
- **attachDelegation()**: Set up event delegation for efficient event handling
|
|
162
98
|
|
|
163
99
|
## Key Features
|
|
164
100
|
|
|
165
101
|
1. Uses CSS custom properties as a storage mechanism, making state changes automatically trigger UI updates
|
|
166
102
|
2. Provides a clear separation between state storage (CSS) and behavior (JavaScript)
|
|
167
103
|
3. Implements a pub/sub pattern for reactive updates
|
|
168
|
-
4. Leverages
|
|
104
|
+
4. Leverages CSS templates for declarative UI definition
|
|
169
105
|
|
|
170
|
-
This implementation is particularly useful for building UI components with clean separation of concerns and
|
|
106
|
+
This implementation is particularly useful for building UI components with clean separation of concerns, optimal performance, and a fully declarative approach.
|
|
171
107
|
|
|
172
108
|
## Contributing
|
|
173
109
|
|
package/package.json
CHANGED
package/src/cssState.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* UIstate - CSS-based state management module
|
|
2
|
+
* UIstate - CSS-based state management module with integrated serialization
|
|
3
3
|
* Part of the UIstate declarative state management system
|
|
4
4
|
* Uses CSS custom properties and data attributes for state representation
|
|
5
|
+
* Includes built-in serialization for complex objects and special characters
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
+
import StateSerializer from './stateSerializer.js';
|
|
8
|
+
|
|
9
|
+
const createCssState = (initialState = {}, serializer = StateSerializer) => {
|
|
7
10
|
const state = {
|
|
8
11
|
_sheet: null,
|
|
9
12
|
_observers: new Map(),
|
|
13
|
+
_serializer: serializer,
|
|
10
14
|
|
|
11
15
|
init() {
|
|
12
16
|
if (!this._sheet) {
|
|
@@ -27,20 +31,52 @@ const createCssState = (initialState = {}) => {
|
|
|
27
31
|
},
|
|
28
32
|
|
|
29
33
|
setState(key, value) {
|
|
30
|
-
|
|
34
|
+
// Use serializer for CSS variables
|
|
35
|
+
const cssValue = this._serializer.serialize(key, value);
|
|
31
36
|
document.documentElement.style.setProperty(`--${key}`, cssValue);
|
|
32
|
-
|
|
37
|
+
|
|
38
|
+
// For data attributes, handle objects specially
|
|
39
|
+
if (value !== null && value !== undefined) {
|
|
40
|
+
if (typeof value === 'object') {
|
|
41
|
+
// Use the serializer for the data attribute value
|
|
42
|
+
document.documentElement.setAttribute(`data-${key}`, this._serializer.serialize(key, value));
|
|
43
|
+
|
|
44
|
+
// For objects, also set each property as a separate data attribute
|
|
45
|
+
if (!Array.isArray(value)) {
|
|
46
|
+
Object.entries(value).forEach(([propKey, propValue]) => {
|
|
47
|
+
const attributeKey = `data-${key}-${propKey.toLowerCase()}`;
|
|
48
|
+
if (propValue !== null && propValue !== undefined) {
|
|
49
|
+
if (typeof propValue === 'object') {
|
|
50
|
+
document.documentElement.setAttribute(
|
|
51
|
+
attributeKey,
|
|
52
|
+
this._serializer.serialize(`${key}.${propKey}`, propValue)
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
document.documentElement.setAttribute(attributeKey, propValue);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
document.documentElement.removeAttribute(attributeKey);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
// For primitives, set directly
|
|
64
|
+
document.documentElement.setAttribute(`data-${key}`, value);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
document.documentElement.removeAttribute(`data-${key}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
33
70
|
this._notifyObservers(key, value);
|
|
34
71
|
return value;
|
|
35
72
|
},
|
|
36
73
|
|
|
37
74
|
getState(key) {
|
|
38
75
|
const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
76
|
+
if (!value) return '';
|
|
77
|
+
|
|
78
|
+
// Use serializer for deserialization
|
|
79
|
+
return this._serializer.deserialize(key, value);
|
|
44
80
|
},
|
|
45
81
|
|
|
46
82
|
observe(key, callback) {
|
|
@@ -69,6 +105,14 @@ const createCssState = (initialState = {}) => {
|
|
|
69
105
|
}
|
|
70
106
|
},
|
|
71
107
|
|
|
108
|
+
// Add serializer configuration method
|
|
109
|
+
configureSerializer(config) {
|
|
110
|
+
if (this._serializer.configure) {
|
|
111
|
+
this._serializer.configure(config);
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
},
|
|
115
|
+
|
|
72
116
|
// Clean up resources
|
|
73
117
|
destroy() {
|
|
74
118
|
this._observers.clear();
|