@uistate/core 1.0.0 → 2.0.1

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
@@ -1,119 +1,105 @@
1
1
  # @uistate/core
2
2
 
3
- High-performance UI state management using CSS custom properties. 44% faster than traditional state management solutions with 12.5% lower memory usage.
3
+ **author**: Ajdin Imsirovic <ajdika@live.com> (GitHub)
4
+ **maintainer**: uistate <ajdika.i@gmail.com> (npm)
5
+
6
+ High-performance UI state management using CSS custom properties and ADSI (Attribute-Driven State Inheritance). Focused heavily on DX and performance.
4
7
 
5
8
  ## Features
6
9
 
7
- - 🚀 44% faster state updates than Redux
8
- - 📉 12.5% lower memory usage
10
+ - 🚀 Potentially O(1) state updates using CSS custom properties
11
+ - 📉 Significant memory savings compared to virtual DOM approaches
9
12
  - 🎯 Zero configuration
10
- - 🔄 Automatic reactivity
13
+ - 🔄 Automatic reactivity through CSS cascade
11
14
  - 🎨 Framework agnostic
12
- - 📦 Tiny bundle size (~1KB)
13
- - 💪 Full TypeScript support
14
- - 📊 Optional performance monitoring
15
+ - 📦 Tiny bundle size (~2KB)
16
+ - 🧩 Modular architecture with dedicated modules for CSS state and events
15
17
 
16
18
  ## Installation
17
19
 
18
20
  ```bash
19
21
  # Install the core package
20
22
  npm install @uistate/core
21
-
22
- # Optional: Install performance monitoring
23
- npm install @uistate/performance
24
23
  ```
25
24
 
26
25
  ## Quick Start
27
26
 
28
- ```typescript
29
- import { UIState } from '@uistate/core';
27
+ ```javascript
28
+ import { cssState, eventState } from '@uistate/core';
30
29
 
31
30
  // Initialize state
32
- UIState.init();
31
+ cssState.init();
33
32
 
34
- // Set state
35
- UIState.setState('count', 0);
33
+ // Set state via CSS variables
34
+ cssState.set('--counter-value', '0');
36
35
 
37
36
  // Get state
38
- const count = UIState.getState('count');
37
+ const count = parseInt(cssState.get('--counter-value'));
39
38
 
40
39
  // Subscribe to changes
