web-manager 4.0.21 → 4.0.23
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 +25 -1
- package/dist/modules/bindings.js +84 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -379,13 +379,37 @@ When an element is bound, Web Manager automatically adds the `wm-bound` class to
|
|
|
379
379
|
}
|
|
380
380
|
```
|
|
381
381
|
|
|
382
|
+
#### Style Bindings
|
|
383
|
+
Set CSS custom properties (CSS variables) or inline styles dynamically:
|
|
384
|
+
|
|
385
|
+
```html
|
|
386
|
+
<!-- Set CSS custom property -->
|
|
387
|
+
<div data-wm-bind="@style --rating-percent site.ratings.starWidth"></div>
|
|
388
|
+
|
|
389
|
+
<!-- Set regular style property -->
|
|
390
|
+
<div data-wm-bind="@style width user.profile.width"></div>
|
|
391
|
+
|
|
392
|
+
<!-- Multiple styles -->
|
|
393
|
+
<div data-wm-bind="@style --primary-color theme.primaryColor, @style --secondary-color theme.secondaryColor"></div>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Then use the custom property in your CSS:
|
|
397
|
+
|
|
398
|
+
```css
|
|
399
|
+
.rating-stars::before {
|
|
400
|
+
width: var(--rating-percent, 0%);
|
|
401
|
+
background: var(--primary-color, #007bff);
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
382
405
|
#### Supported Actions
|
|
383
406
|
- **`@text`** (default): Sets the text content of the element
|
|
384
407
|
- **`@show`**: Shows the element when condition is true
|
|
385
408
|
- **`@hide`**: Hides the element when condition is true
|
|
386
409
|
- **`@attr`**: Sets an attribute value (format: `@attr attributeName expression`)
|
|
410
|
+
- **`@style`**: Sets a CSS custom property or inline style (format: `@style propertyName expression`)
|
|
387
411
|
|
|
388
|
-
Future actions like `@class`
|
|
412
|
+
Future actions like `@class` can be easily added.
|
|
389
413
|
|
|
390
414
|
### Firebase Authentication
|
|
391
415
|
|
package/dist/modules/bindings.js
CHANGED
|
@@ -13,7 +13,10 @@ class Bindings {
|
|
|
13
13
|
...data
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// Get the top-level keys that were updated
|
|
17
|
+
const updatedKeys = Object.keys(data);
|
|
18
|
+
|
|
19
|
+
this._updateBindings(this._context, updatedKeys);
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
// Get current context
|
|
@@ -24,11 +27,11 @@ class Bindings {
|
|
|
24
27
|
// Clear all context
|
|
25
28
|
clear() {
|
|
26
29
|
this._context = {};
|
|
27
|
-
this._updateBindings(this._context);
|
|
30
|
+
this._updateBindings(this._context, null); // null = update all bindings
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
// Main binding update system
|
|
31
|
-
_updateBindings(context) {
|
|
34
|
+
_updateBindings(context, updatedKeys = null) {
|
|
32
35
|
// Find all elements with data-wm-bind attribute
|
|
33
36
|
const bindElements = document.querySelectorAll('[data-wm-bind]');
|
|
34
37
|
|
|
@@ -40,13 +43,16 @@ class Bindings {
|
|
|
40
43
|
|
|
41
44
|
// Execute each action
|
|
42
45
|
bindings.forEach(({ action, expression }) => {
|
|
43
|
-
this._executeAction(element, action, expression, context);
|
|
46
|
+
this._executeAction(element, action, expression, context, updatedKeys);
|
|
44
47
|
});
|
|
45
48
|
|
|
46
|
-
// Add bound class to
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
// Add bound class to trigger fade out
|
|
50
|
+
element.classList.add('wm-bound');
|
|
51
|
+
|
|
52
|
+
// Remove skeleton class after fade completes
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
element.classList.remove('wm-binding-skeleton');
|
|
55
|
+
}, 300);
|
|
50
56
|
});
|
|
51
57
|
}
|
|
52
58
|
|
|
@@ -82,10 +88,16 @@ class Bindings {
|
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
// Execute a single action on an element
|
|
85
|
-
_executeAction(element, action, expression, context) {
|
|
91
|
+
_executeAction(element, action, expression, context, updatedKeys = null) {
|
|
86
92
|
switch (action) {
|
|
87
93
|
case '@show':
|
|
88
94
|
// Show element if condition is true (or always if no condition)
|
|
95
|
+
|
|
96
|
+
// Check if this path should be updated
|
|
97
|
+
if (!this._shouldUpdatePath(expression, updatedKeys)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
const shouldShow = expression ? this._evaluateCondition(expression, context) : true;
|
|
90
102
|
if (shouldShow) {
|
|
91
103
|
element.removeAttribute('hidden');
|
|
@@ -96,6 +108,12 @@ class Bindings {
|
|
|
96
108
|
|
|
97
109
|
case '@hide':
|
|
98
110
|
// Hide element if condition is true (or always if no condition)
|
|
111
|
+
|
|
112
|
+
// Check if this path should be updated
|
|
113
|
+
if (!this._shouldUpdatePath(expression, updatedKeys)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
const shouldHide = expression ? this._evaluateCondition(expression, context) : true;
|
|
100
118
|
if (shouldHide) {
|
|
101
119
|
element.setAttribute('hidden', '');
|
|
@@ -110,6 +128,12 @@ class Bindings {
|
|
|
110
128
|
const attrParts = expression.split(' ');
|
|
111
129
|
const attrName = attrParts[0];
|
|
112
130
|
const attrExpression = attrParts.slice(1).join(' ');
|
|
131
|
+
|
|
132
|
+
// Check if this path should be updated
|
|
133
|
+
if (!this._shouldUpdatePath(attrExpression, updatedKeys)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
113
137
|
const attrValue = this._resolvePath(context, attrExpression) || '';
|
|
114
138
|
|
|
115
139
|
if (attrValue) {
|
|
@@ -119,9 +143,47 @@ class Bindings {
|
|
|
119
143
|
}
|
|
120
144
|
break;
|
|
121
145
|
|
|
146
|
+
case '@style':
|
|
147
|
+
// Set CSS custom property or style
|
|
148
|
+
// Format: @style propertyName expression
|
|
149
|
+
const styleParts = expression.split(' ');
|
|
150
|
+
const styleName = styleParts[0];
|
|
151
|
+
const styleExpression = styleParts.slice(1).join(' ');
|
|
152
|
+
|
|
153
|
+
// Check if this path should be updated
|
|
154
|
+
if (!this._shouldUpdatePath(styleExpression, updatedKeys)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const styleValue = this._resolvePath(context, styleExpression);
|
|
159
|
+
|
|
160
|
+
if (styleValue !== null && styleValue !== undefined && styleValue !== '') {
|
|
161
|
+
// If it starts with --, it's a CSS custom property
|
|
162
|
+
if (styleName.startsWith('--')) {
|
|
163
|
+
element.style.setProperty(styleName, styleValue);
|
|
164
|
+
} else {
|
|
165
|
+
// Regular style property
|
|
166
|
+
element.style[styleName] = styleValue;
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
// Remove the style if value is empty
|
|
170
|
+
if (styleName.startsWith('--')) {
|
|
171
|
+
element.style.removeProperty(styleName);
|
|
172
|
+
} else {
|
|
173
|
+
element.style[styleName] = '';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
|
|
122
178
|
case '@text':
|
|
123
179
|
default:
|
|
124
180
|
// Set text content (default behavior)
|
|
181
|
+
|
|
182
|
+
// Check if this path should be updated
|
|
183
|
+
if (!this._shouldUpdatePath(expression, updatedKeys)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
125
187
|
const value = this._resolvePath(context, expression) || '';
|
|
126
188
|
|
|
127
189
|
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
|
|
@@ -130,11 +192,21 @@ class Bindings {
|
|
|
130
192
|
element.textContent = value;
|
|
131
193
|
}
|
|
132
194
|
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
133
197
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
198
|
+
// Check if a path should be updated based on updatedKeys
|
|
199
|
+
_shouldUpdatePath(path, updatedKeys) {
|
|
200
|
+
// If no updatedKeys filter, always update
|
|
201
|
+
if (updatedKeys === null || !path) {
|
|
202
|
+
return true;
|
|
137
203
|
}
|
|
204
|
+
|
|
205
|
+
// Extract the root key from the path
|
|
206
|
+
const rootKey = path.trim().split('.')[0];
|
|
207
|
+
|
|
208
|
+
// Only update if the root key is in updatedKeys
|
|
209
|
+
return updatedKeys.includes(rootKey);
|
|
138
210
|
}
|
|
139
211
|
|
|
140
212
|
// Resolve nested object path
|
package/package.json
CHANGED