@coherent.js/state 1.0.0-beta.2 → 1.0.0-beta.5
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/dist/index.js +336 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
// src/reactive-state.js
|
|
2
|
-
|
|
2
|
+
var StateError = class extends Error {
|
|
3
|
+
constructor(message, options = {}) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "StateError";
|
|
6
|
+
this.type = options.type || "state";
|
|
7
|
+
this.component = options.component;
|
|
8
|
+
this.context = options.context;
|
|
9
|
+
this.timestamp = Date.now();
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var globalErrorHandler = {
|
|
13
|
+
handle(error, context = {}) {
|
|
14
|
+
console.error("State Error:", error.message, context);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
3
17
|
var Observable = class _Observable {
|
|
4
18
|
constructor(value, options = {}) {
|
|
5
19
|
this._value = value;
|
|
@@ -1646,6 +1660,318 @@ var validators = {
|
|
|
1646
1660
|
}
|
|
1647
1661
|
};
|
|
1648
1662
|
|
|
1663
|
+
// src/enhanced-state-patterns.js
|
|
1664
|
+
var FormState = class {
|
|
1665
|
+
constructor(initialValues = {}, options = {}) {
|
|
1666
|
+
this._state = createReactiveState({
|
|
1667
|
+
values: { ...initialValues },
|
|
1668
|
+
errors: {},
|
|
1669
|
+
touched: {},
|
|
1670
|
+
isSubmitting: false,
|
|
1671
|
+
isValid: true
|
|
1672
|
+
}, options);
|
|
1673
|
+
this._validators = {};
|
|
1674
|
+
this._options = options;
|
|
1675
|
+
}
|
|
1676
|
+
// OOP methods for form management
|
|
1677
|
+
setValue(field, value) {
|
|
1678
|
+
this._state.set("values", {
|
|
1679
|
+
...this._state.get("values"),
|
|
1680
|
+
[field]: value
|
|
1681
|
+
});
|
|
1682
|
+
this._validateField(field);
|
|
1683
|
+
this._state.set("touched", {
|
|
1684
|
+
...this._state.get("touched"),
|
|
1685
|
+
[field]: true
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
getValue(field) {
|
|
1689
|
+
return this._state.get("values")[field];
|
|
1690
|
+
}
|
|
1691
|
+
setError(field, error) {
|
|
1692
|
+
this._state.set("errors", {
|
|
1693
|
+
...this._state.get("errors"),
|
|
1694
|
+
[field]: error
|
|
1695
|
+
});
|
|
1696
|
+
this._updateIsValid();
|
|
1697
|
+
}
|
|
1698
|
+
addValidator(field, validator) {
|
|
1699
|
+
this._validators[field] = validator;
|
|
1700
|
+
}
|
|
1701
|
+
validateAll() {
|
|
1702
|
+
const values = this._state.get("values");
|
|
1703
|
+
const errors = {};
|
|
1704
|
+
Object.entries(this._validators).forEach(([field, validator]) => {
|
|
1705
|
+
const error = validator(values[field], values);
|
|
1706
|
+
if (error) {
|
|
1707
|
+
errors[field] = error;
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
this._state.set("errors", errors);
|
|
1711
|
+
this._updateIsValid();
|
|
1712
|
+
return Object.keys(errors).length === 0;
|
|
1713
|
+
}
|
|
1714
|
+
async submit(onSubmit) {
|
|
1715
|
+
if (!this.validateAll()) return false;
|
|
1716
|
+
this._state.set("isSubmitting", true);
|
|
1717
|
+
try {
|
|
1718
|
+
await onSubmit(this._state.get("values"));
|
|
1719
|
+
return true;
|
|
1720
|
+
} catch (error) {
|
|
1721
|
+
this.setError("_form", error.message);
|
|
1722
|
+
return false;
|
|
1723
|
+
} finally {
|
|
1724
|
+
this._state.set("isSubmitting", false);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
reset() {
|
|
1728
|
+
this._state.set("values", {});
|
|
1729
|
+
this._state.set("errors", {});
|
|
1730
|
+
this._state.set("touched", {});
|
|
1731
|
+
this._state.set("isSubmitting", false);
|
|
1732
|
+
this._state.set("isValid", true);
|
|
1733
|
+
}
|
|
1734
|
+
// Watch methods for FP integration
|
|
1735
|
+
watchValues(callback) {
|
|
1736
|
+
return this._state.watch("values", callback);
|
|
1737
|
+
}
|
|
1738
|
+
watchErrors(callback) {
|
|
1739
|
+
return this._state.watch("errors", callback);
|
|
1740
|
+
}
|
|
1741
|
+
watchSubmitting(callback) {
|
|
1742
|
+
return this._state.watch("isSubmitting", callback);
|
|
1743
|
+
}
|
|
1744
|
+
// Private methods
|
|
1745
|
+
_validateField(field) {
|
|
1746
|
+
const value = this.getValue(field);
|
|
1747
|
+
const validator = this._validators[field];
|
|
1748
|
+
if (validator) {
|
|
1749
|
+
const error = validator(value, this._state.get("values"));
|
|
1750
|
+
this.setError(field, error);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
_updateIsValid() {
|
|
1754
|
+
const hasErrors = Object.keys(this._state.get("errors")).some(
|
|
1755
|
+
(key) => this._state.get("errors")[key]
|
|
1756
|
+
);
|
|
1757
|
+
this._state.set("isValid", !hasErrors);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
var ListState = class {
|
|
1761
|
+
constructor(initialItems = [], options = {}) {
|
|
1762
|
+
this._state = createReactiveState({
|
|
1763
|
+
items: [...initialItems],
|
|
1764
|
+
loading: false,
|
|
1765
|
+
error: null,
|
|
1766
|
+
filters: {},
|
|
1767
|
+
sortBy: null,
|
|
1768
|
+
sortOrder: "asc",
|
|
1769
|
+
page: 1,
|
|
1770
|
+
pageSize: options.pageSize || 10
|
|
1771
|
+
}, options);
|
|
1772
|
+
this._options = options;
|
|
1773
|
+
}
|
|
1774
|
+
// OOP methods for list operations
|
|
1775
|
+
addItem(item) {
|
|
1776
|
+
this._state.set("items", [...this._state.get("items"), item]);
|
|
1777
|
+
}
|
|
1778
|
+
removeItem(indexOrPredicate) {
|
|
1779
|
+
const items = this._state.get("items");
|
|
1780
|
+
let newItems;
|
|
1781
|
+
if (typeof indexOrPredicate === "number") {
|
|
1782
|
+
newItems = items.filter((_, i) => i !== indexOrPredicate);
|
|
1783
|
+
} else {
|
|
1784
|
+
newItems = items.filter((item) => !indexOrPredicate(item));
|
|
1785
|
+
}
|
|
1786
|
+
this._state.set("items", newItems);
|
|
1787
|
+
}
|
|
1788
|
+
updateItem(indexOrPredicate, updates) {
|
|
1789
|
+
const items = this._state.get("items");
|
|
1790
|
+
const newItems = items.map((item, i) => {
|
|
1791
|
+
if (typeof indexOrPredicate === "number") {
|
|
1792
|
+
return i === indexOrPredicate ? { ...item, ...updates } : item;
|
|
1793
|
+
} else {
|
|
1794
|
+
return indexOrPredicate(item) ? { ...item, ...updates } : item;
|
|
1795
|
+
}
|
|
1796
|
+
});
|
|
1797
|
+
this._state.set("items", newItems);
|
|
1798
|
+
}
|
|
1799
|
+
filter(filters) {
|
|
1800
|
+
this._state.set("filters", filters);
|
|
1801
|
+
this._state.set("page", 1);
|
|
1802
|
+
}
|
|
1803
|
+
sort(sortBy, order = "asc") {
|
|
1804
|
+
this._state.set("sortBy", sortBy);
|
|
1805
|
+
this._state.set("sortOrder", order);
|
|
1806
|
+
}
|
|
1807
|
+
setPage(page) {
|
|
1808
|
+
this._state.set("page", Math.max(1, page));
|
|
1809
|
+
}
|
|
1810
|
+
async load(loader) {
|
|
1811
|
+
this._state.set("loading", true);
|
|
1812
|
+
this._state.set("error", null);
|
|
1813
|
+
try {
|
|
1814
|
+
const items = await loader(this._state.get("filters"));
|
|
1815
|
+
this._state.set("items", items);
|
|
1816
|
+
return items;
|
|
1817
|
+
} catch (error) {
|
|
1818
|
+
this._state.set("error", error.message);
|
|
1819
|
+
return [];
|
|
1820
|
+
} finally {
|
|
1821
|
+
this._state.set("loading", false);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
// Computed properties
|
|
1825
|
+
get filteredItems() {
|
|
1826
|
+
const items = this._state.get("items");
|
|
1827
|
+
const filters = this._state.get("filters");
|
|
1828
|
+
return items.filter((item) => {
|
|
1829
|
+
return Object.entries(filters).every(([key, value]) => {
|
|
1830
|
+
if (!value) return true;
|
|
1831
|
+
return String(item[key] || "").toLowerCase().includes(String(value).toLowerCase());
|
|
1832
|
+
});
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
get sortedItems() {
|
|
1836
|
+
const items = this.filteredItems;
|
|
1837
|
+
const sortBy = this._state.get("sortBy");
|
|
1838
|
+
const sortOrder = this._state.get("sortOrder");
|
|
1839
|
+
if (!sortBy) return items;
|
|
1840
|
+
return [...items].sort((a, b) => {
|
|
1841
|
+
const aVal = a[sortBy];
|
|
1842
|
+
const bVal = b[sortBy];
|
|
1843
|
+
if (aVal === bVal) return 0;
|
|
1844
|
+
const comparison = aVal < bVal ? -1 : 1;
|
|
1845
|
+
return sortOrder === "desc" ? -comparison : comparison;
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
get paginatedItems() {
|
|
1849
|
+
const items = this.sortedItems;
|
|
1850
|
+
const page = this._state.get("page");
|
|
1851
|
+
const pageSize = this._state.get("pageSize");
|
|
1852
|
+
const start = (page - 1) * pageSize;
|
|
1853
|
+
const end = start + pageSize;
|
|
1854
|
+
return items.slice(start, end);
|
|
1855
|
+
}
|
|
1856
|
+
get totalPages() {
|
|
1857
|
+
return Math.ceil(this.sortedItems.length / this._state.get("pageSize"));
|
|
1858
|
+
}
|
|
1859
|
+
// Watch methods
|
|
1860
|
+
watchItems(callback) {
|
|
1861
|
+
return this._state.watch("items", callback);
|
|
1862
|
+
}
|
|
1863
|
+
watchLoading(callback) {
|
|
1864
|
+
return this._state.watch("loading", callback);
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
1867
|
+
var ModalState = class {
|
|
1868
|
+
constructor(_initialState = {}) {
|
|
1869
|
+
this._state = createReactiveState({
|
|
1870
|
+
isOpen: false,
|
|
1871
|
+
data: null,
|
|
1872
|
+
loading: false,
|
|
1873
|
+
error: null
|
|
1874
|
+
});
|
|
1875
|
+
this._resolvers = /* @__PURE__ */ new Map();
|
|
1876
|
+
this._currentId = 0;
|
|
1877
|
+
}
|
|
1878
|
+
// OOP methods for modal control
|
|
1879
|
+
async open(data) {
|
|
1880
|
+
return new Promise((resolve) => {
|
|
1881
|
+
const id = ++this._currentId;
|
|
1882
|
+
this._resolvers.set(id, resolve);
|
|
1883
|
+
this._state.set("data", data);
|
|
1884
|
+
this._state.set("isOpen", true);
|
|
1885
|
+
this._state.set("error", null);
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
close(result = null) {
|
|
1889
|
+
const currentId = this._currentId;
|
|
1890
|
+
const resolver = this._resolvers.get(currentId);
|
|
1891
|
+
if (resolver) {
|
|
1892
|
+
resolver(result);
|
|
1893
|
+
this._resolvers.delete(currentId);
|
|
1894
|
+
}
|
|
1895
|
+
this._state.set("isOpen", false);
|
|
1896
|
+
this._state.set("data", null);
|
|
1897
|
+
}
|
|
1898
|
+
setLoading(loading) {
|
|
1899
|
+
this._state.set("loading", loading);
|
|
1900
|
+
}
|
|
1901
|
+
setError(error) {
|
|
1902
|
+
this._state.set("error", error);
|
|
1903
|
+
}
|
|
1904
|
+
// Watch methods
|
|
1905
|
+
watchOpen(callback) {
|
|
1906
|
+
return this._state.watch("isOpen", callback);
|
|
1907
|
+
}
|
|
1908
|
+
watchData(callback) {
|
|
1909
|
+
return this._state.watch("data", callback);
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
var RouterState = class {
|
|
1913
|
+
constructor(initialRoute = "/", options = {}) {
|
|
1914
|
+
this._state = createReactiveState({
|
|
1915
|
+
current: initialRoute,
|
|
1916
|
+
params: {},
|
|
1917
|
+
query: {},
|
|
1918
|
+
history: [initialRoute],
|
|
1919
|
+
canGoBack: false,
|
|
1920
|
+
canGoForward: false
|
|
1921
|
+
}, options);
|
|
1922
|
+
this._routes = /* @__PURE__ */ new Map();
|
|
1923
|
+
this._options = options;
|
|
1924
|
+
}
|
|
1925
|
+
// OOP methods for routing
|
|
1926
|
+
addRoute(path, handler) {
|
|
1927
|
+
this._routes.set(path, handler);
|
|
1928
|
+
}
|
|
1929
|
+
navigate(path, params = {}, query = {}) {
|
|
1930
|
+
this._state.set("history", [...this._state.get("history"), path]);
|
|
1931
|
+
this._state.set("current", path);
|
|
1932
|
+
this._state.set("params", params);
|
|
1933
|
+
this._state.set("query", query);
|
|
1934
|
+
this._updateNavigationState();
|
|
1935
|
+
}
|
|
1936
|
+
back() {
|
|
1937
|
+
const history = this._state.get("history");
|
|
1938
|
+
if (history.length > 1) {
|
|
1939
|
+
const newHistory = history.slice(0, -1);
|
|
1940
|
+
const previousRoute = newHistory[newHistory.length - 1];
|
|
1941
|
+
this._state.set("history", newHistory);
|
|
1942
|
+
this._state.set("current", previousRoute);
|
|
1943
|
+
this._updateNavigationState();
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
forward() {
|
|
1947
|
+
}
|
|
1948
|
+
// Watch methods
|
|
1949
|
+
watchRoute(callback) {
|
|
1950
|
+
return this._state.watch("current", callback);
|
|
1951
|
+
}
|
|
1952
|
+
watchParams(callback) {
|
|
1953
|
+
return this._state.watch("params", callback);
|
|
1954
|
+
}
|
|
1955
|
+
// Private methods
|
|
1956
|
+
_updateNavigationState() {
|
|
1957
|
+
const history = this._state.get("history");
|
|
1958
|
+
this._state.set("canGoBack", history.length > 1);
|
|
1959
|
+
this._state.set("canGoForward", false);
|
|
1960
|
+
}
|
|
1961
|
+
};
|
|
1962
|
+
function createFormState(initialValues, options) {
|
|
1963
|
+
return new FormState(initialValues, options);
|
|
1964
|
+
}
|
|
1965
|
+
function createListState(initialItems, options) {
|
|
1966
|
+
return new ListState(initialItems, options);
|
|
1967
|
+
}
|
|
1968
|
+
function createModalState(initialState) {
|
|
1969
|
+
return new ModalState(initialState);
|
|
1970
|
+
}
|
|
1971
|
+
function createRouterState(initialRoute, options) {
|
|
1972
|
+
return new RouterState(initialRoute, options);
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1649
1975
|
// src/index.js
|
|
1650
1976
|
var index_default = {
|
|
1651
1977
|
// Reactive state utilities
|
|
@@ -1668,6 +1994,11 @@ var index_default = {
|
|
|
1668
1994
|
// Validation utilities
|
|
1669
1995
|
createValidatedState,
|
|
1670
1996
|
validators,
|
|
1997
|
+
// Enhanced state patterns
|
|
1998
|
+
createFormState,
|
|
1999
|
+
createListState,
|
|
2000
|
+
createModalState,
|
|
2001
|
+
createRouterState,
|
|
1671
2002
|
// State utilities
|
|
1672
2003
|
stateUtils
|
|
1673
2004
|
};
|
|
@@ -1677,8 +2008,12 @@ export {
|
|
|
1677
2008
|
clearAllContexts,
|
|
1678
2009
|
computed,
|
|
1679
2010
|
createContextProvider,
|
|
2011
|
+
createFormState,
|
|
2012
|
+
createListState,
|
|
2013
|
+
createModalState,
|
|
1680
2014
|
createPersistentState,
|
|
1681
2015
|
createReactiveState,
|
|
2016
|
+
createRouterState,
|
|
1682
2017
|
createState,
|
|
1683
2018
|
createValidatedState,
|
|
1684
2019
|
index_default as default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/state",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "Reactive state management for Coherent.js applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@coherent.js/core": "1.0.0-beta.
|
|
32
|
+
"@coherent.js/core": "1.0.0-beta.5"
|
|
33
33
|
},
|
|
34
34
|
"types": "./types/index.d.ts",
|
|
35
35
|
"files": [
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"README.md",
|
|
38
38
|
"types/"
|
|
39
39
|
],
|
|
40
|
+
"sideEffects": false,
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "node build.mjs",
|
|
42
43
|
"clean": "rm -rf dist"
|