41
- const unsubscribe = UIState.observe('count', (newValue) => {
42
- console.log('Count changed:', newValue);
40
+ const unsubscribe = eventState.on('counter:change', (newValue) => {
41
+ console.log('Counter changed:', newValue);
43
42
  });
44
43
 
45
- // React Hook
46
- import { useUIState } from '@uistate/core/react';
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
+ ```
47
53
 
48
- function Counter() {
49
- const [count, setCount] = useUIState('count', 0);
50
- return (
51
- <button onClick={() => setCount(count + 1)}>
52
- Count: {count}
53
- </button>
54
- );
54
+ ```css
55
+ [data-counter-value] {
56
+ /* Style based on state */
55
57
  }
56
58
  ```
57
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
+
58
70
  ## Why @uistate/core?
59
71
 
60
72
  ### Performance
61
73
 
62
- - **44% Faster Updates**: Leverages browser's CSS engine for optimal performance
63
- - **12.5% Lower Memory**: Efficient state storage using CSS custom properties
64
- - **Minimal Overhead**: No virtual DOM diffing for state updates
74
+ - **CSS-Driven Updates**: Leverages browser's CSS engine for optimal performance with O(1) complexity
75
+ - **DOM as Source of Truth**: Efficient state storage using CSS custom properties and data attributes
76
+ - **Minimal Overhead**: No virtual DOM diffing or shadow DOM needed
65
77
 
66
78
  ### Developer Experience
67
79
 
68
- - **Simple API**: Just `setState`, `getState`, and `observe`
69
- - **TypeScript Support**: Full type safety and autocompletion
70
- - **Framework Agnostic**: Works with any framework
80
+ - **Simple API**: Modular `cssState` and `eventState` for clear separation of concerns
81
+ - **Framework Agnostic**: Works with any framework or vanilla JavaScript
71
82
  - **Zero Config**: No store setup, no reducers, no actions
83
+ - **CSS-Native**: Leverages the power of CSS selectors and the cascade
72
84
 
73
- ## Performance Monitoring
74
-
75
- The `@uistate/performance` package provides detailed performance metrics for your application:
85
+ ### Core Concepts
76
86
 
77
- ```typescript
78
- import { PerformanceTracker } from '@uistate/performance';
79
- import { PerformanceDisplay } from '@uistate/performance';
80
-
81
- // Start tracking performance
82
- const tracker = PerformanceTracker.getInstance();
83
- tracker.start();
84
-
85
- // Optional: Add the performance display component to your React app
86
- function App() {
87
- return (
88
- <div>
89
- <YourApp />
90
- <PerformanceDisplay />
91
- </div>
92
- );
93
- }
94
- ```
95
-
96
- The performance tracker monitors:
97
- - State update duration
98
- - Component render time
99
- - FPS (Frames Per Second)
100
- - Memory usage
101
- - Long task duration
87
+ - **Attribute-Driven State Inheritance (ADSI)**: State represented both as CSS variables and data attributes
88
+ - **Hierarchical State Machines**: Model complex UI states with nested state machines
89
+ - **CSS-Driven State Derivation**: Derive complex states using CSS without JavaScript
102
90
 
103
91
  ## Project Structure
104
92
 
105
93
  ```
106
94
  @uistate/core/
107
95
  ├── src/ # Core library
108
- │ ├── index.ts # Main entry
109
- │ ├── UIState.ts # Core implementation
110
- └── react/ # React bindings
111
- └── index.ts # React hooks
112
- ├── packages/
113
- │ └── performance/ # Performance monitoring package
96
+ │ ├── index.js # Main entry
97
+ │ ├── cssState.js # CSS variables management
98
+ ├── eventState.js # Event-based state transitions
99
+ └── templateManager.js # Component management
114
100
  └── examples/ # Example applications
115
- ├── traditional/ # Traditional Redux app
116
- └── uistate/ # UIState implementation
101
+ ├── basic/ # Simple examples (range sliders, toggles, etc)
102
+ └── advanced/ # Advanced patterns and techniques
117
103
  ```
118
104
 
119
105
  ## Browser Support
@@ -123,6 +109,66 @@ The performance tracker monitors:
123
109
  - Safari 10.1+
124
110
  - Edge 79+
125
111
 
112
+ # Core Ideas Behind UIstate
113
+
114
+ UIstate is a JavaScript-based UI state management system that leverages CSS custom properties and data attributes as the storage mechanism, paired with event-based state transitions.
115
+
116
+ ## Key Components
117
+
118
+ ### cssState
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
134
+
135
+ The `eventState` module provides an event system for state transitions:
136
+
137
+ ```javascript
138
+ // Listen for state changes
139
+ eventState.on('theme:change', (newTheme) => {
140
+ console.log('Theme changed to:', newTheme);
141
+ });
142
+
143
+ // Trigger state changes
144
+ eventState.emit('theme:change', 'light');
145
+
146
+ // Clean up listeners
147
+ eventState.off('theme:change');
148
+ ```
149
+
150
+ ### templateManager
151
+
152
+ The `templateManager` module helps with component initialization and templating:
153
+
154
+ ```javascript
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
+ ```
162
+
163
+ ## Key Features
164
+
165
+ 1. Uses CSS custom properties as a storage mechanism, making state changes automatically trigger UI updates
166
+ 2. Provides a clear separation between state storage (CSS) and behavior (JavaScript)
167
+ 3. Implements a pub/sub pattern for reactive updates
168
+ 4. Leverages the CSS cascade for hierarchical state inheritance
169
+
170
+ This implementation is particularly useful for building UI components with clean separation of concerns and optimal performance.
171
+
126
172
  ## Contributing
127
173
 
128
174
  We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
package/package.json CHANGED
@@ -1,20 +1,15 @@
1
1
  {
2
2
  "name": "@uistate/core",
3
- "version": "1.0.0",
4
- "description": "High-performance UI state management using CSS custom properties",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
3
+ "version": "2.0.1",
4
+ "description": "High-performance UI state management using CSS custom properties and ADSI (Attribute-Driven State Inheritance)",
5
+ "main": "src/index.js",
6
+ "module": "src/index.js",
8
7
  "files": [
9
- "dist",
10
8
  "src"
11
9
  ],
12
10
  "scripts": {
13
- "build": "tsup src/index.ts --format cjs,esm --dts",
14
11
  "test": "jest",
15
- "lint": "eslint src",
16
- "typecheck": "tsc --noEmit",
17
- "prepare": "npm run build"
12
+ "lint": "eslint src"
18
13
  },
19
14
  "keywords": [
20
15
  "state-management",
@@ -23,7 +18,10 @@
23
18
  "css",
24
19
  "performance"
25
20
  ],
26
- "author": "Imsirovic Ajdin",
21
+ "author": "Ajdin Imsirovic <ajdika@live.com> (GitHub)",
22
+ "contributors": [
23
+ "uistate <ajdika.i@gmail.com> (npm)"
24
+ ],
27
25
  "license": "MIT",
28
26
  "repository": {
29
27
  "type": "git",
@@ -37,18 +35,9 @@
37
35
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
38
36
  },
39
37
  "devDependencies": {
40
- "@types/node": "^20.0.0",
41
- "@types/react": "^18.0.0",
42
- "@typescript-eslint/eslint-plugin": "^6.0.0",
43
- "@typescript-eslint/parser": "^6.0.0",
44
38
  "eslint": "^8.0.0",
45
39
  "jest": "^29.0.0",
46
- "jest-environment-jsdom": "^29.0.0",
47
- "@types/jest": "^29.0.0",
48
- "ts-jest": "^29.0.0",
49
- "tsup": "^8.0.0",
50
- "typescript": "^5.0.0",
51
- "react": "^18.0.0"
40
+ "jest-environment-jsdom": "^29.0.0"
52
41
  },
53
42
  "sideEffects": false
54
43
  }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * UIstate - CSS-based state management module
3
+ * Part of the UIstate declarative state management system
4
+ * Uses CSS custom properties and data attributes for state representation
5
+ */
6
+ const createCssState = (initialState = {}) => {
7
+ const state = {
8
+ _sheet: null,
9
+ _observers: new Map(),
10
+
11
+ init() {
12
+ if (!this._sheet) {
13
+ const style = document.createElement('style');
14
+ document.head.appendChild(style);
15
+ this._sheet = style.sheet;
16
+ this._addRule(':root {}');
17
+ }
18
+
19
+ // Initialize with any provided state
20
+ if (initialState && typeof initialState === 'object') {
21
+ Object.entries(initialState).forEach(([key, value]) => {
22
+ this.setState(key, value);
23
+ });
24
+ }
25
+
26
+ return this;
27
+ },
28
+
29
+ setState(key, value) {
30
+ const cssValue = typeof value === 'string' ? value : JSON.stringify(value);
31
+ document.documentElement.style.setProperty(`--${key}`, cssValue);
32
+ document.documentElement.setAttribute(`data-${key}`, value);
33
+ this._notifyObservers(key, value);
34
+ return value;
35
+ },
36
+
37
+ getState(key) {
38
+ const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
39
+ try {
40
+ return JSON.parse(value);
41
+ } catch (e) {
42
+ return value;
43
+ }
44
+ },
45
+
46
+ observe(key, callback) {
47
+ if (!this._observers.has(key)) {
48
+ this._observers.set(key, new Set());
49
+ }
50
+ this._observers.get(key).add(callback);
51
+ return () => {
52
+ const observers = this._observers.get(key);
53
+ if (observers) {
54
+ observers.delete(callback);
55
+ }
56
+ };
57
+ },
58
+
59
+ _notifyObservers(key, value) {
60
+ const observers = this._observers.get(key);
61
+ if (observers) {
62
+ observers.forEach(cb => cb(value));
63
+ }
64
+ },
65
+
66
+ _addRule(rule) {
67
+ if (this._sheet) {
68
+ this._sheet.insertRule(rule, this._sheet.cssRules.length);
69
+ }
70
+ },
71
+
72
+ // Clean up resources
73
+ destroy() {
74
+ this._observers.clear();
75
+ // The style element will remain in the DOM
76
+ // as removing it would affect the UI state
77
+ }
78
+ };
79
+
80
+ return state.init();
81
+ };
82
+
83
+ // Legacy singleton for backward compatibility
84
+ const CssState = createCssState();
85
+
86
+ export default createCssState;
87
+ export { createCssState, CssState };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * UIstate - Event-based hierarchical state management module
3
+ * Part of the UIstate declarative state management system
4
+ * Uses DOM events for pub/sub with hierarchical path support
5
+ */
6
+
7
+ const createEventState = (initial = {}) => {
8
+ // Clone the initial state to avoid direct mutations to the passed object
9
+ const store = JSON.parse(JSON.stringify(initial));
10
+
11
+ // Create a dedicated DOM element to use as an event bus
12
+ const bus = document.createElement("x-store");
13
+
14
+ // Optional: Keep the bus element off the actual DOM for better encapsulation
15
+ // but this isn't strictly necessary for functionality
16
+ bus.style.display = "none";
17
+ document.documentElement.appendChild(bus);
18
+
19
+ return {
20
+ // get a value from the store by path
21
+ get: (path) => {
22
+ if (!path) return store;
23
+ return path
24
+ .split(".")
25
+ .reduce(
26
+ (obj, prop) =>
27
+ obj && obj[prop] !== undefined ? obj[prop] : undefined,
28
+ store
29
+ );
30
+ },
31
+
32
+ // set a value in the store by path
33
+ set: (path, value) => {
34
+ if(!path) return;
35
+
36
+ // Update the store
37
+ let target = store;
38
+ const parts = path.split(".");
39
+ const last = parts.pop();
40
+
41
+ // Create the path if it doesn't exist
42
+ parts.forEach((part) => {
43
+ if (!target[part] || typeof target[part] !== "object") {
44
+ target[part] = {};
45
+ }
46
+ target = target[part];
47
+ });
48
+
49
+ // Set the value
50
+ target[last] = value;
51
+
52
+ // Notify subscribers with a DOM event
53
+ bus.dispatchEvent(new CustomEvent(path, { detail: value }));
54
+
55
+ // Also dispatch events for parent paths to support wildcards
56
+ if (parts.length > 0) {
57
+ let parentPath = "";
58
+ for (const part of parts) {
59
+ parentPath = parentPath ? `${parentPath}.${part}` : part;
60
+ bus.dispatchEvent(
61
+ new CustomEvent(`${parentPath}.*`, {
62
+ detail: { path, value },
63
+ })
64
+ );
65
+ }
66
+
67
+ // Dispatch root wildcard for any state change
68
+ bus.dispatchEvent(
69
+ new CustomEvent("*", {
70
+ detail: { path, value},
71
+ })
72
+ );
73
+ }
74
+
75
+ return value;
76
+ },
77
+
78
+ // Subscribe to changes on a path
79
+ subscribe: (path, callback) => {
80
+ if (!path || typeof callback !== "function") return () => {};
81
+
82
+ const handler = (e) => callback(e.detail, path);
83
+ bus.addEventListener(path, handler);
84
+
85
+ return () => bus.removeEventListener(path, handler);
86
+ },
87
+
88
+ // Optional method to clean up resources
89
+ destroy: () => {
90
+ if (bus.parentNode) {
91
+ bus.parentNode.removeChild(bus);
92
+ }
93
+ },
94
+ };
95
+ };
96
+
97
+ export default createEventState;
98
+ export { createEventState };
package/src/index.js ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * UIstate - Declarative state management for the web
3
+ *
4
+ * A unified system that combines CSS and Event-based state management with templating
5
+ * Integrates CSS variables, event-based state, and template management for optimal performance
6
+ */
7
+ import { createCssState } from './cssState.js';
8
+ import { createEventState } from './eventState.js';
9
+ import { createTemplateManager } from './templateManager.js';
10
+
11
+ const createUnifiedState = (initialState = {}) => {
12
+ // Initialize state store
13
+ const store = JSON.parse(JSON.stringify(initialState));
14
+
15
+ // Create the CSS state manager
16
+ const cssState = createCssState(initialState);
17
+
18
+ // Create the event state manager with the same initial state
19
+ const eventState = createEventState(initialState);
20
+
21
+ // Create a unified API
22
+ const unifiedState = {
23
+ _isNotifying: false, // Flag to prevent recursive notifications
24
+
25
+ // Get state with hierarchical path support
26
+ getState(path) {
27
+ if (!path) return store;
28
+
29
+ // Try to get from event state first (faster)
30
+ const value = eventState.get(path);
31
+
32
+ if (value !== undefined) return value;
33
+
34
+ // Fall back to CSS variable (for values set outside this API)
35
+ const cssPath = path.replace(/\./g, "-");
36
+ return cssState.getState(cssPath);
37
+ },
38
+
39
+ // Set state with hierarchical path support
40
+ setState(path, value) {
41
+ // Prevent recursive notifications
42
+ if (this._isNotifying) return value;
43
+
44
+ this._isNotifying = true;
45
+
46
+ try {
47
+ // Update event state
48
+ eventState.set(path, value);
49
+
50
+ // Update CSS state (convert dots to dashes for CSS variables)
51
+ const cssPath = path.replace(/\./g, "-");
52
+ cssState.setState(cssPath, value);
53
+
54
+ return value;
55
+ } finally {
56
+ this._isNotifying = false;
57
+ }
58
+ },
59
+
60
+ // Subscribe to state changes with support for wildcards
61
+ subscribe(path, callback) {
62
+ return eventState.subscribe(path, callback);
63
+ },
64
+
65
+ // Observe CSS state changes (simpler API, no wildcards)
66
+ observe(key, callback) {
67
+ return cssState.observe(key, callback);
68
+ },
69
+
70
+ // Clean up resources
71
+ destroy() {
72
+ cssState.destroy();
73
+ eventState.destroy();
74
+ }
75
+ };
76
+
77
+ return unifiedState;
78
+ };
79
+
80
+ // Create a singleton instance of the unified state
81
+ const UnifiedState = createUnifiedState();
82
+
83
+ // Create a template manager connected to the unified state
84
+ const TemplateManager = createTemplateManager(UnifiedState);
85
+
86
+ // Create a combined API for backward compatibility
87
+ const UIstate = {
88
+ ...UnifiedState,
89
+
90
+ // Add template manager methods
91
+ handlers: TemplateManager.handlers,
92
+ onAction: TemplateManager.onAction.bind(TemplateManager),
93
+ attachDelegation: TemplateManager.attachDelegation.bind(TemplateManager),
94
+ mount: TemplateManager.mount.bind(TemplateManager),
95
+
96
+ // Initialize both systems
97
+ init() {
98
+ // Attach event delegation to document body
99
+ this.attachDelegation(document.body);
100
+ return this;
101
+ }
102
+ };
103
+
104
+ export default UIstate;
105
+ export {
106
+ createUnifiedState,
107
+ UnifiedState,
108
+ createTemplateManager,
109
+ TemplateManager,
110
+ UIstate
111
+ };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * TemplateManager - Component mounting and event delegation
3
+ * Handles HTML templating, component mounting, and event delegation
4
+ */
5
+
6
+ const createTemplateManager = (stateManager) => {
7
+ const manager = {
8
+ handlers: {},
9
+
10
+ onAction(action, handler) {
11
+ this.handlers[action] = handler;
12
+ return this;
13
+ },
14
+
15
+ attachDelegation(root = document.body) {
16
+ root.addEventListener('click', e => {
17
+ const target = e.target.closest('[data-action]');
18
+ if (!target) return;
19
+
20
+ const action = target.dataset.action;
21
+ if (!action) return;
22
+
23
+ const handler = this.handlers[action];
24
+ if (typeof handler === 'function') {
25
+ handler(e);
26
+ } else if (target.dataset.value !== undefined && stateManager) {
27
+ // If we have a state manager, use it to update state
28
+ stateManager.setState(action, target.dataset.value);
29
+ }
30
+ });
31
+ return this;
32
+ },
33
+
34
+ mount(componentName, container) {
35
+ const tpl = document.getElementById(`${componentName}-template`);
36
+ if (!tpl) throw new Error(`Template not found: ${componentName}-template`);
37
+ const clone = tpl.content.cloneNode(true);
38
+
39
+ function resolvePlaceholders(fragment) {
40
+ Array.from(fragment.querySelectorAll('*')).forEach(el => {
41
+ const tag = el.tagName.toLowerCase();
42
+ if (tag.endsWith('-placeholder')) {
43
+ const name = tag.replace('-placeholder','');
44
+ const childTpl = document.getElementById(`${name}-template`);
45
+ if (!childTpl) throw new Error(`Template not found: ${name}-template`);
46
+ const childClone = childTpl.content.cloneNode(true);
47
+ resolvePlaceholders(childClone);
48
+ el.replaceWith(childClone);
49
+ }
50
+ });
51
+ }
52
+
53
+ resolvePlaceholders(clone);
54
+ container.appendChild(clone);
55
+ return clone.firstElementChild;
56
+ },
57
+
58
+ // Helper to create a reactive component with automatic updates
59
+ createComponent(name, renderFn, stateKeys = []) {
60
+ if (!stateManager) {
61
+ throw new Error('State manager is required for reactive components');
62
+ }
63
+
64
+ // Create template element if it doesn't exist
65
+ let tpl = document.getElementById(`${name}-template`);
66
+ if (!tpl) {
67
+ tpl = document.createElement('template');
68
+ tpl.id = `${name}-template`;
69
+ document.body.appendChild(tpl);
70
+ }
71
+
72
+ // Initial render
73
+ tpl.innerHTML = renderFn(stateManager);
74
+
75
+ // Set up observers for reactive updates
76
+ if (stateKeys.length > 0) {
77
+ stateKeys.forEach(key => {
78
+ stateManager.observe(key, () => {
79
+ tpl.innerHTML = renderFn(stateManager);
80
+ });
81
+ });
82
+ }
83
+
84
+ return {
85
+ mount: (container) => this.mount(name, container)
86
+ };
87
+ }
88
+ };
89
+
90
+ return manager;
91
+ };
92
+
93
+ // Create a standalone instance that doesn't depend on any state manager
94
+ const TemplateManager = createTemplateManager();
95
+
96
+ export default createTemplateManager;
97
+ export { createTemplateManager, TemplateManager };
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Imsirovic Ajdin
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/dist/index.d.mts DELETED
@@ -1,16 +0,0 @@
1
- type StateObserver<T = any> = (value: T) => void;
2
- interface UIStateType {
3
- _sheet: CSSStyleSheet | null;
4
- _observers: Map<string, Set<StateObserver>>;
5
- init(): UIStateType;
6
- setState<T>(key: string, value: T): void;
7
- getState<T>(key: string): T;
8
- observe<T>(key: string, callback: StateObserver<T>): () => void;
9
- _notifyObservers<T>(key: string, value: T): void;
10
- _addRule(rule: string): void;
11
- }
12
- declare const UIState: UIStateType;
13
-
14
- declare function useUIState<T>(key: string, initialValue: T): [T, (value: T) => void];
15
-
16
- export { UIState, useUIState };
package/dist/index.d.ts DELETED
@@ -1,16 +0,0 @@
1
- type StateObserver<T = any> = (value: T) => void;
2
- interface UIStateType {
3
- _sheet: CSSStyleSheet | null;
4
- _observers: Map<string, Set<StateObserver>>;
5
- init(): UIStateType;
6
- setState<T>(key: string, value: T): void;
7
- getState<T>(key: string): T;
8
- observe<T>(key: string, callback: StateObserver<T>): () => void;
9
- _notifyObservers<T>(key: string, value: T): void;
10
- _addRule(rule: string): void;
11
- }
12
- declare const UIState: UIStateType;
13
-
14
- declare function useUIState<T>(key: string, initialValue: T): [T, (value: T) => void];
15
-
16
- export { UIState, useUIState };
package/dist/index.js DELETED
@@ -1,107 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- UIState: () => UIState_default,
24
- useUIState: () => useUIState
25
- });
26
- module.exports = __toCommonJS(index_exports);
27
-
28
- // src/UIState.ts
29
- var UIState = {
30
- _sheet: null,
31
- _observers: /* @__PURE__ */ new Map(),
32
- init() {
33
- if (!this._sheet) {
34
- const style = document.createElement("style");
35
- document.head.appendChild(style);
36
- this._sheet = style.sheet;
37
- this._addRule(":root {}");
38
- }
39
- return this;
40
- },
41
- setState(key, value) {
42
- const cssValue = typeof value === "string" ? value : JSON.stringify(value);
43
- document.documentElement.style.setProperty(`--${key}`, cssValue);
44
- this._notifyObservers(key, value);
45
- },
46
- getState(key) {
47
- const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
48
- try {
49
- return JSON.parse(value);
50
- } catch (e) {
51
- return value;
52
- }
53
- },
54
- observe(key, callback) {
55
- var _a;
56
- if (!this._observers.has(key)) {
57
- this._observers.set(key, /* @__PURE__ */ new Set());
58
- }
59
- (_a = this._observers.get(key)) == null ? void 0 : _a.add(callback);
60
- return () => {
61
- var _a2;
62
- (_a2 = this._observers.get(key)) == null ? void 0 : _a2.delete(callback);
63
- };
64
- },
65
- _notifyObservers(key, value) {
66
- var _a;
67
- (_a = this._observers.get(key)) == null ? void 0 : _a.forEach(
68
- (callback) => callback(value)
69
- );
70
- },
71
- _addRule(rule) {
72
- if (this._sheet) {
73
- this._sheet.insertRule(rule, this._sheet.cssRules.length);
74
- }
75
- }
76
- };
77
- var UIState_default = UIState;
78
-
79
- // src/react/index.ts
80
- var import_react = require("react");
81
- function useUIState(key, initialValue) {
82
- (0, import_react.useEffect)(() => {
83
- UIState_default.init();
84
- }, []);
85
- const [state, setState] = (0, import_react.useState)(() => {
86
- try {
87
- const value = UIState_default.getState(key);
88
- return value !== void 0 ? value : initialValue;
89
- } catch (e) {
90
- return initialValue;
91
- }
92
- });
93
- (0, import_react.useEffect)(() => {
94
- return UIState_default.observe(key, (value) => {
95
- setState(value);
96
- });
97
- }, [key]);
98
- const setUIState = (value) => {
99
- UIState_default.setState(key, value);
100
- };
101
- return [state, setUIState];
102
- }
103
- // Annotate the CommonJS export names for ESM import in node:
104
- 0 && (module.exports = {
105
- UIState,
106
- useUIState
107
- });
package/dist/index.mjs DELETED
@@ -1,79 +0,0 @@
1
- // src/UIState.ts
2
- var UIState = {
3
- _sheet: null,
4
- _observers: /* @__PURE__ */ new Map(),
5
- init() {
6
- if (!this._sheet) {
7
- const style = document.createElement("style");
8
- document.head.appendChild(style);
9
- this._sheet = style.sheet;
10
- this._addRule(":root {}");
11
- }
12
- return this;
13
- },
14
- setState(key, value) {
15
- const cssValue = typeof value === "string" ? value : JSON.stringify(value);
16
- document.documentElement.style.setProperty(`--${key}`, cssValue);
17
- this._notifyObservers(key, value);
18
- },
19
- getState(key) {
20
- const value = getComputedStyle(document.documentElement).getPropertyValue(`--${key}`).trim();
21
- try {
22
- return JSON.parse(value);
23
- } catch (e) {
24
- return value;
25
- }
26
- },
27
- observe(key, callback) {
28
- var _a;
29
- if (!this._observers.has(key)) {
30
- this._observers.set(key, /* @__PURE__ */ new Set());
31
- }
32
- (_a = this._observers.get(key)) == null ? void 0 : _a.add(callback);
33
- return () => {
34
- var _a2;
35
- (_a2 = this._observers.get(key)) == null ? void 0 : _a2.delete(callback);
36
- };
37
- },
38
- _notifyObservers(key, value) {
39
- var _a;
40
- (_a = this._observers.get(key)) == null ? void 0 : _a.forEach(
41
- (callback) => callback(value)
42
- );
43
- },
44
- _addRule(rule) {
45
- if (this._sheet) {
46
- this._sheet.insertRule(rule, this._sheet.cssRules.length);
47
- }
48
- }
49
- };
50
- var UIState_default = UIState;
51
-
52
- // src/react/index.ts
53
- import { useState, useEffect } from "react";
54
- function useUIState(key, initialValue) {
55
- useEffect(() => {
56
- UIState_default.init();
57
- }, []);
58
- const [state, setState] = useState(() => {
59
- try {
60
- const value = UIState_default.getState(key);
61
- return value !== void 0 ? value : initialValue;
62
- } catch (e) {
63
- return initialValue;
64
- }
65
- });
66
- useEffect(() => {
67
- return UIState_default.observe(key, (value) => {
68
- setState(value);
69
- });
70
- }, [key]);
71
- const setUIState = (value) => {
72
- UIState_default.setState(key, value);
73
- };
74
- return [state, setUIState];
75
- }
76
- export {
77
- UIState_default as UIState,
78
- useUIState
79
- };
package/src/UIState.ts DELETED
@@ -1,68 +0,0 @@
1
- type StateObserver<T = any> = (value: T) => void;
2
-
3
- interface UIStateType {
4
- _sheet: CSSStyleSheet | null;
5
- _observers: Map<string, Set<StateObserver>>;
6
- init(): UIStateType;
7
- setState<T>(key: string, value: T): void;
8
- getState<T>(key: string): T;
9
- observe<T>(key: string, callback: StateObserver<T>): () => void;
10
- _notifyObservers<T>(key: string, value: T): void;
11
- _addRule(rule: string): void;
12
- }
13
-
14
- const UIState: UIStateType = {
15
- _sheet: null,
16
- _observers: new Map(),
17
-
18
- init() {
19
- if (!this._sheet) {
20
- const style = document.createElement('style');
21
- document.head.appendChild(style);
22
- this._sheet = style.sheet;
23
- this._addRule(':root {}');
24
- }
25
- return this;
26
- },
27
-
28
- setState<T>(key: string, value: T): void {
29
- const cssValue = typeof value === 'string' ? value : JSON.stringify(value);
30
- document.documentElement.style.setProperty(`--${key}`, cssValue);
31
- this._notifyObservers(key, value);
32
- },
33
-
34
- getState<T>(key: string): T {
35
- const value = getComputedStyle(document.documentElement)
36
- .getPropertyValue(`--${key}`).trim();
37
- try {
38
- return JSON.parse(value) as T;
39
- } catch {
40
- return value as unknown as T;
41
- }
42
- },
43
-
44
- observe<T>(key: string, callback: StateObserver<T>): () => void {
45
- if (!this._observers.has(key)) {
46
- this._observers.set(key, new Set());
47
- }
48
- this._observers.get(key)?.add(callback as StateObserver);
49
-
50
- return () => {
51
- this._observers.get(key)?.delete(callback as StateObserver);
52
- };
53
- },
54
-
55
- _notifyObservers<T>(key: string, value: T): void {
56
- this._observers.get(key)?.forEach(callback =>
57
- (callback as StateObserver<T>)(value)
58
- );
59
- },
60
-
61
- _addRule(rule: string): void {
62
- if (this._sheet) {
63
- this._sheet.insertRule(rule, this._sheet.cssRules.length);
64
- }
65
- }
66
- };
67
-
68
- export default UIState;
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { default as UIState } from './UIState';
2
- export * from './react';
@@ -1,33 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import UIState from '../UIState';
3
-
4
- export function useUIState<T>(key: string, initialValue: T): [T, (value: T) => void] {
5
- // Initialize UIState if needed
6
- useEffect(() => {
7
- UIState.init();
8
- }, []);
9
-
10
- // Get initial state
11
- const [state, setState] = useState<T>(() => {
12
- try {
13
- const value = UIState.getState<T>(key);
14
- return value !== undefined ? value : initialValue;
15
- } catch {
16
- return initialValue;
17
- }
18
- });
19
-
20
- // Set up observer
21
- useEffect(() => {
22
- return UIState.observe<T>(key, (value) => {
23
- setState(value);
24
- });
25
- }, [key]);
26
-
27
- // Return state and setter
28
- const setUIState = (value: T) => {
29
- UIState.setState(key, value);
30
- };
31
-
32
- return [state, setUIState];
33
- }