@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.
Files changed (2) hide show
  1. package/dist/index.js +336 -1
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,5 +1,19 @@
1
1
  // src/reactive-state.js
2
- import { globalErrorHandler, StateError } from "@coherent.js/core/src/utils/_error-handler.js";
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.2",
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.2"
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"