@uistate/core 2.0.0 → 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 +53 -141
- 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,122 +1,68 @@
|
|
|
1
|
-
# @uistate/core
|
|
1
|
+
# @uistate/core v3.0.0
|
|
2
2
|
|
|
3
|
-
**author**: Ajdin Imsirovic <ajdika@live.com> (GitHub)
|
|
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
|
|
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
|
-
-
|
|
11
|
-
-
|
|
18
|
+
- 🚀 O(1) state updates using CSS custom properties
|
|
19
|
+
- 📉 Significant memory savings compared to virtual DOM approaches
|
|
12
20
|
- 🎯 Zero configuration
|
|
13
|
-
- 🔄 Automatic reactivity
|
|
21
|
+
- 🔄 Automatic reactivity through CSS cascade
|
|
14
22
|
- 🎨 Framework agnostic
|
|
15
|
-
- 📦 Tiny bundle size (~
|
|
16
|
-
-
|
|
17
|
-
-
|
|
23
|
+
- 📦 Tiny bundle size (~2KB)
|
|
24
|
+
- 🧩 Modular architecture with dedicated modules for CSS state and templates
|
|
25
|
+
- 📝 Declarative HTML-in-CSS templates
|
|
18
26
|
|
|
19
27
|
## Installation
|
|
20
28
|
|
|
21
29
|
```bash
|
|
22
|
-
# Install the core package
|
|
23
30
|
npm install @uistate/core
|
|
24
|
-
|
|
25
|
-
# Optional: Install performance monitoring
|
|
26
|
-
npm install @uistate/performance
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Quick Start
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
import { UIState } from '@uistate/core';
|
|
33
|
-
|
|
34
|
-
// Initialize state
|
|
35
|
-
UIState.init();
|
|
36
|
-
|
|
37
|
-
// Set state
|
|
38
|
-
UIState.setState('count', 0);
|
|
39
|
-
|
|
40
|
-
// Get state
|
|
41
|
-
const count = UIState.getState('count');
|
|
42
|
-
|
|
43
|
-
// Subscribe to changes
|
|
44
|
-
const unsubscribe = UIState.observe('count', (newValue) => {
|
|
45
|
-
console.log('Count changed:', newValue);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// React Hook
|
|
49
|
-
import { useUIState } from '@uistate/core/react';
|
|
50
|
-
|
|
51
|
-
function Counter() {
|
|
52
|
-
const [count, setCount] = useUIState('count', 0);
|
|
53
|
-
return (
|
|
54
|
-
<button onClick={() => setCount(count + 1)}>
|
|
55
|
-
Count: {count}
|
|
56
|
-
</button>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
31
|
```
|
|
60
32
|
|
|
61
33
|
## Why @uistate/core?
|
|
62
34
|
|
|
63
35
|
### Performance
|
|
64
36
|
|
|
65
|
-
- **
|
|
66
|
-
- **
|
|
67
|
-
- **Minimal Overhead**: No virtual DOM diffing
|
|
37
|
+
- **CSS-Driven Updates**: Leverages browser's CSS engine for optimal performance with O(1) complexity
|
|
38
|
+
- **DOM as Source of Truth**: Efficient state storage using CSS custom properties and data attributes
|
|
39
|
+
- **Minimal Overhead**: No virtual DOM diffing or shadow DOM needed
|
|
68
40
|
|
|
69
41
|
### Developer Experience
|
|
70
42
|
|
|
71
|
-
- **
|
|
72
|
-
- **
|
|
73
|
-
- **Framework Agnostic**: Works with any framework
|
|
43
|
+
- **Declarative API**: Define UI structure in CSS templates
|
|
44
|
+
- **Framework Agnostic**: Works with any framework or vanilla JavaScript
|
|
74
45
|
- **Zero Config**: No store setup, no reducers, no actions
|
|
46
|
+
- **CSS-Native**: Leverages the power of CSS selectors and the cascade
|
|
75
47
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
The `@uistate/performance` package provides detailed performance metrics for your application:
|
|
48
|
+
### Core Concepts
|
|
79
49
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// Start tracking performance
|
|
85
|
-
const tracker = PerformanceTracker.getInstance();
|
|
86
|
-
tracker.start();
|
|
87
|
-
|
|
88
|
-
// Optional: Add the performance display component to your React app
|
|
89
|
-
function App() {
|
|
90
|
-
return (
|
|
91
|
-
<div>
|
|
92
|
-
<YourApp />
|
|
93
|
-
<PerformanceDisplay />
|
|
94
|
-
</div>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
The performance tracker monitors:
|
|
100
|
-
- State update duration
|
|
101
|
-
- Component render time
|
|
102
|
-
- FPS (Frames Per Second)
|
|
103
|
-
- Memory usage
|
|
104
|
-
- Long task duration
|
|
50
|
+
- **Attribute-Driven State Inheritance (ADSI)**: State represented both as CSS variables and data attributes
|
|
51
|
+
- **Declarative Templates**: Define UI components directly in CSS
|
|
52
|
+
- **Automatic State Propagation**: State changes automatically update the UI
|
|
105
53
|
|
|
106
54
|
## Project Structure
|
|
107
55
|
|
|
108
56
|
```
|
|
109
57
|
@uistate/core/
|
|
110
|
-
├── src/
|
|
111
|
-
│ ├── index.
|
|
112
|
-
│ ├──
|
|
113
|
-
│
|
|
114
|
-
│
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
└──
|
|
118
|
-
├── traditional/ # Traditional Redux app
|
|
119
|
-
└── uistate/ # UIState implementation
|
|
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
|
|
120
66
|
```
|
|
121
67
|
|
|
122
68
|
## Browser Support
|
|
@@ -126,72 +72,38 @@ The performance tracker monitors:
|
|
|
126
72
|
- Safari 10.1+
|
|
127
73
|
- Edge 79+
|
|
128
74
|
|
|
129
|
-
#
|
|
75
|
+
# Core Ideas Behind UIstate
|
|
130
76
|
|
|
131
|
-
|
|
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.
|
|
132
78
|
|
|
133
79
|
## Key Components
|
|
134
80
|
|
|
135
|
-
###
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
type StateObserver<T> = (value: T) => void;
|
|
139
|
-
interface UIStateType { ... }
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
- Defines a type for state change observers (callbacks)
|
|
143
|
-
- Defines the interface for the state management system
|
|
144
|
-
|
|
145
|
-
## Core Functionality
|
|
146
|
-
|
|
147
|
-
The `UIState` object provides several key methods:
|
|
81
|
+
### UIstate Core
|
|
148
82
|
|
|
149
|
-
|
|
150
|
-
- Creates a style element in the document head
|
|
151
|
-
- Initializes a CSS stylesheet for managing custom properties
|
|
152
|
-
- Returns the UIState instance for chaining
|
|
83
|
+
The main UIstate object provides methods to manage state and templates:
|
|
153
84
|
|
|
154
|
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
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
|
|
158
90
|
|
|
159
|
-
###
|
|
160
|
-
- Retrieves values from CSS custom properties
|
|
161
|
-
- Attempts to parse JSON values back to their original type
|
|
162
|
-
- Falls back to raw string if parsing fails
|
|
91
|
+
### Template Manager
|
|
163
92
|
|
|
164
|
-
|
|
165
|
-
- Implements an observer pattern for state changes
|
|
166
|
-
- Returns a cleanup function to remove the observer
|
|
167
|
-
- Allows multiple observers per state key
|
|
93
|
+
The template manager provides tools for declarative UI rendering:
|
|
168
94
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
_sheet: CSSStyleSheet | null // Stores the stylesheet reference
|
|
173
|
-
_observers: Map<string, Set<StateObserver>> // Stores observers per key
|
|
174
|
-
```
|
|
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
|
|
175
98
|
|
|
176
99
|
## Key Features
|
|
177
100
|
|
|
178
101
|
1. Uses CSS custom properties as a storage mechanism, making state changes automatically trigger UI updates
|
|
179
|
-
2. Provides
|
|
180
|
-
3. Implements
|
|
181
|
-
4.
|
|
182
|
-
|
|
183
|
-
## Example Usage
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
UIState.init();
|
|
187
|
-
UIState.setState('theme', 'dark');
|
|
188
|
-
UIState.observe('theme', (newValue) => {
|
|
189
|
-
console.log('Theme changed to:', newValue);
|
|
190
|
-
});
|
|
191
|
-
const currentTheme = UIState.getState<string>('theme');
|
|
192
|
-
```
|
|
102
|
+
2. Provides a clear separation between state storage (CSS) and behavior (JavaScript)
|
|
103
|
+
3. Implements a pub/sub pattern for reactive updates
|
|
104
|
+
4. Leverages CSS templates for declarative UI definition
|
|
193
105
|
|
|
194
|
-
This implementation is particularly useful for
|
|
106
|
+
This implementation is particularly useful for building UI components with clean separation of concerns, optimal performance, and a fully declarative approach.
|
|
195
107
|
|
|
196
108
|
## Contributing
|
|
197
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();
|