@cocreate/state 1.24.9 → 1.25.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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/index.js +227 -200
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.25.1](https://github.com/CoCreate-app/CoCreate-state/compare/v1.25.0...v1.25.1) (2026-03-05)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* support adding classes via state attributes ([dfa50d2](https://github.com/CoCreate-app/CoCreate-state/commit/dfa50d29ac8b5c15ef384dfebd67dc8faad816f8))
|
|
7
|
+
|
|
8
|
+
# [1.25.0](https://github.com/CoCreate-app/CoCreate-state/compare/v1.24.9...v1.25.0) (2026-02-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* state suports local and session storage ([fab140f](https://github.com/CoCreate-app/CoCreate-state/commit/fab140f9c660d55a0d3819c18bf99635f5e024f5))
|
|
14
|
+
|
|
1
15
|
## [1.24.9](https://github.com/CoCreate-app/CoCreate-state/compare/v1.24.8...v1.24.9) (2026-02-25)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/state",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.1",
|
|
4
4
|
"description": "Data attributes which can be used for components in CoCreate framework combined as a group of attributes that dynamically change attributes & fetch custom data.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state",
|
package/src/index.js
CHANGED
|
@@ -2,250 +2,277 @@ import "@cocreate/element-prototype";
|
|
|
2
2
|
import Observer from "@cocreate/observer";
|
|
3
3
|
import Action from "@cocreate/actions";
|
|
4
4
|
import uid from "@cocreate/uuid";
|
|
5
|
-
import
|
|
5
|
+
import storage from "@cocreate/local-storage";
|
|
6
|
+
|
|
7
|
+
const { localStorage, sessionStorage } = storage;
|
|
6
8
|
|
|
7
9
|
function init() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
let elements = document.querySelectorAll("[state-id]");
|
|
11
|
+
initElements(elements);
|
|
12
|
+
|
|
13
|
+
window.addEventListener("storage", function (e) {
|
|
14
|
+
if (e.key == "state") {
|
|
15
|
+
// Re-initialize only elements that are explicitly listening to storage changes
|
|
16
|
+
elements = document.querySelectorAll(
|
|
17
|
+
'[state-id][state-onstoragechange]:not([state-onstoragechange="false"])'
|
|
18
|
+
);
|
|
19
|
+
initElements(elements);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
document.addEventListener("click", function (e) {
|
|
24
|
+
const target = e.target.closest("[state-to]");
|
|
25
|
+
if (target) {
|
|
26
|
+
if (target.closest('[actions*="state"]')) return;
|
|
27
|
+
stateAttributes(target);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
function initElements(elements) {
|
|
28
|
-
|
|
33
|
+
for (let element of elements) initElement(element);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
function initElement(element) {
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
let state_id = element.getAttribute("state-id");
|
|
38
|
+
if (!state_id) return;
|
|
39
|
+
|
|
40
|
+
// Determine target storage based on attributes
|
|
41
|
+
let isLocal = element.hasAttribute("state-localstorage") || element.hasAttribute("state-onstoragechange");
|
|
42
|
+
let storageObj = isLocal ? localStorage : sessionStorage;
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
let statedAttributes = storageObj.getItem("state");
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
if (!statedAttributes || statedAttributes.length == 0) return;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
statedAttributes = JSON.parse(statedAttributes);
|
|
50
|
+
} catch(e) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
if (state_id.includes(",")) state_id = state_id.split(",");
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
if (!Array.isArray(state_id)) state_id = [state_id];
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
for (let i = 0; i < state_id.length; i++) {
|
|
59
|
+
let attrValues = statedAttributes[`${state_id[i].trim()}`];
|
|
60
|
+
if (!attrValues) continue; // Use continue to ensure other IDs in the array still process
|
|
61
|
+
_setAttributeValues(element, attrValues);
|
|
62
|
+
}
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
function _setAttributeValues(el, attrValues) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
let isOverwrite = el.getAttribute("state-overwrite");
|
|
67
|
+
if (isOverwrite === null || isOverwrite === undefined)
|
|
68
|
+
isOverwrite = attrValues["overwrite"];
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
if ((isOverwrite && isOverwrite != "false") || isOverwrite === "")
|
|
71
|
+
isOverwrite = true;
|
|
72
|
+
else if (!isOverwrite || isOverwrite === "false") isOverwrite = false;
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
// delete attrValues["overwrite"];
|
|
61
75
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
for (const key of Object.keys(attrValues)) {
|
|
77
|
+
_setAttributeValue(el, key, attrValues[key], isOverwrite);
|
|
78
|
+
}
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
async function _setAttributeValue(element, attribute, value, isOverwrite) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
// TODO: if (value !== undefined)???
|
|
83
|
+
if (!element.getAttribute(attribute) || isOverwrite) {
|
|
84
|
+
if (attribute == "value") {
|
|
85
|
+
if (element.value == "" || (element.value && isOverwrite))
|
|
86
|
+
element.value = value;
|
|
87
|
+
else if (
|
|
88
|
+
isOverwrite ||
|
|
89
|
+
(element.hasAttribute("value") && !(await element.getValue()))
|
|
90
|
+
)
|
|
91
|
+
element.setValue(value);
|
|
92
|
+
} else if (attribute === "class" && value) {
|
|
93
|
+
const classes = String(value).split(/\s+/).filter(Boolean);
|
|
94
|
+
if (classes.length) element.classList.add(...classes);
|
|
95
|
+
} else if (element.hasAttribute(attribute) && (value || value === "")) {
|
|
96
|
+
element.setAttribute(attribute, value);
|
|
97
|
+
} else if (attribute.startsWith("$")) {
|
|
98
|
+
// Handle using operators.js
|
|
99
|
+
const prop = attribute.substring(1);
|
|
100
|
+
if (element[prop]) {
|
|
101
|
+
if (typeof element[prop] === "function") {
|
|
102
|
+
element[prop](value);
|
|
103
|
+
} else {
|
|
104
|
+
element[prop] = value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
async function stateAttributes(element) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
112
|
+
let sessionState = {};
|
|
113
|
+
let localState = {};
|
|
114
|
+
|
|
115
|
+
try { sessionState = JSON.parse(sessionStorage.getItem("state") || "{}"); } catch(e) {}
|
|
116
|
+
try { localState = JSON.parse(localStorage.getItem("state") || "{}"); } catch(e) {}
|
|
117
|
+
|
|
118
|
+
let elements = [];
|
|
119
|
+
|
|
120
|
+
// let form = element.closest("form");
|
|
121
|
+
// if (form) {
|
|
122
|
+
// elements = form.querySelectorAll("[state_to]");
|
|
123
|
+
// } else {
|
|
124
|
+
if (element.hasAttribute("state-to")) elements.push(element);
|
|
125
|
+
let nestedElements = element.querySelectorAll("[state-to]");
|
|
126
|
+
elements.push(...nestedElements);
|
|
127
|
+
let current = element;
|
|
128
|
+
while (current) {
|
|
129
|
+
if (current.hasAttribute("state-to") && !elements.includes(current)) {
|
|
130
|
+
elements.push(current);
|
|
131
|
+
}
|
|
132
|
+
current = current.parentElement;
|
|
133
|
+
}
|
|
134
|
+
// }
|
|
135
|
+
|
|
136
|
+
let changeState = false;
|
|
137
|
+
let sessionChanged = false;
|
|
138
|
+
let localChanged = false;
|
|
139
|
+
let triggerIsLocal = element.hasAttribute("state-localstorage") || element.hasAttribute("state-onstoragechange");
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < elements.length; i++) {
|
|
142
|
+
let attrValues = await _getAttributeValues(elements[i]);
|
|
143
|
+
if (attrValues.src === "$back" || attrValues.href === "$back") {
|
|
144
|
+
changeState = true;
|
|
145
|
+
window.history.back();
|
|
146
|
+
break;
|
|
147
|
+
} else if (
|
|
148
|
+
attrValues.src === "$forward" ||
|
|
149
|
+
attrValues.href === "$forward"
|
|
150
|
+
) {
|
|
151
|
+
changeState = true;
|
|
152
|
+
window.history.forward();
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let state_to = elements[i].getAttribute("state-to");
|
|
157
|
+
|
|
158
|
+
let isLocal = triggerIsLocal || elements[i].hasAttribute("state-localstorage") || elements[i].hasAttribute("state-onstoragechange");
|
|
159
|
+
|
|
160
|
+
if (isLocal) {
|
|
161
|
+
Object.assign(localState, { [`${state_to}`]: attrValues });
|
|
162
|
+
localChanged = true;
|
|
163
|
+
} else {
|
|
164
|
+
Object.assign(sessionState, { [`${state_to}`]: attrValues });
|
|
165
|
+
sessionChanged = true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_getStateId(attrValues, state_to);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let href = element.closest("href");
|
|
172
|
+
if (!changeState && !href) {
|
|
173
|
+
// TODO: Handle $title when adding statedAttributes
|
|
174
|
+
let title = element.getAttribute("title") || document.title || "";
|
|
175
|
+
|
|
176
|
+
history.pushState(
|
|
177
|
+
{ sessionState: JSON.stringify(sessionState), localState: JSON.stringify(localState), title, url: location.href },
|
|
178
|
+
title,
|
|
179
|
+
location.href
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!changeState) {
|
|
184
|
+
if (sessionChanged) sessionStorage.setItem("state", JSON.stringify(sessionState));
|
|
185
|
+
if (localChanged) localStorage.setItem("state", JSON.stringify(localState));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
element.dispatchEvent(
|
|
189
|
+
new CustomEvent("stateEnd", {
|
|
190
|
+
detail: {}
|
|
191
|
+
})
|
|
192
|
+
);
|
|
163
193
|
}
|
|
164
194
|
|
|
165
195
|
async function _getAttributeValues(element) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
element.value !== undefined &&
|
|
182
|
-
!element.hasAttribute("state.value") &&
|
|
183
|
-
element.getValue
|
|
184
|
-
)
|
|
185
|
-
Object.assign(attributeValues, { value: await element.getValue() });
|
|
186
|
-
|
|
187
|
-
return attributeValues;
|
|
196
|
+
let attributeValues = {};
|
|
197
|
+
let attributes = element.attributes;
|
|
198
|
+
for (let attribute of attributes) {
|
|
199
|
+
if (attribute.name.startsWith("state.")) {
|
|
200
|
+
const key = attribute.name.slice(6);
|
|
201
|
+
if (attribute.value == "$uid") {
|
|
202
|
+
Object.assign(attributeValues, { [key]: uid.generate(6) });
|
|
203
|
+
} else if (key === "value" && !attribute.value) {
|
|
204
|
+
Object.assign(attributeValues, { value: await element.getValue() });
|
|
205
|
+
} else {
|
|
206
|
+
Object.assign(attributeValues, { [key]: element.getAttribute(attribute.name) });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return attributeValues;
|
|
188
211
|
}
|
|
189
212
|
|
|
190
213
|
function _getStateId(attrValues, state_to) {
|
|
191
|
-
|
|
192
|
-
|
|
214
|
+
const elements = document.querySelectorAll(`[state-id="${state_to}"]`);
|
|
215
|
+
for (let element of elements) _setAttributeValues(element, attrValues);
|
|
193
216
|
}
|
|
194
217
|
|
|
195
218
|
window.onload = function () {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
219
|
+
if (!history.length) {
|
|
220
|
+
const sessionState = sessionStorage.getItem("state") || "";
|
|
221
|
+
const localState = localStorage.getItem("state") || "";
|
|
222
|
+
history.replaceState(
|
|
223
|
+
{ sessionState, localState, url: location.href, title: document.title },
|
|
224
|
+
document.title,
|
|
225
|
+
location.href
|
|
226
|
+
);
|
|
227
|
+
} else if (!history.state || history.state.url !== location.href) {
|
|
228
|
+
const sessionState = sessionStorage.getItem("state") || "";
|
|
229
|
+
const localState = localStorage.getItem("state") || "";
|
|
230
|
+
history.pushState(
|
|
231
|
+
{ sessionState, localState, url: location.href, title: document.title },
|
|
232
|
+
document.title,
|
|
233
|
+
location.href
|
|
234
|
+
);
|
|
235
|
+
}
|
|
211
236
|
};
|
|
212
237
|
|
|
213
238
|
window.addEventListener("popstate", function (event) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
239
|
+
if (event.state) {
|
|
240
|
+
if (event.state.sessionState || event.state.localState) {
|
|
241
|
+
if (event.state.sessionState) sessionStorage.setItem("state", event.state.sessionState);
|
|
242
|
+
if (event.state.localState) localStorage.setItem("state", event.state.localState);
|
|
243
|
+
|
|
244
|
+
let elements = document.querySelectorAll("[state-id]");
|
|
245
|
+
initElements(elements);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (event.state.url && event.state.url !== window.location.href) {
|
|
249
|
+
if (event.state.title)
|
|
250
|
+
sessionStorage.setItem("currentPageTitle", event.state.title); // Store title using the wrapper
|
|
251
|
+
|
|
252
|
+
location.href = event.state.url; // Navigate if the URL is different
|
|
253
|
+
} else if (event.state.title) {
|
|
254
|
+
document.title = event.state.title; // Update the title if provided
|
|
255
|
+
}
|
|
256
|
+
}
|
|
230
257
|
});
|
|
231
258
|
|
|
232
259
|
Observer.init({
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
260
|
+
name: "CoCreateState",
|
|
261
|
+
types: ["addedNodes"],
|
|
262
|
+
selector: "[state-id]",
|
|
263
|
+
callback: function (mutation) {
|
|
264
|
+
initElement(mutation.target);
|
|
265
|
+
}
|
|
239
266
|
});
|
|
240
267
|
|
|
241
268
|
Action.init({
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
269
|
+
name: "state",
|
|
270
|
+
endEvent: "stateEnd",
|
|
271
|
+
callback: (action) => {
|
|
272
|
+
stateAttributes(action.element);
|
|
273
|
+
}
|
|
247
274
|
});
|
|
248
275
|
|
|
249
276
|
init();
|
|
250
277
|
|
|
251
|
-
export default { initElements, initElement, stateAttributes };
|
|
278
|
+
export default { initElements, initElement, stateAttributes };
|