native-document 1.0.150 → 1.0.151

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 (49) hide show
  1. package/devtools/plugin/dev-tools-plugin.js +1 -1
  2. package/devtools/widget/Widget.js +2 -1
  3. package/devtools/widget.js +1 -1
  4. package/dist/native-document.components.min.js +1146 -2721
  5. package/dist/native-document.dev.js +2862 -2862
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/package.json +1 -1
  9. package/rollup.config.js +1 -1
  10. package/src/components/$traits/has-items/HasItems.js +1 -1
  11. package/src/components/BaseComponent.js +1 -1
  12. package/src/components/accordion/AccordionItem.js +1 -1
  13. package/src/components/avatar/Avatar.js +0 -2
  14. package/src/components/breadcrumb/BreadCrumb.js +1 -1
  15. package/src/components/context-menu/ContextMenu.js +1 -1
  16. package/src/components/dropdown/Dropdown.js +1 -1
  17. package/src/components/dropdown/DropdownGroup.js +1 -1
  18. package/src/components/form/FormControl.js +2 -1
  19. package/src/components/form/field/DefaultRender.js +1 -1
  20. package/src/components/form/field/Field.js +2 -1
  21. package/src/components/form/field/FieldCollection.js +2 -1
  22. package/src/components/form/field/types/CheckboxField.js +1 -1
  23. package/src/components/form/field/types/FileField.js +1 -1
  24. package/src/components/form/field/types/RadioField.js +1 -1
  25. package/src/components/form/field/types/file-field-mode/FileItemPreview.js +1 -1
  26. package/src/components/form/validation/Validation.js +1 -1
  27. package/src/components/list/ListItem.js +1 -1
  28. package/src/components/menu/Menu.js +1 -1
  29. package/src/components/menu/MenuGroup.js +1 -1
  30. package/src/components/menu/MenuItem.js +1 -1
  31. package/src/components/modal/Modal.js +1 -1
  32. package/src/components/pagination/Pagination.js +1 -1
  33. package/src/components/popover/Popover.js +1 -1
  34. package/src/components/progress/Progress.js +0 -1
  35. package/src/components/splitter/Splitter.js +1 -1
  36. package/src/components/splitter/SplitterGutter.js +1 -1
  37. package/src/components/splitter/SplitterPanel.js +1 -1
  38. package/src/components/stepper/Stepper.js +1 -1
  39. package/src/components/stepper/StepperStep.js +1 -1
  40. package/src/components/switch/Switch.js +1 -1
  41. package/src/components/table/DataTable.js +1 -1
  42. package/src/components/table/index.js +0 -2
  43. package/src/components/tabs/Tabs.js +1 -1
  44. package/src/components/toast/Toast.js +1 -1
  45. package/src/components/tooltip/Tooltip.js +1 -1
  46. package/src/core/elements/anchor/one-child-anchor-overwriting.js +1 -1
  47. package/src/i18n/service/I18nService.js +1 -1
  48. package/src/i18n/service/functions.js +1 -1
  49. package/cdn.components.js +0 -28
@@ -1,16 +1,16 @@
1
1
  var NativeComponents = (function (exports) {
2
2
  'use strict';
3
3
 
4
- let DebugManager$2 = {};
4
+ let DebugManager$1 = {};
5
5
  {
6
- DebugManager$2 = {
6
+ DebugManager$1 = {
7
7
  log() {},
8
8
  warn() {},
9
9
  error() {},
10
10
  disable() {}
11
11
  };
12
12
  }
13
- var DebugManager$1 = DebugManager$2;
13
+ var DebugManager$2 = DebugManager$1;
14
14
 
15
15
  class NativeDocumentError extends Error {
16
16
  constructor(message, context = {}) {
@@ -68,7 +68,7 @@ var NativeComponents = (function (exports) {
68
68
  }
69
69
  }
70
70
  if (cleanedCount > 0) {
71
- DebugManager$1.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
71
+ DebugManager$2.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
72
72
  }
73
73
  }
74
74
  };
@@ -159,19 +159,6 @@ var NativeComponents = (function (exports) {
159
159
  }
160
160
  };
161
161
 
162
- const nextTick = function(fn) {
163
- let pending = false;
164
- return function(...args) {
165
- if (pending) return;
166
- pending = true;
167
-
168
- Promise.resolve().then(() => {
169
- fn.apply(this, args);
170
- pending = false;
171
- });
172
- };
173
- };
174
-
175
162
  const deepClone = (value, onObservableFound) => {
176
163
  try {
177
164
  if(window.structuredClone !== undefined) {
@@ -1706,2655 +1693,1093 @@ var NativeComponents = (function (exports) {
1706
1693
  };
1707
1694
  };
1708
1695
 
1709
- const EVENTS = [
1710
- "Click",
1711
- "DblClick",
1712
- "MouseDown",
1713
- "MouseEnter",
1714
- "MouseLeave",
1715
- "MouseMove",
1716
- "MouseOut",
1717
- "MouseOver",
1718
- "MouseUp",
1719
- "Wheel",
1720
- "KeyDown",
1721
- "KeyPress",
1722
- "KeyUp",
1723
- "Blur",
1724
- "Change",
1725
- "Focus",
1726
- "Input",
1727
- "Invalid",
1728
- "Reset",
1729
- "Search",
1730
- "Select",
1731
- "Submit",
1732
- "Drag",
1733
- "DragEnd",
1734
- "DragEnter",
1735
- "DragLeave",
1736
- "DragOver",
1737
- "DragStart",
1738
- "Drop",
1739
- "AfterPrint",
1740
- "BeforePrint",
1741
- "BeforeUnload",
1742
- "Error",
1743
- "HashChange",
1744
- "Load",
1745
- "Offline",
1746
- "Online",
1747
- "PageHide",
1748
- "PageShow",
1749
- "Resize",
1750
- "Scroll",
1751
- "Unload",
1752
- "Abort",
1753
- "CanPlay",
1754
- "CanPlayThrough",
1755
- "DurationChange",
1756
- "Emptied",
1757
- "Ended",
1758
- "LoadedData",
1759
- "LoadedMetadata",
1760
- "LoadStart",
1761
- "Pause",
1762
- "Play",
1763
- "Playing",
1764
- "Progress",
1765
- "RateChange",
1766
- "Seeked",
1767
- "Seeking",
1768
- "Stalled",
1769
- "Suspend",
1770
- "TimeUpdate",
1771
- "VolumeChange",
1772
- "Waiting",
1773
-
1774
- "TouchCancel",
1775
- "TouchEnd",
1776
- "TouchMove",
1777
- "TouchStart",
1778
- "AnimationEnd",
1779
- "AnimationIteration",
1780
- "AnimationStart",
1781
- "TransitionEnd",
1782
- "Copy",
1783
- "Cut",
1784
- "Paste",
1785
- "FocusIn",
1786
- "FocusOut",
1787
- "ContextMenu"
1788
- ];
1789
-
1790
- const EVENTS_WITH_PREVENT = [
1791
- "Click",
1792
- "DblClick",
1793
- "MouseDown",
1794
- "MouseUp",
1795
- "Wheel",
1796
- "KeyDown",
1797
- "KeyPress",
1798
- "Invalid",
1799
- "Reset",
1800
- "Submit",
1801
- "DragOver",
1802
- "Drop",
1803
- "BeforeUnload",
1804
- "TouchCancel",
1805
- "TouchEnd",
1806
- "TouchMove",
1807
- "TouchStart",
1808
- "Copy",
1809
- "Cut",
1810
- "Paste",
1811
- "ContextMenu"
1812
- ];
1696
+ function oneChildAnchorOverwriting(anchor, parent) {
1813
1697
 
1814
- const EVENTS_WITH_STOP = [
1815
- "Click",
1816
- "DblClick",
1817
- "MouseDown",
1818
- "MouseMove",
1819
- "MouseOut",
1820
- "MouseOver",
1821
- "MouseUp",
1822
- "Wheel",
1823
- "KeyDown",
1824
- "KeyPress",
1825
- "KeyUp",
1826
- "Change",
1827
- "Input",
1828
- "Invalid",
1829
- "Reset",
1830
- "Search",
1831
- "Select",
1832
- "Submit",
1833
- "Drag",
1834
- "DragEnd",
1835
- "DragEnter",
1836
- "DragLeave",
1837
- "DragOver",
1838
- "DragStart",
1839
- "Drop",
1840
- "BeforeUnload",
1841
- "HashChange",
1842
- "TouchCancel",
1843
- "TouchEnd",
1844
- "TouchMove",
1845
- "TouchStart",
1846
- "AnimationEnd",
1847
- "AnimationIteration",
1848
- "AnimationStart",
1849
- "TransitionEnd",
1850
- "Copy",
1851
- "Cut",
1852
- "Paste",
1853
- "FocusIn",
1854
- "FocusOut",
1855
- "ContextMenu"
1856
- ];
1698
+ anchor.remove = () => {
1699
+ anchor.append.apply(anchor, parent.childNodes);
1700
+ };
1701
+ anchor.getParent = () => parent;
1857
1702
 
1858
- const property = {
1859
- configurable: true,
1860
- get() {
1861
- return new NDElement(this);
1862
- }
1863
- };
1703
+ anchor.appendChild = (child) => {
1704
+ child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1705
+ parent.appendChild(child);
1706
+ };
1864
1707
 
1865
- Object.defineProperty(HTMLElement.prototype, 'nd', property);
1708
+ anchor.appendChildRaw = parent.appendChild.bind(parent);
1709
+ anchor.append = anchor.appendChild;
1710
+ anchor.appendRaw = anchor.appendChildRaw;
1866
1711
 
1867
- Object.defineProperty(DocumentFragment.prototype, 'nd', property);
1712
+ anchor.insertAtStart = (child) => {
1713
+ child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1714
+ parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
1715
+ };
1716
+ anchor.insertAtStartRaw = (child) => {
1717
+ parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
1718
+ };
1868
1719
 
1869
- Object.defineProperty(NDElement.prototype, 'nd', {
1870
- configurable: true,
1871
- get: function() {
1872
- return this;
1873
- }
1874
- });
1720
+ anchor.appendElement = anchor.appendChild;
1875
1721
 
1722
+ anchor.removeChildren = () => {
1723
+ parent.textContent = '';
1724
+ };
1876
1725
 
1726
+ anchor.replaceContent = function(content) {
1727
+ const child = Validator.isElement(content) ? content : ElementCreator.getChild(content);
1728
+ parent.replaceChildren(child);
1729
+ };
1877
1730
 
1878
- // ----------------------------------------------------------------
1879
- // Events helpers
1880
- // ----------------------------------------------------------------
1881
- EVENTS.forEach(eventSourceName => {
1882
- const eventName = eventSourceName.toLowerCase();
1883
- NDElement.prototype['on'+eventSourceName] = function(callback = null) {
1884
- this.$element.addEventListener(eventName, callback);
1885
- return this;
1731
+ anchor.replaceContentRaw = function(child) {
1732
+ parent.replaceChildren(child);
1886
1733
  };
1887
- });
1734
+ anchor.setContent = anchor.replaceContent;
1888
1735
 
1889
- EVENTS_WITH_STOP.forEach(eventSourceName => {
1890
- const eventName = eventSourceName.toLowerCase();
1891
- NDElement.prototype['onStop'+eventSourceName] = function(callback = null) {
1892
- _stop(this.$element, eventName, callback);
1893
- return this;
1736
+ anchor.insertBefore = (child, anchor) => {
1737
+ child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1738
+ parent.insertBefore(child, anchor);
1894
1739
  };
1895
- NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
1896
- _preventStop(this.$element, eventName, callback);
1897
- return this;
1740
+ anchor.insertBeforeRaw = (child, anchor) => {
1741
+ parent.insertBefore(child, anchor);
1898
1742
  };
1899
- });
1900
1743
 
1901
- EVENTS_WITH_PREVENT.forEach(eventSourceName => {
1902
- const eventName = eventSourceName.toLowerCase();
1903
- NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null) {
1904
- _prevent(this.$element, eventName, callback);
1905
- return this;
1906
- };
1907
- });
1744
+ anchor.appendChildBefore = anchor.insertBefore;
1745
+ anchor.appendChildBeforeRaw = anchor.insertBeforeRaw;
1908
1746
 
1909
- NDElement.prototype.on = function(name, callback, options) {
1910
- this.$element.addEventListener(name.toLowerCase(), callback, options);
1911
- return this;
1912
- };
1747
+ anchor.clear = anchor.remove;
1748
+ anchor.detach = anchor.remove;
1913
1749
 
1914
- const _prevent = function(element, eventName, callback) {
1915
- const handler = (event) => {
1916
- event.preventDefault();
1917
- callback && callback.call(element, event);
1750
+ anchor.replaceChildren = function() {
1751
+ parent.replaceChildren(...arguments);
1918
1752
  };
1919
- element.addEventListener(eventName, handler);
1920
- return this;
1921
- };
1922
1753
 
1923
- const _stop = function(element, eventName, callback) {
1924
- const handler = (event) => {
1925
- event.stopPropagation();
1926
- callback && callback.call(element, event);
1754
+ anchor.getByIndex = (index) => {
1755
+ return parent.childNodes[index];
1927
1756
  };
1928
- element.addEventListener(eventName, handler);
1929
- return this;
1930
- };
1931
-
1932
- const _preventStop = function(element, eventName, callback) {
1933
- const handler = (event) => {
1934
- event.stopPropagation();
1935
- event.preventDefault();
1936
- callback && callback.call(element, event);
1937
- };
1938
- element.addEventListener(eventName, handler);
1939
- return this;
1940
- };
1941
-
1757
+ }
1942
1758
 
1759
+ function Anchor(name, isUniqueChild = false) {
1760
+ const anchorFragment = new AnchorWithSentinel(name);
1943
1761
 
1944
- // ----------------------------------------------------------------
1945
- // Class attributes binder
1946
- // ----------------------------------------------------------------
1947
- const classListMethods = {
1948
- getClasses() {
1949
- return this.$element.className?.split(' ').filter(Boolean);
1950
- },
1951
- add(value) {
1952
- const classes = this.getClasses();
1953
- if(classes.indexOf(value) >= 0) {
1954
- return;
1955
- }
1956
- classes.push(value);
1957
- this.$element.className = classes.join(' ');
1958
- },
1959
- remove(value) {
1960
- const classes = this.getClasses();
1961
- const index = classes.indexOf(value);
1962
- if(index < 0) {
1963
- return;
1964
- }
1965
- classes.splice(index, 1);
1966
- this.$element.className = classes.join(' ');
1967
- },
1968
- toggle(value, force = undefined) {
1969
- const classes = this.getClasses();
1970
- const index = classes.indexOf(value);
1971
- if(index >= 0) {
1972
- if(force === true) {
1973
- return;
1974
- }
1975
- classes.splice(index, 1);
1976
- }
1977
- else {
1978
- if(force === false) {
1979
- return;
1980
- }
1981
- classes.push(value);
1762
+ anchorFragment.onConnectedOnce((parent) => {
1763
+ if(isUniqueChild) {
1764
+ oneChildAnchorOverwriting(anchorFragment, parent);
1982
1765
  }
1983
- this.$element.className = classes.join(' ');
1984
- },
1985
- contains(value) {
1986
- return this.getClasses().indexOf(value) >= 0;
1987
- }
1988
- };
1989
-
1990
- Object.defineProperty(HTMLElement.prototype, 'classes', {
1991
- configurable: true,
1992
- get() {
1993
- return {
1994
- $element: this,
1995
- ...classListMethods
1996
- };
1997
- }
1998
- });
1999
-
2000
- let withValidation = (fn) => fn;
2001
-
2002
- const normalizeComponentArgs = function(props, children = null) {
2003
- if(props && children) {
2004
- return { props, children };
2005
- }
2006
- if(typeof props !== 'object' || Array.isArray(props) || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
2007
- return { props: children, children: props }
2008
- }
2009
- return { props, children };
2010
- };
1766
+ });
2011
1767
 
2012
- /**
2013
- *
2014
- * @param {*} value
2015
- * @returns {Text}
2016
- */
2017
- const createTextNode = (value) => {
2018
- if(value) {
2019
- return value.toNdElement();
2020
- }
2021
- return ElementCreator.createTextNode();
2022
- };
1768
+ anchorFragment.__Anchor__ = true;
2023
1769
 
1770
+ const anchorStart = anchorFragment.$start;
1771
+ const anchorEnd = anchorFragment.$end;
2024
1772
 
2025
- const createHtmlElement = (element, _attributes, _children = null) => {
2026
- let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
1773
+ anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
1774
+ anchorFragment.nativeAppendChild = anchorFragment.appendChild;
1775
+ anchorFragment.nativeAppend = anchorFragment.append;
2027
1776
 
2028
- ElementCreator.processAttributes(element, attributes);
2029
- ElementCreator.processChildren(children, element);
2030
- return element;
2031
- };
1777
+ const isParentUniqueChild = isUniqueChild
1778
+ ? () => true: (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
2032
1779
 
2033
- /**
2034
- *
2035
- * @param {string} name
2036
- * @param {?Function=} customWrapper
2037
- * @returns {Function}
2038
- */
2039
- function HtmlElementWrapper(name, customWrapper = null) {
2040
- if(name) {
2041
- if(customWrapper) {
2042
- let node = null;
2043
- let createElement = (attr, children) => {
2044
- node = document.createElement(name);
2045
- createElement = (attr, children) => {
2046
- return createHtmlElement(customWrapper(node.cloneNode()), attr, children);
2047
- };
2048
- return createHtmlElement(customWrapper(node.cloneNode()), attr, children); };
1780
+ const insertBefore = (parent, child, target) => {
1781
+ const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1782
+ insertBeforeRaw(parent, childElement, target);
1783
+ };
2049
1784
 
2050
- return (attr, children) => createElement(attr, children)
1785
+ const insertBeforeRaw = (parent, child, target) => {
1786
+ if(parent === anchorFragment) {
1787
+ parent.nativeInsertBefore(child, target);
1788
+ return;
2051
1789
  }
2052
-
2053
- let node = null;
2054
- let createElement = (attr, children) => {
2055
- node = document.createElement(name);
2056
- createElement = (attr, children) => {
2057
- return createHtmlElement(node.cloneNode(), attr, children);
2058
- };
2059
- return createHtmlElement(node.cloneNode(), attr, children);
2060
- };
2061
-
2062
- return (attr, children) => createElement(attr, children)
2063
- }
2064
- return (children, name = '') => {
2065
- const anchor = Anchor(name);
2066
- anchor.append(children);
2067
- return anchor;
1790
+ if(isParentUniqueChild(parent) && target === anchorEnd) {
1791
+ parent.append(child, target);
1792
+ return;
1793
+ }
1794
+ parent.insertBefore(child, target);
2068
1795
  };
2069
- }
2070
1796
 
2071
- function NodeCloner($element) {
2072
- this.$element = $element;
2073
- this.$classes = null;
2074
- this.$styles = null;
2075
- this.$attrs = null;
2076
- this.$ndMethods = null;
2077
- }
1797
+ anchorFragment.appendElement = function(child) {
1798
+ const parentNode = anchorStart.parentNode;
1799
+ if(parentNode === anchorFragment) {
1800
+ parentNode.nativeInsertBefore(child, anchorEnd);
1801
+ return;
1802
+ }
1803
+ parentNode.insertBefore(child, anchorEnd);
1804
+ };
2078
1805
 
1806
+ anchorFragment.appendChild = function(child, before = null) {
1807
+ const parent = anchorEnd.parentNode;
1808
+ if(!parent) {
1809
+ DebugManager.error('Anchor', 'Anchor : parent not found', child);
1810
+ return;
1811
+ }
1812
+ before = before ?? anchorEnd;
1813
+ insertBefore(parent, child, before);
1814
+ };
2079
1815
 
2080
- /**
2081
- * Attaches a template binding to the element by hydrating it with the specified method.
2082
- *
2083
- * @param {string} methodName - Name of the hydration method to call
2084
- * @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
2085
- * @returns {HTMLElement} The underlying HTML element
2086
- * @example
2087
- * const onClick = $binder.attach((event, data) => console.log(data));
2088
- * element.nd.attach('onClick', onClick);
2089
- */
2090
- NDElement.prototype.attach = function(methodName, bindingHydrator) {
2091
- if(typeof bindingHydrator === 'function') {
2092
- const element = this.$element;
2093
- element.nodeCloner = element.nodeCloner || new NodeCloner(element);
2094
- element.nodeCloner.attach(methodName, bindingHydrator);
2095
- return element;
2096
- }
2097
- bindingHydrator.$hydrate(this.$element, methodName);
2098
- return this.$element;
2099
- };
1816
+ anchorFragment.appendChildRaw = function(child, before = null) {
1817
+ const parent = anchorEnd.parentNode;
1818
+ if(!parent) {
1819
+ DebugManager.error('Anchor', 'Anchor : parent not found', child);
1820
+ return;
1821
+ }
1822
+ before = before ?? anchorEnd;
1823
+ insertBeforeRaw(parent, child, before);
1824
+ };
2100
1825
 
2101
- NodeCloner.prototype.__$isNodeCloner = true;
1826
+ anchorFragment.getParent = () => anchorEnd.parentNode;
1827
+ anchorFragment.append = anchorFragment.appendChild;
1828
+ anchorFragment.appendRaw = anchorFragment.appendChildRaw;
2102
1829
 
2103
- const buildProperties = (cache, properties, data) => {
2104
- for(const key in properties) {
2105
- cache[key] = properties[key].apply(null, data);
2106
- }
2107
- return cache;
2108
- };
1830
+ anchorFragment.insertAtStart = function(child) {
1831
+ child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1832
+ anchorFragment.insertAtStartRaw(child);
1833
+ };
2109
1834
 
2110
- NodeCloner.prototype.resolve = function() {
2111
- if(this.$content) {
2112
- return;
2113
- }
2114
- const steps = [];
2115
- if(this.$ndMethods) {
2116
- const methods = Object.keys(this.$ndMethods);
2117
- if(methods.length === 1) {
2118
- const methodName = methods[0];
2119
- const callback = this.$ndMethods[methodName];
2120
- steps.push((clonedNode, data) => {
2121
- clonedNode.nd[methodName](callback.bind(clonedNode, ...data));
2122
- });
2123
- } else {
2124
- steps.push((clonedNode, data) => {
2125
- const nd = clonedNode.nd;
2126
- for(const methodName in this.$ndMethods) {
2127
- nd[methodName](this.$ndMethods[methodName].bind(clonedNode, ...data));
2128
- }
2129
- });
1835
+ anchorFragment.insertAtStartRaw = function(child) {
1836
+ const parentNode = anchorStart.parentNode;
1837
+ if(parentNode === anchorFragment) {
1838
+ parentNode.nativeInsertBefore(child, anchorStart);
1839
+ return;
2130
1840
  }
2131
- }
2132
- if(this.$classes) {
2133
- const cache = {};
2134
- const keys = Object.keys(this.$classes);
1841
+ parentNode.insertBefore(child, anchorStart);
1842
+ };
2135
1843
 
2136
- if(keys.length === 1) {
2137
- const key = keys[0];
2138
- const callback = this.$classes[key];
2139
- steps.push((clonedNode, data) => {
2140
- cache[key] = callback.apply(null, data);
2141
- ElementCreator.processClassAttribute(clonedNode, cache);
2142
- });
2143
- } else {
2144
- steps.push((clonedNode, data) => {
2145
- ElementCreator.processClassAttribute(clonedNode, buildProperties(cache, this.$classes, data));
2146
- });
1844
+ anchorFragment.removeChildren = function() {
1845
+ const parent = anchorEnd.parentNode;
1846
+ if(parent === anchorFragment) {
1847
+ return;
2147
1848
  }
2148
- }
2149
- if(this.$styles) {
2150
- const cache = {};
2151
- const keys = Object.keys(this.$styles);
2152
-
2153
- if(keys.length === 1) {
2154
- const key = keys[0];
2155
- const callback = this.$styles[key];
2156
- steps.push((clonedNode, data) => {
2157
- cache[key] = callback.apply(null, data);
2158
- ElementCreator.processStyleAttribute(clonedNode, cache);
2159
- });
2160
- } else {
2161
- steps.push((clonedNode, data) => {
2162
- ElementCreator.processStyleAttribute(clonedNode, buildProperties(cache, this.$styles, data));
2163
- });
1849
+ if(isParentUniqueChild(parent)) {
1850
+ parent.replaceChildren(anchorStart, anchorEnd);
1851
+ return;
2164
1852
  }
2165
- }
2166
- if(this.$attrs) {
2167
- const cache = {};
2168
- const keys = Object.keys(this.$attrs);
2169
1853
 
2170
- if(keys.length === 1) {
2171
- const key = keys[0];
2172
- const callback = this.$attrs[key];
2173
- steps.push((clonedNode, data) => {
2174
- cache[key] = callback.apply(null, data);
2175
- ElementCreator.processAttributes(clonedNode, cache);
2176
- });
2177
- } else {
2178
- steps.push((clonedNode, data) => {
2179
- ElementCreator.processAttributes(clonedNode, buildProperties(cache, this.$attrs, data));
2180
- });
1854
+ let itemToRemove = anchorStart.nextSibling, tempItem;
1855
+ while(itemToRemove && itemToRemove !== anchorEnd) {
1856
+ tempItem = itemToRemove.nextSibling;
1857
+ itemToRemove.remove();
1858
+ itemToRemove = tempItem;
2181
1859
  }
2182
- }
2183
-
2184
- const stepsCount = steps.length;
2185
- const $element = this.$element;
1860
+ };
2186
1861
 
2187
- this.cloneNode = (data) => {
2188
- const clonedNode = $element.cloneNode(false);
2189
- for(let i = 0; i < stepsCount; i++) {
2190
- steps[i](clonedNode, data);
1862
+ anchorFragment.remove = function() {
1863
+ const parent = anchorEnd.parentNode;
1864
+ if(parent === anchorFragment) {
1865
+ return;
1866
+ }
1867
+ if(isParentUniqueChild(parent)) {
1868
+ anchorFragment.nativeAppend.apply(anchorFragment, parent.childNodes);
1869
+ parent.replaceChildren(anchorStart, anchorEnd);
1870
+ return;
1871
+ }
1872
+ let itemToRemove = anchorStart.nextSibling, tempItem;
1873
+ while(itemToRemove && itemToRemove !== anchorEnd) {
1874
+ tempItem = itemToRemove.nextSibling;
1875
+ anchorFragment.nativeAppend(itemToRemove);
1876
+ itemToRemove = tempItem;
2191
1877
  }
2192
- return clonedNode;
2193
1878
  };
2194
- };
2195
1879
 
2196
- NodeCloner.prototype.cloneNode = function(data) {
2197
- return this.$element.cloneNode(false);
2198
- };
1880
+ anchorFragment.removeWithAnchors = function() {
1881
+ anchorFragment.removeChildren();
1882
+ anchorStart.remove();
1883
+ anchorEnd.remove();
1884
+ };
1885
+ anchorFragment.delete = anchorFragment.removeWithAnchors;
2199
1886
 
2200
- NodeCloner.prototype.attach = function(methodName, callback) {
2201
- this.$ndMethods = this.$ndMethods || {};
2202
- this.$ndMethods[methodName] = callback;
2203
- return this;
2204
- };
2205
-
2206
- NodeCloner.prototype.text = function(value) {
2207
- this.$content = value;
2208
- if(typeof value === 'function') {
2209
- this.cloneNode = (data) => createTextNode(value.apply(null, data));
2210
- return this;
2211
- }
2212
- this.cloneNode = (data) => createTextNode(data[0][value]);
2213
- return this;
2214
- };
1887
+ anchorFragment.replaceContent = function(child) {
1888
+ const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1889
+ anchorFragment.replaceContentRaw(childElement);
1890
+ };
2215
1891
 
2216
- NodeCloner.prototype.attr = function(attrName, value) {
2217
- if(attrName === 'class') {
2218
- this.$classes = this.$classes || {};
2219
- this.$classes[value.property] = value.value;
2220
- return this;
2221
- }
2222
- if(attrName === 'style') {
2223
- this.$styles = this.$styles || {};
2224
- this.$styles[value.property] = value.value;
2225
- return this;
2226
- }
2227
- this.$attrs = this.$attrs || {};
2228
- this.$attrs[attrName] = value.value;
2229
- return this;
2230
- };
1892
+ anchorFragment.replaceContentRaw = function(child) {
1893
+ const parent = anchorEnd.parentNode;
1894
+ if(!parent) {
1895
+ return;
1896
+ }
1897
+ if(isParentUniqueChild(parent)) {
1898
+ parent.replaceChildren(anchorStart, child, anchorEnd);
1899
+ return;
1900
+ }
1901
+ anchorFragment.removeChildren();
1902
+ parent.insertBefore(child, anchorEnd);
1903
+ };
2231
1904
 
2232
- DocumentFragment.prototype.__IS_FRAGMENT = true;
1905
+ anchorFragment.setContent = anchorFragment.replaceContent;
1906
+ anchorFragment.setContentRaw = anchorFragment.replaceContentRaw;
2233
1907
 
2234
- Function.prototype.args = function(...args) {
2235
- return withValidation(this);
2236
- };
1908
+ anchorFragment.insertBefore = anchorFragment.appendChild;
1909
+ anchorFragment.insertBeforeRaw = anchorFragment.appendChildRaw;
2237
1910
 
2238
- Function.prototype.errorBoundary = function(callback) {
2239
- const handler = (...args) => {
2240
- try {
2241
- return this.apply(this, args);
2242
- } catch(e) {
2243
- return callback(e, {caller: handler, args: args });
2244
- }
1911
+ anchorFragment.endElement = function() {
1912
+ return anchorEnd;
2245
1913
  };
2246
- return handler;
2247
- };
2248
1914
 
2249
- const cssPropertyAccumulator = function(initialValue = {}) {
2250
- let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
1915
+ anchorFragment.startElement = function() {
1916
+ return anchorStart;
1917
+ };
2251
1918
 
2252
- return {
2253
- add(key, value) {
2254
- if(Array.isArray(data)) {
2255
- data.push(key+': '+value);
2256
- return;
2257
- }
2258
- if(Validator.isObject(key)) {
2259
- value = key;
2260
- for(const property in value) {
2261
- data[property] = value[property];
2262
- }
2263
- return;
2264
- }
2265
- data[key] = value;
2266
- },
2267
- value() {
2268
- if(Array.isArray(data)) {
2269
- return data.join(';').concat(';');
2270
- }
2271
- return { ...data };
2272
- },
1919
+ anchorFragment.restore = function() {
1920
+ anchorFragment.appendChild(anchorFragment);
2273
1921
  };
2274
- };
2275
1922
 
2276
- const classPropertyAccumulator = function(initialValue = []) {
2277
- let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
1923
+ anchorFragment.clear = anchorFragment.remove;
1924
+ anchorFragment.detach = anchorFragment.remove;
2278
1925
 
2279
- return {
2280
- add(key, value = true) {
2281
- if(Validator.isJson(key)) {
2282
- for(const property in key) {
2283
- if(key[property]) {
2284
- data[property] = key[property];
2285
- }
2286
- }
2287
- return;
2288
- }
2289
- if(value != null || key.__$Observable) {
2290
- if(Array.isArray(data)) {
2291
- data = data.reduce((acc, item) => {
2292
- acc[item] = true;
2293
- return acc;
2294
- }, {});
2295
- }
2296
- if(key.__$Observable) {
2297
- const uniqueId = `obs-${Math.random().toString(36).substr(2, 9)}`;
2298
- data[uniqueId] = key;
2299
- }
2300
- else {
2301
- data[key] = value;
2302
- }
2303
- return;
2304
- }
2305
- if(Array.isArray(data)) {
2306
- data.push(key);
2307
- return;
2308
- }
2309
- data[key] = value;
2310
- },
2311
- value() {
2312
- if(Array.isArray(data)) {
2313
- return data.join(' ');
1926
+ anchorFragment.getByIndex = function(index) {
1927
+ let currentNode = anchorStart;
1928
+ for(let i = 0; i <= index; i++) {
1929
+ if(!currentNode.nextSibling) {
1930
+ return null;
2314
1931
  }
2315
- return { ...data };
2316
- },
1932
+ currentNode = currentNode.nextSibling;
1933
+ }
1934
+ return currentNode !== anchorStart ? currentNode : null;
2317
1935
  };
2318
- };
2319
1936
 
2320
- const mutationMethods = ['push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice'];
2321
- const noMutationMethods = ['map', 'forEach', 'filter', 'reduce', 'some', 'every', 'find', 'findIndex', 'concat', 'includes', 'indexOf'];
1937
+ return anchorFragment;
1938
+ }
1939
+ DocumentFragment.prototype.setAttribute = () => {};
2322
1940
 
2323
- /**
2324
- *
2325
- * @param target
2326
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
2327
- * @constructor
2328
- */
2329
- const ObservableArray = function (target, configs = null) {
2330
- if(!Array.isArray(target)) {
2331
- throw new NativeDocumentError('Observable.array : target must be an array');
2332
- }
1941
+ function NDElement(element) {
1942
+ this.$element = element;
1943
+ this.$attachements = null;
1944
+ }
2333
1945
 
2334
- ObservableItem.call(this, target, configs);
2335
- };
1946
+ NDElement.prototype.__$isNDElement = true;
2336
1947
 
2337
- ObservableArray.prototype = Object.create(ObservableItem.prototype);
2338
- ObservableArray.prototype.constructor = ObservableArray;
2339
- ObservableArray.prototype.__$isObservableArray = true;
1948
+ NDElement.prototype.ghostDom = function(element) {
1949
+ if(!this.$attachements) {
1950
+ this.$attachements = document.createDocumentFragment();
1951
+ }
1952
+ this.$attachements.appendChild(ElementCreator.getChild(element));
1953
+ return this;
1954
+ };
2340
1955
 
1956
+ NDElement.prototype.valueOf = function() {
1957
+ return this.$element;
1958
+ };
2341
1959
 
2342
- Object.defineProperty(ObservableArray.prototype, 'length', {
2343
- get() {
2344
- return this.$currentValue.length;
2345
- }
2346
- });
1960
+ NDElement.prototype.ref = function(target, name) {
1961
+ target[name] = this.$element;
1962
+ return this;
1963
+ };
2347
1964
 
1965
+ NDElement.prototype.refSelf = function(target, name) {
1966
+ target[name] = this;
1967
+ // TODO: @DIM to check
1968
+ // target[name] = new NDElement(this.$element);
1969
+ return this;
1970
+ };
2348
1971
 
2349
- ObservableArray.prototype.$mutate = function(action, args, mutateFn) {
2350
- if(this.$mutationInterceptor) {
2351
- const value = this.$mutationInterceptor(args, { action });
2352
- if(args !== undefined) {
2353
- args = value;
1972
+ NDElement.prototype.unmountChildren = function() {
1973
+ let element = this.$element;
1974
+ for(let i = 0, length = element.children.length; i < length; i++) {
1975
+ let elementChildren = element.children[i];
1976
+ if(!elementChildren.$ndProx) {
1977
+ elementChildren.nd?.remove();
2354
1978
  }
1979
+ elementChildren = null;
2355
1980
  }
2356
- mutateFn(args);
1981
+ element = null;
1982
+ return this;
2357
1983
  };
2358
1984
 
2359
- mutationMethods.forEach((method) => {
2360
- ObservableArray.prototype[method] = function(...values) {
2361
- return this.$mutate(method, values, (argsToUse) => {
2362
- const result = this.$currentValue[method].apply(this.$currentValue, argsToUse);
2363
- this.trigger({ action: method, args: argsToUse, result });
2364
- return result;
2365
- })
2366
- };
2367
- });
1985
+ NDElement.prototype.remove = function() {
1986
+ let element = this.$element;
1987
+ element.nd.unmountChildren();
1988
+ element.$ndProx = null;
2368
1989
 
2369
- noMutationMethods.forEach((method) => {
2370
- ObservableArray.prototype[method] = function(...values) {
2371
- return this.$currentValue[method].apply(this.$currentValue, values);
2372
- };
2373
- });
1990
+ $lifeCycleObservers.delete(element);
2374
1991
 
1992
+ element = null;
1993
+ return this;
1994
+ };
2375
1995
 
2376
- const $clearEvent = { action: 'clear' };
1996
+ const $lifeCycleObservers = new WeakMap();
1997
+ NDElement.prototype.lifecycle = function(states) {
1998
+ const el = this.$element;
1999
+ if (!$lifeCycleObservers.has(el)) {
2000
+ $lifeCycleObservers.set(el, DocumentObserver.watch(el));
2001
+ }
2002
+ const observer = $lifeCycleObservers.get(el);
2377
2003
 
2378
- /**
2379
- * Removes all items from the array and triggers an update.
2380
- *
2381
- * @returns {boolean} True if array was cleared, false if it was already empty
2382
- * @example
2383
- * const items = Observable.array([1, 2, 3]);
2384
- * items.clear(); // []
2385
- */
2386
- ObservableArray.prototype.clear = function() {
2387
- if(this.$currentValue.length === 0) {
2388
- return;
2004
+ if(states.mounted) {
2005
+ this.$element.setAttribute('data--nd-mounted', '1');
2006
+ observer.mounted(states.mounted);
2389
2007
  }
2390
- this.$mutate('clear', [], () => {
2391
- this.$currentValue.length = 0;
2392
- this.trigger($clearEvent);
2393
- });
2394
- return true;
2008
+ if(states.unmounted) {
2009
+ this.$element.setAttribute('data--nd-unmounted', '1');
2010
+ observer.unmounted(states.unmounted);
2011
+ }
2012
+ return this;
2395
2013
  };
2396
2014
 
2397
- /**
2398
- * Returns the element at the specified index in the array.
2399
- *
2400
- * @param {number} index - Zero-based index of the element to retrieve
2401
- * @returns {*} The element at the specified index
2402
- * @example
2403
- * const items = Observable.array(['a', 'b', 'c']);
2404
- * items.at(1); // 'b'
2405
- */
2406
- ObservableArray.prototype.at = function(index) {
2407
- return this.$currentValue[index];
2015
+ NDElement.prototype.mounted = function(callback) {
2016
+ return this.lifecycle({ mounted: callback });
2408
2017
  };
2409
2018
 
2410
-
2411
- /**
2412
- * Merges multiple values into the array and triggers an update.
2413
- * Similar to push but with a different operation name.
2414
- *
2415
- * @param {Array} values - Array of values to merge
2416
- * @example
2417
- * const items = Observable.array([1, 2]);
2418
- * items.merge([3, 4]); // [1, 2, 3, 4]
2419
- */
2420
- ObservableArray.prototype.merge = function(values) {
2421
- this.$mutate('merge', values, (valuesToMerge) => {
2422
- this.$currentValue.push.apply(this.$currentValue, valuesToMerge);
2423
- this.trigger({ action: 'merge', args: valuesToMerge });
2424
- });
2019
+ NDElement.prototype.unmounted = function(callback) {
2020
+ return this.lifecycle({ unmounted: callback });
2425
2021
  };
2426
2022
 
2427
- /**
2428
- * Counts the number of elements that satisfy the provided condition.
2429
- *
2430
- * @param {(value: *, index: number) => Boolean} condition - Function that tests each element (item, index) => boolean
2431
- * @returns {number} The count of elements that satisfy the condition
2432
- * @example
2433
- * const numbers = Observable.array([1, 2, 3, 4, 5]);
2434
- * numbers.count(n => n > 3); // 2
2435
- */
2436
- ObservableArray.prototype.count = function(condition) {
2437
- let count = 0;
2438
- this.$currentValue.forEach((item, index) => {
2439
- if(condition(item, index)) {
2440
- count++;
2441
- }
2442
- });
2443
- return count;
2444
- };
2023
+ NDElement.prototype.beforeUnmount = function(id, callback) {
2024
+ const el = this.$element;
2445
2025
 
2446
- /**
2447
- * Swaps two elements at the specified indices and triggers an update.
2448
- *
2449
- * @param {number} indexA - Index of the first element
2450
- * @param {number} indexB - Index of the second element
2451
- * @returns {boolean} True if swap was successful, false if indices are out of bounds
2452
- * @example
2453
- * const items = Observable.array(['a', 'b', 'c']);
2454
- * items.swap(0, 2); // ['c', 'b', 'a']
2455
- */
2456
- ObservableArray.prototype.swap = function(indexA, indexB) {
2457
- this.$mutate('swap', [indexA, indexB], ([indexA, indexB]) => {
2458
- const value = this.$currentValue;
2459
- const length = value.length;
2460
- if(indexB < indexA) {
2461
- const temp = indexA;
2462
- indexA = indexB;
2463
- indexB = temp;
2464
- }
2465
- if(length < indexA || length < indexB) {
2466
- return false;
2467
- }
2468
- const elementA = value[indexA];
2469
- const elementB = value[indexB];
2026
+ if(!DocumentObserver.beforeUnmount.has(el)) {
2027
+ DocumentObserver.beforeUnmount.set(el, new Map());
2028
+ const originalRemove = el.remove.bind(el);
2470
2029
 
2471
- value[indexA] = elementB;
2472
- value[indexB] = elementA;
2473
- this.trigger({ action: 'swap', args: [indexA, indexB], result: [elementA, elementB] });
2474
- });
2475
- return true;
2476
- };
2030
+ let $isUnmounting = false;
2477
2031
 
2478
- ObservableArray.prototype.swapItems = function(itemA, itemB) {
2479
- const indexA = this.$currentValue.indexOf(itemA);
2480
- const indexB = this.$currentValue.indexOf(itemB);
2032
+ el.remove = async () => {
2033
+ if($isUnmounting) {
2034
+ return;
2035
+ }
2036
+ $isUnmounting = true;
2037
+
2038
+ try {
2039
+ const callbacks = DocumentObserver.beforeUnmount.get(el);
2040
+ for (const cb of callbacks.values()) {
2041
+ await cb.call(this, el);
2042
+ }
2043
+ } finally {
2044
+ originalRemove();
2045
+ $isUnmounting = false;
2046
+ }
2047
+ };
2048
+ }
2481
2049
 
2482
- return this.swap(indexA, indexB);
2050
+ DocumentObserver.beforeUnmount.get(el).set(id, callback);
2051
+ return this;
2483
2052
  };
2484
2053
 
2485
- ObservableArray.prototype.insertAfter = function(data, target) {
2486
- const targetIndex = this.$currentValue.indexOf(target);
2487
- return this.splice(targetIndex + 1, 0, data);
2054
+ NDElement.prototype.htmlElement = function() {
2055
+ return this.$element;
2488
2056
  };
2489
2057
 
2490
- /**
2491
- * Removes the element at the specified index and triggers an update.
2492
- *
2493
- * @param {number} index - Index of the element to remove
2494
- * @returns {Array} Array containing the removed element, or empty array if index is invalid
2495
- * @example
2496
- * const items = Observable.array(['a', 'b', 'c']);
2497
- * items.remove(1); // ['b'] - Array is now ['a', 'c']
2498
- */
2499
- ObservableArray.prototype.remove = function(index) {
2500
- let deleted = [];
2501
- this.$mutate('remove', [index], ([idx]) => {
2502
- deleted = this.$currentValue.splice(idx, 1);
2503
- if(deleted.length === 0) {
2504
- return;
2505
- }
2506
- this.trigger({action: 'remove', args: [idx], result: deleted[0]});
2507
- });
2508
- return deleted;
2509
- };
2058
+ NDElement.prototype.node = NDElement.prototype.htmlElement;
2510
2059
 
2511
- /**
2512
- * Removes the first occurrence of the specified item from the array.
2513
- *
2514
- * @param {*} item - The item to remove
2515
- * @returns {Array} Array containing the removed element, or empty array if item not found
2516
- * @example
2517
- * const items = Observable.array(['a', 'b', 'c']);
2518
- * items.removeItem('b'); // ['b'] - Array is now ['a', 'c']
2519
- */
2520
- ObservableArray.prototype.removeItem = function(item) {
2521
- const indexOfItem = this.$currentValue.indexOf(item);
2522
- if(indexOfItem === -1) {
2523
- return [];
2060
+ NDElement.prototype.shadow = function(mode, style = null) {
2061
+ const $element = this.$element;
2062
+ const children = Array.from($element.childNodes);
2063
+ const shadowRoot = $element.attachShadow({ mode });
2064
+ if(style) {
2065
+ const styleNode = document.createElement("style");
2066
+ styleNode.textContent = style;
2067
+ shadowRoot.appendChild(styleNode);
2524
2068
  }
2525
- return this.remove(indexOfItem);
2526
- };
2527
-
2528
- /**
2529
- * Checks if the array is empty.
2530
- *
2531
- * @returns {boolean} True if array has no elements
2532
- * @example
2533
- * const items = Observable.array([]);
2534
- * items.isEmpty(); // true
2535
- */
2536
- ObservableArray.prototype.empty = function() {
2537
- return this.$currentValue.length === 0;
2538
- };
2069
+ $element.append = shadowRoot.append.bind(shadowRoot);
2070
+ $element.appendChild = shadowRoot.appendChild.bind(shadowRoot);
2071
+ shadowRoot.append(...children);
2539
2072
 
2540
- /**
2541
- * Triggers a populate operation with the current array, iteration count, and callback.
2542
- * Used internally for rendering optimizations.
2543
- *
2544
- * @param {number} iteration - Iteration count for rendering
2545
- * @param {Function} callback - Callback function for rendering items
2546
- */
2547
- ObservableArray.prototype.populateAndRender = function(iteration, callback) {
2548
- this.trigger({ action: 'populate', args: [this.$currentValue, iteration, callback] });
2073
+ return this;
2549
2074
  };
2550
2075
 
2551
-
2552
- /**
2553
- * Creates a filtered view of the array based on predicates.
2554
- * The filtered array updates automatically when source data or predicates change.
2555
- *
2556
- * @param {Object} predicates - Object mapping property names to filter conditions or functions
2557
- * @returns {ObservableArray} A new observable array containing filtered items
2558
- * @example
2559
- * const users = Observable.array([
2560
- * { name: 'John', age: 25 },
2561
- * { name: 'Jane', age: 30 }
2562
- * ]);
2563
- *
2564
- * const adults = users.where({ age: (val) => val >= 18 });
2565
- */
2566
- ObservableArray.prototype.where = function(predicates) {
2567
- if(typeof predicates === 'function') {
2568
- predicates = { _: predicates };
2569
- }
2570
- const sourceArray = this;
2571
- const observableDependencies = [sourceArray];
2572
- const filterCallbacks = {};
2573
-
2574
- for (const [key, rawPredicate] of Object.entries(predicates)) {
2575
- const predicate = Validator.isObservable(rawPredicate) ? match(rawPredicate, false) : rawPredicate;
2576
- if (predicate && typeof predicate === 'object' && 'callback' in predicate) {
2577
- filterCallbacks[key] = predicate.callback;
2578
-
2579
- if (predicate.dependencies) {
2580
- const deps = Array.isArray(predicate.dependencies)
2581
- ? predicate.dependencies
2582
- : [predicate.dependencies];
2583
- observableDependencies.push.apply(observableDependencies, deps);
2584
- }
2585
- } else if(typeof predicate === 'function') {
2586
- filterCallbacks[key] = predicate;
2587
- } else {
2588
- filterCallbacks[key] = (value) => value === predicate;
2589
- }
2590
- }
2591
-
2592
- const viewArray = Observable.array();
2593
-
2594
- const filters = Object.entries(filterCallbacks);
2595
- const updateView = () => {
2596
- const filtered = sourceArray.val().filter(item => {
2597
- for (const [key, callback] of filters) {
2598
- if(key === '_') {
2599
- if (!callback(item)) return false;
2600
- } else {
2601
- if (!callback(item[key])) return false;
2602
- }
2603
- }
2604
- return true;
2605
- });
2606
-
2607
- viewArray.set(filtered);
2608
- };
2609
-
2610
- observableDependencies.forEach(dep => dep.subscribe(updateView));
2611
-
2612
- updateView();
2613
-
2614
- return viewArray;
2076
+ NDElement.prototype.openShadow = function(style = null) {
2077
+ return this.shadow('open', style);
2615
2078
  };
2616
2079
 
2617
- /**
2618
- * Creates a filtered view where at least one of the specified fields matches the filter.
2619
- *
2620
- * @param {Array<string>} fields - Array of field names to check
2621
- * @param {FilterResult} filter - Filter condition with callback and dependencies
2622
- * @returns {ObservableArray} A new observable array containing filtered items
2623
- * @example
2624
- * const products = Observable.array([
2625
- * { name: 'Apple', category: 'Fruit' },
2626
- * { name: 'Carrot', category: 'Vegetable' }
2627
- * ]);
2628
- * const searchTerm = Observable('App');
2629
- * const filtered = products.whereSome(['name', 'category'], match(searchTerm));
2630
- */
2631
- ObservableArray.prototype.whereSome = function(fields, filter) {
2632
- return this.where({
2633
- _: {
2634
- dependencies: filter.dependencies,
2635
- callback: (item) => fields.some(field => filter.callback(item[field]))
2636
- }
2637
- });
2080
+ NDElement.prototype.closedShadow = function(style = null) {
2081
+ return this.shadow('closed', style);
2638
2082
  };
2639
2083
 
2640
2084
  /**
2641
- * Creates a filtered view where all specified fields match the filter.
2085
+ * Extends the current NDElement instance with custom methods.
2086
+ * Methods are bound to the instance and available for chaining.
2642
2087
  *
2643
- * @param {Array<string>} fields - Array of field names to check
2644
- * @param {FilterResult} filter - Filter condition with callback and dependencies
2645
- * @returns {ObservableArray} A new observable array containing filtered items
2088
+ * @param {Object} methods - Object containing method definitions
2089
+ * @returns {this} The NDElement instance with added methods for chaining
2646
2090
  * @example
2647
- * const items = Observable.array([
2648
- * { status: 'active', verified: true },
2649
- * { status: 'active', verified: false }
2650
- * ]);
2651
- * const activeFilter = equals('active');
2652
- * const filtered = items.whereEvery(['status', 'verified'], activeFilter);
2653
- */
2654
- ObservableArray.prototype.whereEvery = function(fields, filter) {
2655
- return this.where({
2656
- _: {
2657
- dependencies: filter.dependencies,
2658
- callback: (item) => fields.every(field => filter.callback(item[field]))
2659
- }
2660
- });
2661
- };
2662
-
2663
- ObservableArray.prototype.deepSubscribe = function(callback) {
2664
- const updatedValue = nextTick(() => callback(this.val()));
2665
- const $listeners = new WeakMap();
2666
-
2667
- const bindItem = (item) => {
2668
- if ($listeners.has(item)) {
2669
- return;
2670
- }
2671
- if (item?.__$isObservableArray) {
2672
- $listeners.set(item, item.deepSubscribe(updatedValue));
2673
- return;
2674
- }
2675
- if (item?.__$isObservable) {
2676
- item.subscribe(updatedValue);
2677
- $listeners.set(item, () => item.unsubscribe(updatedValue));
2678
- }
2679
- };
2680
-
2681
- const unbindItem = (item) => {
2682
- const unsub = $listeners.get(item);
2683
- if (unsub) {
2684
- unsub();
2685
- $listeners.delete(item);
2686
- }
2687
- };
2688
-
2689
- this.$currentValue.forEach(bindItem);
2690
- this.subscribe(updatedValue);
2691
-
2692
- this.subscribe((items, _, operations) => {
2693
- switch (operations?.action) {
2694
- case 'push':
2695
- case 'unshift':
2696
- operations.args.forEach(bindItem);
2697
- break;
2698
-
2699
- case 'splice': {
2700
- const [start, deleteCount, ...newItems] = operations.args;
2701
- operations.result?.forEach(unbindItem);
2702
- newItems.forEach(bindItem);
2703
- break;
2704
- }
2705
-
2706
- case 'remove':
2707
- unbindItem(operations.result);
2708
- break;
2709
-
2710
- case 'merge':
2711
- operations.args.forEach(bindItem);
2712
- break;
2713
-
2714
- case 'clear':
2715
- this.$currentValue.forEach(unbindItem);
2716
- break;
2717
- }
2718
- });
2719
-
2720
- return () => {
2721
- this.$currentValue.forEach(unbindItem);
2722
- };
2723
- };
2724
-
2725
-
2726
- ObservableArray.prototype.sync = function(targetObservable) {
2727
- if (!targetObservable || !targetObservable.__$isObservableArray) {
2728
- throw new NativeDocumentError('ObservableArray.sync : target must be an ObservableArray');
2091
+ * element.nd.with({
2092
+ * highlight() {
2093
+ * this.$element.style.background = 'yellow';
2094
+ * return this;
2095
+ * }
2096
+ * }).highlight().onClick(() => console.log('Clicked'));
2097
+ */
2098
+ NDElement.prototype.with = function(methods) {
2099
+ if (!methods || typeof methods !== 'object') {
2100
+ throw new NativeDocumentError('extend() requires an object of methods');
2729
2101
  }
2730
2102
 
2731
- targetObservable.set([...this.$currentValue]);
2103
+ for (const name in methods) {
2104
+ const method = methods[name];
2732
2105
 
2733
- const sync = (currentValue, _, operations) => {
2734
- if (!operations) {
2735
- targetObservable.set([...currentValue]);
2736
- return;
2106
+ if (typeof method !== 'function') {
2107
+ DebugManager$2.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
2108
+ continue;
2737
2109
  }
2738
2110
 
2739
- const { action, args } = operations;
2740
- targetObservable[action].apply(targetObservable, args);
2741
- };
2742
- this.subscribe(sync);
2743
-
2744
- return () => this.unsubscribe(sync);
2745
- };
2111
+ this[name] = method.bind(this);
2112
+ }
2746
2113
 
2747
- ObservableArray.prototype.clone = function() {
2748
- return new ObservableArray(this.resolve());
2114
+ return this;
2749
2115
  };
2750
2116
 
2751
2117
  /**
2752
- * Creates an observable array with reactive array methods.
2753
- * All mutations trigger updates automatically.
2118
+ * Extends the NDElement prototype with new methods available to all NDElement instances.
2119
+ * Use this to add global methods to all NDElements.
2754
2120
  *
2755
- * @param {Array} [target=[]] - Initial array value
2756
- * @param {Object|null} [configs=null] - Configuration options
2757
- * // @param {boolean} [configs.propagation=true] - Whether to propagate changes to parent observables
2758
- * // @param {boolean} [configs.deep=false] - Whether to make nested objects observable
2759
- * @param {boolean} [configs.reset=false] - Whether to store initial value for reset()
2760
- * @returns {ObservableArray} An observable array with reactive methods
2121
+ * @param {Object} methods - Object containing method definitions to add to prototype
2122
+ * @returns {typeof NDElement} The NDElement constructor
2123
+ * @throws {NativeDocumentError} If methods is not an object or contains non-function values
2761
2124
  * @example
2762
- * const items = Observable.array([1, 2, 3]);
2763
- * items.push(4); // Triggers update
2764
- * items.subscribe((arr) => console.log(arr));
2765
- */
2766
- Observable.array = function(target = [], configs = null) {
2767
- return new ObservableArray(target, configs);
2768
- };
2769
-
2770
- /**
2771
- *
2772
- * @param {Function} callback
2773
- * @returns {Function}
2125
+ * NDElement.extend({
2126
+ * fadeIn() {
2127
+ * this.$element.style.opacity = '1';
2128
+ * return this;
2129
+ * }
2130
+ * });
2131
+ * // Now all NDElements have .fadeIn() method
2132
+ * Div().nd.fadeIn();
2774
2133
  */
2775
- Observable.batch = function(callback) {
2776
- const $observer = Observable(0);
2777
- const batch = function() {
2778
- if(Validator.isAsyncFunction(callback)) {
2779
- return (callback(...arguments)).then(() => {
2780
- $observer.trigger();
2781
- }).catch(error => { throw error; });
2782
- }
2783
- callback(...arguments);
2784
- $observer.trigger();
2785
- };
2786
- batch.$observer = $observer;
2787
- return batch;
2788
- };
2789
-
2790
- const ObservableObject = function(target, configs) {
2791
- ObservableItem.call(this, target);
2792
- this.$observables = {};
2793
- this.configs = configs;
2794
-
2795
- this.$load(target);
2796
-
2797
- for(const name in target) {
2798
- if(!Object.hasOwn(this, name)) {
2799
- Object.defineProperty(this, name, {
2800
- get: () => this.$observables[name],
2801
- set: (value) => this.$observables[name].set(value)
2802
- });
2803
- }
2134
+ NDElement.extend = function(methods) {
2135
+ if (!methods || typeof methods !== 'object') {
2136
+ throw new NativeDocumentError('NDElement.extend() requires an object of methods');
2804
2137
  }
2805
2138
 
2806
- };
2807
-
2808
- ObservableObject.prototype = Object.create(ObservableItem.prototype);
2809
-
2810
- Object.defineProperty(ObservableObject, '$value', {
2811
- get() {
2812
- return this.val();
2813
- },
2814
- set(value) {
2815
- this.set(value);
2139
+ if (Array.isArray(methods)) {
2140
+ throw new NativeDocumentError('NDElement.extend() requires an object, not an array');
2816
2141
  }
2817
- });
2818
2142
 
2819
- ObservableObject.prototype.__$isObservableObject = true;
2820
- ObservableObject.prototype.__isProxy__ = true;
2821
-
2822
- ObservableObject.prototype.$load = function(initialValue) {
2823
- const configs = this.configs;
2824
- for(const key in initialValue) {
2825
- const itemValue = initialValue[key];
2826
- if(Array.isArray(itemValue)) {
2827
- if(configs?.deep !== false) {
2828
- const mappedItemValue = itemValue.map(item => {
2829
- if(Validator.isJson(item)) {
2830
- return Observable.json(item, configs);
2831
- }
2832
- if(Validator.isArray(item)) {
2833
- return Observable.array(item, configs);
2834
- }
2835
- return Observable(item, configs);
2836
- });
2837
- this.$observables[key] = Observable.array(mappedItemValue, configs);
2838
- continue;
2839
- }
2840
- this.$observables[key] = Observable.array(itemValue, configs);
2841
- continue;
2842
- }
2843
- if(Validator.isObservable(itemValue) || Validator.isProxy(itemValue)) {
2844
- this.$observables[key] = itemValue;
2845
- continue;
2846
- }
2847
- this.$observables[key] = (typeof itemValue === 'object') ? Observable.object(itemValue, configs) : Observable(itemValue, configs);
2848
- }
2849
- };
2143
+ const protectedMethods = new Set([
2144
+ 'constructor', 'valueOf', '$element', '$observer',
2145
+ 'ref', 'remove', 'cleanup', 'with', 'extend', 'attach',
2146
+ 'lifecycle', 'mounted', 'unmounted', 'unmountChildren'
2147
+ ]);
2850
2148
 
2851
- ObservableObject.prototype.val = function() {
2852
- const result = {};
2853
- for(const key in this.$observables) {
2854
- const dataItem = this.$observables[key];
2855
- if(Validator.isObservable(dataItem)) {
2856
- let value = dataItem.val();
2857
- if(Array.isArray(value)) {
2858
- value = value.map(item => {
2859
- if(Validator.isObservable(item)) {
2860
- return item.val();
2861
- }
2862
- if(Validator.isProxy(item)) {
2863
- return item.$value;
2864
- }
2865
- return item;
2866
- });
2867
- }
2868
- result[key] = value;
2869
- } else if(Validator.isProxy(dataItem)) {
2870
- result[key] = dataItem.$value;
2871
- } else {
2872
- result[key] = dataItem;
2149
+ for (const name in methods) {
2150
+ if (!Object.hasOwn(methods, name)) {
2151
+ continue;
2873
2152
  }
2874
- }
2875
- return result;
2876
- };
2877
- ObservableObject.prototype.$val = ObservableObject.prototype.val;
2878
-
2879
- ObservableObject.prototype.get = function(property) {
2880
- const item = this.$observables[property];
2881
- if(Validator.isObservable(item)) {
2882
- return item.val();
2883
- }
2884
- if(Validator.isProxy(item)) {
2885
- return item.$value;
2886
- }
2887
- return item;
2888
- };
2889
- ObservableObject.prototype.$get = ObservableObject.prototype.get;
2890
2153
 
2891
- ObservableObject.prototype.set = function(newData) {
2892
- const data = Validator.isProxy(newData) ? newData.$value : newData;
2893
- const configs = this.configs;
2894
-
2895
- for(const key in data) {
2896
- const targetItem = this.$observables[key];
2897
- const newValueOrigin = newData[key];
2898
- const newValue = data[key];
2154
+ const method = methods[name];
2899
2155
 
2900
- if(Validator.isObservable(targetItem)) {
2901
- if(!Validator.isArray(newValue)) {
2902
- targetItem.set(newValue);
2903
- continue;
2904
- }
2905
- const firstElementFromOriginalValue = newValueOrigin.at(0);
2906
- if(Validator.isObservable(firstElementFromOriginalValue) || Validator.isProxy(firstElementFromOriginalValue)) {
2907
- const newValues = newValue.map(item => {
2908
- if(Validator.isProxy(firstElementFromOriginalValue)) {
2909
- return Observable.init(item, configs);
2910
- }
2911
- return Observable(item, configs);
2912
- });
2913
- targetItem.set(newValues);
2914
- continue;
2915
- }
2916
- targetItem.set([...newValue]);
2917
- continue;
2918
- }
2919
- if(Validator.isProxy(targetItem)) {
2920
- targetItem.update(newValue);
2156
+ if (typeof method !== 'function') {
2157
+ DebugManager$2.warn('NDElement.extend', `"${name}" is not a function, skipping`);
2921
2158
  continue;
2922
2159
  }
2923
- this[key] = newValue;
2924
- }
2925
- };
2926
- ObservableObject.prototype.$set = ObservableObject.prototype.set;
2927
- ObservableObject.prototype.$updateWith = ObservableObject.prototype.set;
2928
-
2929
- ObservableObject.prototype.observables = function() {
2930
- return Object.values(this.$observables);
2931
- };
2932
- ObservableObject.prototype.$observables = ObservableObject.prototype.observables;
2933
-
2934
- ObservableObject.prototype.keys = function() {
2935
- return Object.keys(this.$observables);
2936
- };
2937
- ObservableObject.prototype.$keys = ObservableObject.prototype.keys;
2938
- ObservableObject.prototype.clone = function() {
2939
- return Observable.init(this.val(), this.configs);
2940
- };
2941
- ObservableObject.prototype.$clone = ObservableObject.prototype.clone;
2942
- ObservableObject.prototype.reset = function() {
2943
- for(const key in this.$observables) {
2944
- this.$observables[key].reset();
2945
- }
2946
- };
2947
- ObservableObject.prototype.originalSubscribe = ObservableObject.prototype.subscribe;
2948
- ObservableObject.prototype.subscribe = function(callback) {
2949
- const observables = this.observables();
2950
- const updatedValue = nextTick(() => this.trigger());
2951
2160
 
2952
- this.originalSubscribe(callback);
2953
-
2954
- for (let i = 0, length = observables.length; i < length; i++) {
2955
- const observable = observables[i];
2956
- if (observable.__$isObservableArray) {
2957
- observable.deepSubscribe(updatedValue);
2958
- continue
2161
+ if (protectedMethods.has(name)) {
2162
+ DebugManager$2.error('NDElement.extend', `Cannot override protected method "${name}"`);
2163
+ throw new NativeDocumentError(`Cannot override protected method "${name}"`);
2959
2164
  }
2960
- observable.subscribe(updatedValue);
2961
- }
2962
- };
2963
- ObservableObject.prototype.configs = function() {
2964
- return this.configs;
2965
- };
2966
-
2967
- ObservableObject.prototype.update = ObservableObject.prototype.set;
2968
-
2969
- Observable.init = function(initialValue, configs = null) {
2970
- return new ObservableObject(initialValue, configs)
2971
- };
2972
-
2973
- /**
2974
- *
2975
- * @param {any[]} data
2976
- * @return Proxy[]
2977
- */
2978
- Observable.arrayOfObject = function(data) {
2979
- return data.map(item => Observable.object(item));
2980
- };
2981
2165
 
2982
- /**
2983
- * Get the value of an observable or an object of observables.
2984
- * @param {ObservableItem|Object<ObservableItem>} data
2985
- * @returns {{}|*|null}
2986
- */
2987
- Observable.value = function(data) {
2988
- if(data?.__$isObservableArray) {
2989
- const result = [];
2990
- for(let i = 0, length = data.length; i < length; i++) {
2991
- const item = data.at(i);
2992
- result.push(Observable.value(item));
2166
+ if (NDElement.prototype[name]) {
2167
+ DebugManager$2.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
2993
2168
  }
2994
- return result;
2995
- }
2996
- if(data?.__$Observable) {
2997
- return data.val();
2998
- }
2999
- if(Validator.isProxy(data)) {
3000
- return data.$value;
3001
- }
3002
- return data;
3003
- };
3004
2169
 
3005
- ObservableItem.prototype.resolve = function () {
3006
- return Observable.value(this);
3007
- };
3008
-
3009
- Observable.object = Observable.init;
3010
- Observable.json = Observable.init;
3011
-
3012
- /**
3013
- * Creates a computed observable that automatically updates when its dependencies change.
3014
- * The callback is re-executed whenever any dependency observable changes.
3015
- *
3016
- * @param {Function} callback - Function that returns the computed value
3017
- * @param {Array<ObservableItem|ObservableChecker|ObservableProxy>|Function} [dependencies=[]] - Array of observables to watch, or batch function
3018
- * @returns {ObservableItem} A new observable that updates automatically
3019
- * @example
3020
- * const firstName = Observable('John');
3021
- * const lastName = Observable('Doe');
3022
- * const fullName = Observable.computed(
3023
- * () => `${firstName.val()} ${lastName.val()}`,
3024
- * [firstName, lastName]
3025
- * );
3026
- *
3027
- * // With batch function
3028
- * const batch = Observable.batch(() => { ... });
3029
- * const computed = Observable.computed(() => { ... }, batch);
3030
- */
3031
- Observable.computed = function(callback, dependencies = []) {
3032
- const initialValue = callback();
3033
- const observable = new ObservableItem(initialValue);
3034
- const getValues = () => dependencies.map((item) => item.val());
3035
- const updatedValue = nextTick(() => observable.set(callback(...getValues())));
3036
-
3037
- if(Validator.isFunction(dependencies)) {
3038
- if(!Validator.isObservable(dependencies.$observer)) {
3039
- throw new NativeDocumentError('Observable.computed : dependencies must be valid batch function');
3040
- }
3041
- dependencies.$observer.subscribe(updatedValue);
3042
- return observable;
2170
+ NDElement.prototype[name] = method;
3043
2171
  }
3044
2172
 
3045
- dependencies.forEach(dependency => {
3046
- if(Validator.isProxy(dependency)) {
3047
- dependency.$observables.forEach((observable) => {
3048
- observable.subscribe(updatedValue);
3049
- });
3050
- return;
3051
- }
3052
- dependency.subscribe(updatedValue);
3053
- });
2173
+ return NDElement;
2174
+ };
3054
2175
 
3055
- return observable;
2176
+ const COMMON_NODE_TYPES = {
2177
+ ELEMENT: 1,
2178
+ TEXT: 3,
2179
+ COMMENT: 8,
2180
+ DOCUMENT_FRAGMENT: 11
3056
2181
  };
3057
2182
 
3058
- const $computed = (fn, dependencies) => Observable.computed(fn, dependencies);
3059
- const $checker = (obs, fn) => obs.transform(fn);
3060
-
3061
- //
3062
- // is... -> ObservableChecker<boolean>
3063
- //
3064
-
3065
- ObservableItem.prototype.isEqualTo = function (value) {
3066
- if (value?.__$Observable) {
3067
- return $computed((a, b) => a === b, [this, value]);
3068
- }
3069
- return $checker(this, x => x === value);
3070
- };
3071
-
3072
- ObservableItem.prototype.isNotEqualTo = function (value) {
3073
- if (value?.__$Observable) {
3074
- return $computed((a, b) => a !== b, [this, value]);
3075
- }
3076
- return $checker(this, x => x !== value);
3077
- };
2183
+ const VALID_TYPES = [];
2184
+ VALID_TYPES[COMMON_NODE_TYPES.ELEMENT] = true;
2185
+ VALID_TYPES[COMMON_NODE_TYPES.TEXT] = true;
2186
+ VALID_TYPES[COMMON_NODE_TYPES.DOCUMENT_FRAGMENT] = true;
2187
+ VALID_TYPES[COMMON_NODE_TYPES.COMMENT] = true;
3078
2188
 
3079
- ObservableItem.prototype.isGreaterThan = function (value) {
3080
- if (value?.__$Observable) {
3081
- return $computed((a, b) => a > b, [this, value]);
3082
- }
3083
- return $checker(this, x => x > value);
3084
- };
2189
+ const Validator = {
2190
+ isObservable(value) {
2191
+ return value && (value.__$isObservable || value.__$Observable);
2192
+ },
2193
+ isTemplateBinding(value) {
2194
+ return value?.__$isTemplateBinding;
2195
+ },
2196
+ isObservableWhenResult(value) {
2197
+ return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
2198
+ },
2199
+ isArrayObservable(value) {
2200
+ return value?.__$isObservableArray;
2201
+ },
2202
+ isProxy(value) {
2203
+ return value?.__isProxy__
2204
+ },
2205
+ isObservableOrProxy(value) {
2206
+ return Validator.isObservable(value) || Validator.isProxy(value);
2207
+ },
2208
+ isAnchor(value) {
2209
+ return value?.__Anchor__
2210
+ },
2211
+ isObservableChecker(value) {
2212
+ return value?.__$isObservableChecker || value instanceof ObservableChecker;
2213
+ },
2214
+ isArray(value) {
2215
+ return Array.isArray(value);
2216
+ },
2217
+ isString(value) {
2218
+ return typeof value === 'string';
2219
+ },
2220
+ isNumber(value) {
2221
+ return typeof value === 'number';
2222
+ },
2223
+ isBoolean(value) {
2224
+ return typeof value === 'boolean';
2225
+ },
2226
+ isFunction(value) {
2227
+ return typeof value === 'function';
2228
+ },
2229
+ isAsyncFunction(value) {
2230
+ return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
2231
+ },
2232
+ isObject(value) {
2233
+ return typeof value === 'object' && value !== null;
2234
+ },
2235
+ isJson(value) {
2236
+ return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
2237
+ },
2238
+ isElement(value) {
2239
+ return value && VALID_TYPES[value.nodeType];
2240
+ },
2241
+ isDOMNode(value) {
2242
+ return VALID_TYPES[value.nodeType];
2243
+ },
2244
+ isFragment(value) {
2245
+ return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
2246
+ },
2247
+ isStringOrObservable(value) {
2248
+ return this.isString(value) || this.isObservable(value);
2249
+ },
2250
+ isValidChild(child) {
2251
+ return child === null ||
2252
+ this.isElement(child) ||
2253
+ this.isObservable(child) ||
2254
+ this.isNDElement(child) ||
2255
+ ['string', 'number', 'boolean'].includes(typeof child);
2256
+ },
2257
+ isNDElement(child) {
2258
+ return child?.__$isNDElement || child instanceof NDElement;
2259
+ },
2260
+ isValidChildren(children) {
2261
+ if (!Array.isArray(children)) {
2262
+ children = [children];
2263
+ }
3085
2264
 
3086
- ObservableItem.prototype.isGreaterThanOrEqualTo = function (value) {
3087
- if (value?.__$Observable) {
3088
- return $computed((a, b) => a >= b, [this, value]);
3089
- }
3090
- return $checker(this, x => x >= value);
3091
- };
2265
+ const invalid = children.filter(child => !this.isValidChild(child));
2266
+ return invalid.length === 0;
2267
+ },
2268
+ validateChildren(children) {
2269
+ if (!Array.isArray(children)) {
2270
+ children = [children];
2271
+ }
3092
2272
 
3093
- ObservableItem.prototype.isLessThan = function (value) {
3094
- if (value?.__$Observable) {
3095
- return $computed((a, b) => a < b, [this, value]);
3096
- }
3097
- return $checker(this, x => x < value);
3098
- };
2273
+ const invalid = children.filter(child => !this.isValidChild(child));
2274
+ if (invalid.length > 0) {
2275
+ throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
2276
+ }
3099
2277
 
3100
- ObservableItem.prototype.isLessThanOrEqualTo = function (value) {
3101
- if (value?.__$Observable) {
3102
- return $computed((a, b) => a <= b, [this, value]);
3103
- }
3104
- return $checker(this, x => x <= value);
3105
- };
2278
+ return children;
2279
+ },
2280
+ /**
2281
+ * Check if the data contains observables.
2282
+ * @param {Array|Object} data
2283
+ * @returns {boolean}
2284
+ */
2285
+ containsObservables(data) {
2286
+ if(!data) {
2287
+ return false;
2288
+ }
2289
+ return Validator.isObject(data)
2290
+ && Object.values(data).some(value => Validator.isObservable(value));
2291
+ },
2292
+ /**
2293
+ * Check if the data contains an observable reference.
2294
+ * @param {string} data
2295
+ * @returns {boolean}
2296
+ */
2297
+ containsObservableReference(data) {
2298
+ if(!data || typeof data !== 'string') {
2299
+ return false;
2300
+ }
2301
+ return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
2302
+ },
2303
+ validateAttributes(attributes) {},
3106
2304
 
3107
- ObservableItem.prototype.isBetween = function (min, max) {
3108
- if (min.__$Observable && max.__$Observable) {
3109
- return $computed((x, a, b) => x >= a && x <= b, [this, min, max]);
3110
- }
3111
- if (min.__$Observable) {
3112
- return $computed((x, a) => x >= a && x <= max, [this, min]);
3113
- }
3114
- if (max.__$Observable) {
3115
- return $computed((x, b) => x >= min && x <= b, [this, max]);
2305
+ validateEventCallback(callback) {
2306
+ if (typeof callback !== 'function') {
2307
+ throw new NativeDocumentError('Event callback must be a function');
2308
+ }
3116
2309
  }
3117
- return $checker(this, x => x >= min && x <= max);
3118
2310
  };
3119
2311
 
3120
- ObservableItem.prototype.isNull = function () {
3121
- return $checker(this, x => x == null);
3122
- };
2312
+ const cssPropertyAccumulator = function(initialValue = {}) {
2313
+ let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
3123
2314
 
3124
- ObservableItem.prototype.isTruthy = function () {
3125
- return $checker(this, x => !!x);
2315
+ return {
2316
+ add(key, value) {
2317
+ if(Array.isArray(data)) {
2318
+ data.push(key+': '+value);
2319
+ return;
2320
+ }
2321
+ if(Validator.isObject(key)) {
2322
+ value = key;
2323
+ for(const property in value) {
2324
+ data[property] = value[property];
2325
+ }
2326
+ return;
2327
+ }
2328
+ data[key] = value;
2329
+ },
2330
+ value() {
2331
+ if(Array.isArray(data)) {
2332
+ return data.join(';').concat(';');
2333
+ }
2334
+ return { ...data };
2335
+ },
2336
+ };
3126
2337
  };
3127
2338
 
3128
- ObservableItem.prototype.isFalsy = function () {
3129
- return $checker(this, x => !x);
3130
- };
2339
+ const classPropertyAccumulator = function(initialValue = []) {
2340
+ let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
3131
2341
 
3132
- ObservableItem.prototype.isStartingWith = function (str) {
3133
- if (str?.__$Observable) {
3134
- return $computed((a, b) => String(a).startsWith(b), [this, str]);
3135
- }
3136
- return $checker(this, x => String(x).startsWith(str));
2342
+ return {
2343
+ add(key, value = true) {
2344
+ if(Validator.isJson(key)) {
2345
+ for(const property in key) {
2346
+ if(key[property]) {
2347
+ data[property] = key[property];
2348
+ }
2349
+ }
2350
+ return;
2351
+ }
2352
+ if(value != null || key.__$Observable) {
2353
+ if(Array.isArray(data)) {
2354
+ data = data.reduce((acc, item) => {
2355
+ acc[item] = true;
2356
+ return acc;
2357
+ }, {});
2358
+ }
2359
+ if(key.__$Observable) {
2360
+ const uniqueId = `obs-${Math.random().toString(36).substr(2, 9)}`;
2361
+ data[uniqueId] = key;
2362
+ }
2363
+ else {
2364
+ data[key] = value;
2365
+ }
2366
+ return;
2367
+ }
2368
+ if(Array.isArray(data)) {
2369
+ data.push(key);
2370
+ return;
2371
+ }
2372
+ data[key] = value;
2373
+ },
2374
+ value() {
2375
+ if(Array.isArray(data)) {
2376
+ return data.join(' ');
2377
+ }
2378
+ return { ...data };
2379
+ },
2380
+ };
3137
2381
  };
3138
2382
 
3139
- ObservableItem.prototype.isEndingWith = function (str) {
3140
- if (str?.__$Observable) {
3141
- return $computed((a, b) => String(a).endsWith(b), [this, str]);
3142
- }
3143
- return $checker(this, x => String(x).endsWith(str));
3144
- };
2383
+ /**
2384
+ * Conditionally shows an element based on an observable condition.
2385
+ * The element is mounted/unmounted from the DOM as the condition changes.
2386
+ *
2387
+ * @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
2388
+ * @param {NdChild|(() => NdChild)} child - Element or content to show/hide
2389
+ * @param {Object} [options={}] - Configuration options
2390
+ * @param {string|null} [options.comment=null] - Comment for debugging
2391
+ * @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
2392
+ * @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
2393
+ * @example
2394
+ * const isVisible = Observable(false);
2395
+ * ShowIf(isVisible, Div({}, 'Hello World'));
2396
+ */
2397
+ const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
2398
+ if(!Validator.isObservable(condition)) {
2399
+ if(typeof condition === "boolean") {
2400
+ return condition ? ElementCreator.getChild(child) : null;
2401
+ }
3145
2402
 
3146
- ObservableItem.prototype.isMatchingPattern = function (regex) {
3147
- if (regex?.__$Observable) {
3148
- return $computed((a, b) => new RegExp(b).test(String(a)), [this, regex]);
2403
+ return DebugManager$2.warn('ShowIf', "ShowIf : condition must be an Observable or boolean / "+comment, condition);
3149
2404
  }
3150
- return $checker(this, x => regex.test(String(x)));
3151
- };
2405
+ const element = Anchor('Show if : '+(comment || ''));
3152
2406
 
3153
- ObservableItem.prototype.isEmpty = function () {
3154
- return $checker(this, x => x == null || x === '' || (Array.isArray(x) && x.length === 0));
3155
- };
2407
+ let childElement = null;
2408
+ const getChildElement = () => {
2409
+ if(childElement && shouldKeepInCache) {
2410
+ return childElement;
2411
+ }
2412
+ childElement = ElementCreator.getChild(child);
2413
+ if(Validator.isFragment(childElement)) {
2414
+ childElement = Array.from(childElement.childNodes);
2415
+ }
2416
+ return childElement;
2417
+ };
3156
2418
 
3157
- ObservableItem.prototype.isNotEmpty = function () {
3158
- return $checker(this, x => x == null || x === '' || (Array.isArray(x) && x.length !== 0));
3159
- };
2419
+ const currentValue = condition.val();
3160
2420
 
3161
- ObservableItem.prototype.isIncludes = function (value) {
3162
- if (value?.__$Observable) {
3163
- return $computed((a, b) => {
3164
- if (Array.isArray(a)) return a.includes(b);
3165
- return String(a).includes(String(b));
3166
- }, [this, value]);
2421
+ if(currentValue) {
2422
+ element.appendChild(getChildElement());
3167
2423
  }
3168
- return $checker(this, x => {
3169
- if (Array.isArray(x)) return x.includes(value);
3170
- return String(x).includes(String(value));
2424
+
2425
+ condition.subscribe((value) => {
2426
+ if(!!value) {
2427
+ element.appendChild(getChildElement());
2428
+ return;
2429
+ }
2430
+ element.remove();
3171
2431
  });
3172
- };
3173
2432
 
3174
- ObservableItem.prototype.isIncludedIn = function (array) {
3175
- if (array?.__$Observable) {
3176
- return $computed((a, b) => b.includes(a), [this, array]);
3177
- }
3178
- return $checker(this, x => array.includes(x));
2433
+ return element;
3179
2434
  };
3180
2435
 
3181
- ObservableItem.prototype.isOneOf = ObservableItem.prototype.isIncludedIn;
3182
-
3183
- ObservableItem.prototype.isHaving = function (key) {
3184
- if (key?.__$Observable) {
3185
- return $computed((a, b) => b in Object(a), [this, key]);
3186
- }
3187
- return $checker(this, x => key in Object(x));
3188
- };
2436
+ const EVENTS = [
2437
+ "Click",
2438
+ "DblClick",
2439
+ "MouseDown",
2440
+ "MouseEnter",
2441
+ "MouseLeave",
2442
+ "MouseMove",
2443
+ "MouseOut",
2444
+ "MouseOver",
2445
+ "MouseUp",
2446
+ "Wheel",
2447
+ "KeyDown",
2448
+ "KeyPress",
2449
+ "KeyUp",
2450
+ "Blur",
2451
+ "Change",
2452
+ "Focus",
2453
+ "Input",
2454
+ "Invalid",
2455
+ "Reset",
2456
+ "Search",
2457
+ "Select",
2458
+ "Submit",
2459
+ "Drag",
2460
+ "DragEnd",
2461
+ "DragEnter",
2462
+ "DragLeave",
2463
+ "DragOver",
2464
+ "DragStart",
2465
+ "Drop",
2466
+ "AfterPrint",
2467
+ "BeforePrint",
2468
+ "BeforeUnload",
2469
+ "Error",
2470
+ "HashChange",
2471
+ "Load",
2472
+ "Offline",
2473
+ "Online",
2474
+ "PageHide",
2475
+ "PageShow",
2476
+ "Resize",
2477
+ "Scroll",
2478
+ "Unload",
2479
+ "Abort",
2480
+ "CanPlay",
2481
+ "CanPlayThrough",
2482
+ "DurationChange",
2483
+ "Emptied",
2484
+ "Ended",
2485
+ "LoadedData",
2486
+ "LoadedMetadata",
2487
+ "LoadStart",
2488
+ "Pause",
2489
+ "Play",
2490
+ "Playing",
2491
+ "Progress",
2492
+ "RateChange",
2493
+ "Seeked",
2494
+ "Seeking",
2495
+ "Stalled",
2496
+ "Suspend",
2497
+ "TimeUpdate",
2498
+ "VolumeChange",
2499
+ "Waiting",
3189
2500
 
3190
- //
3191
- // to... -> ObservableChecker<any>
3192
- //
2501
+ "TouchCancel",
2502
+ "TouchEnd",
2503
+ "TouchMove",
2504
+ "TouchStart",
2505
+ "AnimationEnd",
2506
+ "AnimationIteration",
2507
+ "AnimationStart",
2508
+ "TransitionEnd",
2509
+ "Copy",
2510
+ "Cut",
2511
+ "Paste",
2512
+ "FocusIn",
2513
+ "FocusOut",
2514
+ "ContextMenu"
2515
+ ];
3193
2516
 
3194
- ObservableItem.prototype.toUpperCase = function () {
3195
- return $checker(this, x => String(x).toUpperCase());
3196
- };
2517
+ const EVENTS_WITH_PREVENT = [
2518
+ "Click",
2519
+ "DblClick",
2520
+ "MouseDown",
2521
+ "MouseUp",
2522
+ "Wheel",
2523
+ "KeyDown",
2524
+ "KeyPress",
2525
+ "Invalid",
2526
+ "Reset",
2527
+ "Submit",
2528
+ "DragOver",
2529
+ "Drop",
2530
+ "BeforeUnload",
2531
+ "TouchCancel",
2532
+ "TouchEnd",
2533
+ "TouchMove",
2534
+ "TouchStart",
2535
+ "Copy",
2536
+ "Cut",
2537
+ "Paste",
2538
+ "ContextMenu"
2539
+ ];
3197
2540
 
3198
- ObservableItem.prototype.toLowerCase = function () {
3199
- return $checker(this, x => String(x).toLowerCase());
3200
- };
2541
+ const EVENTS_WITH_STOP = [
2542
+ "Click",
2543
+ "DblClick",
2544
+ "MouseDown",
2545
+ "MouseMove",
2546
+ "MouseOut",
2547
+ "MouseOver",
2548
+ "MouseUp",
2549
+ "Wheel",
2550
+ "KeyDown",
2551
+ "KeyPress",
2552
+ "KeyUp",
2553
+ "Change",
2554
+ "Input",
2555
+ "Invalid",
2556
+ "Reset",
2557
+ "Search",
2558
+ "Select",
2559
+ "Submit",
2560
+ "Drag",
2561
+ "DragEnd",
2562
+ "DragEnter",
2563
+ "DragLeave",
2564
+ "DragOver",
2565
+ "DragStart",
2566
+ "Drop",
2567
+ "BeforeUnload",
2568
+ "HashChange",
2569
+ "TouchCancel",
2570
+ "TouchEnd",
2571
+ "TouchMove",
2572
+ "TouchStart",
2573
+ "AnimationEnd",
2574
+ "AnimationIteration",
2575
+ "AnimationStart",
2576
+ "TransitionEnd",
2577
+ "Copy",
2578
+ "Cut",
2579
+ "Paste",
2580
+ "FocusIn",
2581
+ "FocusOut",
2582
+ "ContextMenu"
2583
+ ];
3201
2584
 
3202
- ObservableItem.prototype.toTrimmed = function () {
3203
- return $checker(this, x => String(x).trim());
2585
+ const property = {
2586
+ configurable: true,
2587
+ get() {
2588
+ return new NDElement(this);
2589
+ }
3204
2590
  };
3205
2591
 
3206
- ObservableItem.prototype.toBoolean = function () {
3207
- return $checker(this, x => !!x);
3208
- };
2592
+ Object.defineProperty(HTMLElement.prototype, 'nd', property);
3209
2593
 
3210
- ObservableItem.prototype.toLiteral = function (template, placeholder = '${v}') {
3211
- return $checker(this, x => template.replace(placeholder, x));
3212
- };
2594
+ Object.defineProperty(DocumentFragment.prototype, 'nd', property);
3213
2595
 
3214
- ObservableItem.prototype.toFormatted = ObservableItem.prototype.toLiteral;
2596
+ Object.defineProperty(NDElement.prototype, 'nd', {
2597
+ configurable: true,
2598
+ get: function() {
2599
+ return this;
2600
+ }
2601
+ });
3215
2602
 
3216
- ObservableItem.prototype.toProperty = function (key) {
3217
- const keys = key.split('.');
3218
- return $checker(this, x => {
3219
- let value = x;
3220
- for (const k of keys) {
3221
- if (value == null) return undefined;
3222
- value = value[k];
3223
- }
3224
- return value;
3225
- });
3226
- };
3227
2603
 
3228
- ObservableItem.prototype.toLength = function () {
3229
- return $checker(this, x => (x == null ? 0 : x.length));
3230
- };
3231
2604
 
3232
- ObservableItem.prototype.toClamped = function (min, max) {
3233
- if (min.__$Observable && max.__$Observable) {
3234
- return $computed((x, a, b) => Math.min(Math.max(x, a), b), [this, min, max]);
3235
- }
3236
- if (min.__$Observable) {
3237
- return $computed((x, a) => Math.min(Math.max(x, a), max), [this, min]);
3238
- }
3239
- if (max.__$Observable) {
3240
- return $computed((x, b) => Math.min(Math.max(x, min), b), [this, max]);
3241
- }
3242
- return $checker(this, x => Math.min(Math.max(x, min), max));
3243
- };
2605
+ // ----------------------------------------------------------------
2606
+ // Events helpers
2607
+ // ----------------------------------------------------------------
2608
+ EVENTS.forEach(eventSourceName => {
2609
+ const eventName = eventSourceName.toLowerCase();
2610
+ NDElement.prototype['on'+eventSourceName] = function(callback = null) {
2611
+ this.$element.addEventListener(eventName, callback);
2612
+ return this;
2613
+ };
2614
+ });
3244
2615
 
3245
- ObservableItem.prototype.toPercent = function (total) {
3246
- if (total?.__$Observable) {
3247
- return $computed((a, b) => (b === 0 ? 0 : (a / b) * 100), [this, total]);
3248
- }
3249
- return $checker(this, x => (total === 0 ? 0 : (x / total) * 100));
3250
- };
2616
+ EVENTS_WITH_STOP.forEach(eventSourceName => {
2617
+ const eventName = eventSourceName.toLowerCase();
2618
+ NDElement.prototype['onStop'+eventSourceName] = function(callback = null) {
2619
+ _stop(this.$element, eventName, callback);
2620
+ return this;
2621
+ };
2622
+ NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
2623
+ _preventStop(this.$element, eventName, callback);
2624
+ return this;
2625
+ };
2626
+ });
3251
2627
 
3252
- const StoreFactory = function() {
2628
+ EVENTS_WITH_PREVENT.forEach(eventSourceName => {
2629
+ const eventName = eventSourceName.toLowerCase();
2630
+ NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null) {
2631
+ _prevent(this.$element, eventName, callback);
2632
+ return this;
2633
+ };
2634
+ });
3253
2635
 
3254
- const $stores = new Map();
3255
- const $followersCache = new Map();
2636
+ NDElement.prototype.on = function(name, callback, options) {
2637
+ this.$element.addEventListener(name.toLowerCase(), callback, options);
2638
+ return this;
2639
+ };
3256
2640
 
3257
- /**
3258
- * Internal helper retrieves a store entry or throws if not found.
3259
- */
3260
- const $getStoreOrThrow = (method, name) => {
3261
- const item = $stores.get(name);
3262
- if (!item) {
3263
- DebugManager$1.error('Store', `Store.${method}('${name}') : store not found. Did you call Store.create('${name}') first?`);
3264
- throw new NativeDocumentError(
3265
- `Store.${method}('${name}') : store not found.`
3266
- );
3267
- }
3268
- return item;
2641
+ const _prevent = function(element, eventName, callback) {
2642
+ const handler = (event) => {
2643
+ event.preventDefault();
2644
+ callback && callback.call(element, event);
3269
2645
  };
2646
+ element.addEventListener(eventName, handler);
2647
+ return this;
2648
+ };
3270
2649
 
3271
- /**
3272
- * Internal helper blocks write operations on a read-only observer.
3273
- */
3274
- const $applyReadOnly = (observer, name, context) => {
3275
- const readOnlyError = (method) => () => {
3276
- DebugManager$1.error('Store', `Store.${context}('${name}') is read-only. '${method}()' is not allowed.`);
3277
- throw new NativeDocumentError(
3278
- `Store.${context}('${name}') is read-only.`
3279
- );
3280
- };
3281
- observer.set = readOnlyError('set');
3282
- observer.toggle = readOnlyError('toggle');
3283
- observer.reset = readOnlyError('reset');
2650
+ const _stop = function(element, eventName, callback) {
2651
+ const handler = (event) => {
2652
+ event.stopPropagation();
2653
+ callback && callback.call(element, event);
3284
2654
  };
2655
+ element.addEventListener(eventName, handler);
2656
+ return this;
2657
+ };
3285
2658
 
3286
- const $createObservable = (value, options = {}) => {
3287
- if(Array.isArray(value)) {
3288
- return Observable.array(value, options);
3289
- }
3290
- if(typeof value === 'object') {
3291
- return Observable.object(value, options);
3292
- }
3293
- return Observable(value, options);
2659
+ const _preventStop = function(element, eventName, callback) {
2660
+ const handler = (event) => {
2661
+ event.stopPropagation();
2662
+ event.preventDefault();
2663
+ callback && callback.call(element, event);
3294
2664
  };
2665
+ element.addEventListener(eventName, handler);
2666
+ return this;
2667
+ };
3295
2668
 
3296
- const $api = {
3297
- /**
3298
- * Create a new state and return the observer.
3299
- * Throws if a store with the same name already exists.
3300
- *
3301
- * @param {string} name
3302
- * @param {*} value
3303
- * @returns {ObservableItem}
3304
- */
3305
- create(name, value) {
3306
- if ($stores.has(name)) {
3307
- DebugManager$1.warn('Store', `Store.create('${name}') : a store with this name already exists. Use Store.get('${name}') to retrieve it.`);
3308
- throw new NativeDocumentError(
3309
- `Store.create('${name}') : a store with this name already exists.`
3310
- );
3311
- }
3312
- const observer = $createObservable(value);
3313
- $stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: false });
3314
- return observer;
3315
- },
3316
-
3317
- /**
3318
- * Create a new resettable state and return the observer.
3319
- * The store can be reset to its initial value via Store.reset(name).
3320
- * Throws if a store with the same name already exists.
3321
- *
3322
- * @param {string} name
3323
- * @param {*} value
3324
- * @returns {ObservableItem}
3325
- */
3326
- createResettable(name, value) {
3327
- if ($stores.has(name)) {
3328
- DebugManager$1.warn('Store', `Store.createResettable('${name}') : a store with this name already exists.`);
3329
- throw new NativeDocumentError(
3330
- `Store.createResettable('${name}') : a store with this name already exists.`
3331
- );
3332
- }
3333
- const observer = $createObservable(value, { reset: true });
3334
- $stores.set(name, { observer, subscribers: new Set(), resettable: true, composed: false });
3335
- return observer;
3336
- },
3337
2669
 
3338
- /**
3339
- * Create a computed store derived from other stores.
3340
- * The value is automatically recalculated when any dependency changes.
3341
- * This store is read-only — Store.use() and Store.set() will throw.
3342
- * Throws if a store with the same name already exists.
3343
- *
3344
- * @param {string} name
3345
- * @param {() => *} computation - Function that returns the computed value
3346
- * @param {string[]} dependencies - Names of the stores to watch
3347
- * @returns {ObservableItem}
3348
- *
3349
- * @example
3350
- * Store.create('products', [{ id: 1, price: 10 }]);
3351
- * Store.create('cart', [{ productId: 1, quantity: 2 }]);
3352
- *
3353
- * Store.createComposed('total', () => {
3354
- * const products = Store.get('products').val();
3355
- * const cart = Store.get('cart').val();
3356
- * return cart.reduce((sum, item) => {
3357
- * const product = products.find(p => p.id === item.productId);
3358
- * return sum + (product.price * item.quantity);
3359
- * }, 0);
3360
- * }, ['products', 'cart']);
3361
- */
3362
- createComposed(name, computation, dependencies) {
3363
- if ($stores.has(name)) {
3364
- DebugManager$1.warn('Store', `Store.createComposed('${name}') : a store with this name already exists.`);
3365
- throw new NativeDocumentError(
3366
- `Store.createComposed('${name}') : a store with this name already exists.`
3367
- );
3368
- }
3369
- if (typeof computation !== 'function') {
3370
- throw new NativeDocumentError(
3371
- `Store.createComposed('${name}') : computation must be a function.`
3372
- );
3373
- }
3374
- if (!Array.isArray(dependencies) || dependencies.length === 0) {
3375
- throw new NativeDocumentError(
3376
- `Store.createComposed('${name}') : dependencies must be a non-empty array of store names.`
3377
- );
3378
- }
3379
2670
 
3380
- // Resolve dependency observers
3381
- const depObservers = dependencies.map(depName => {
3382
- if(typeof depName !== 'string') {
3383
- return depName;
3384
- }
3385
- const depItem = $stores.get(depName);
3386
- if (!depItem) {
3387
- DebugManager$1.error('Store', `Store.createComposed('${name}') : dependency '${depName}' not found. Create it first.`);
3388
- throw new NativeDocumentError(
3389
- `Store.createComposed('${name}') : dependency store '${depName}' not found.`
3390
- );
3391
- }
3392
- return depItem.observer;
3393
- });
3394
-
3395
- // Create computed observable from dependency observers
3396
- const observer = Observable.computed(computation, depObservers);
3397
-
3398
- $stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: true });
3399
- return observer;
3400
- },
3401
-
3402
- /**
3403
- * Returns true if a store with the given name exists.
3404
- *
3405
- * @param {string} name
3406
- * @returns {boolean}
3407
- */
3408
- has(name) {
3409
- return $stores.has(name);
3410
- },
3411
-
3412
- /**
3413
- * Resets a resettable store to its initial value and notifies all subscribers.
3414
- * Throws if the store was not created with createResettable().
3415
- *
3416
- * @param {string} name
3417
- */
3418
- reset(name) {
3419
- const item = $getStoreOrThrow('reset', name);
3420
- if (item.composed) {
3421
- DebugManager$1.error('Store', `Store.reset('${name}') : composed stores cannot be reset. Their value is derived from dependencies.`);
3422
- throw new NativeDocumentError(
3423
- `Store.reset('${name}') : composed stores cannot be reset.`
3424
- );
3425
- }
3426
- if (!item.resettable) {
3427
- DebugManager$1.error('Store', `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`);
3428
- throw new NativeDocumentError(
3429
- `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`
3430
- );
3431
- }
3432
- item.observer.reset();
3433
- },
3434
-
3435
- /**
3436
- * Returns a two-way synchronized follower of the store.
3437
- * Writing to the follower propagates the value back to the store and all its subscribers.
3438
- * Throws if called on a composed store — use Store.follow() instead.
3439
- * Call follower.destroy() or follower.dispose() to unsubscribe.
3440
- *
3441
- * @param {string} name
3442
- * @returns {ObservableItem}
3443
- */
3444
- use(name) {
3445
- const item = $getStoreOrThrow('use', name);
3446
-
3447
- if (item.composed) {
3448
- DebugManager$1.error('Store', `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`);
3449
- throw new NativeDocumentError(
3450
- `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`
3451
- );
3452
- }
3453
-
3454
- const { observer: originalObserver, subscribers } = item;
3455
- const observerFollower = $createObservable(originalObserver.val());
3456
-
3457
- const onStoreChange = value => observerFollower.set(value);
3458
- const onFollowerChange = value => originalObserver.set(value);
3459
-
3460
- originalObserver.subscribe(onStoreChange);
3461
- observerFollower.subscribe(onFollowerChange);
3462
-
3463
- observerFollower.destroy = () => {
3464
- originalObserver.unsubscribe(onStoreChange);
3465
- observerFollower.unsubscribe(onFollowerChange);
3466
- subscribers.delete(observerFollower);
3467
- observerFollower.cleanup();
3468
- };
3469
- observerFollower.dispose = observerFollower.destroy;
3470
-
3471
- subscribers.add(observerFollower);
3472
- return observerFollower;
3473
- },
3474
-
3475
- /**
3476
- * Returns a read-only follower of the store.
3477
- * The follower reflects store changes but cannot write back to the store.
3478
- * Any attempt to call .set(), .toggle() or .reset() will throw.
3479
- * Call follower.destroy() or follower.dispose() to unsubscribe.
3480
- *
3481
- * @param {string} name
3482
- * @returns {ObservableItem}
3483
- */
3484
- follow(name) {
3485
- const { observer: originalObserver, subscribers } = $getStoreOrThrow('follow', name);
3486
- const observerFollower = $createObservable(originalObserver.val());
3487
-
3488
- const onStoreChange = value => observerFollower.set(value);
3489
- originalObserver.subscribe(onStoreChange);
3490
-
3491
- $applyReadOnly(observerFollower, name, 'follow');
3492
-
3493
- observerFollower.destroy = () => {
3494
- originalObserver.unsubscribe(onStoreChange);
3495
- subscribers.delete(observerFollower);
3496
- observerFollower.cleanup();
3497
- };
3498
- observerFollower.dispose = observerFollower.destroy;
3499
-
3500
- subscribers.add(observerFollower);
3501
- return observerFollower;
3502
- },
3503
-
3504
- /**
3505
- * Returns the raw store observer directly (no follower, no cleanup contract).
3506
- * Use this for direct read access when you don't need to unsubscribe.
3507
- * WARNING : mutations on this observer impact all subscribers immediately.
3508
- *
3509
- * @param {string} name
3510
- * @returns {ObservableItem|null}
3511
- */
3512
- get(name) {
3513
- const item = $stores.get(name);
3514
- if (!item) {
3515
- DebugManager$1.warn('Store', `Store.get('${name}') : store not found.`);
3516
- return null;
3517
- }
3518
- return item.observer;
3519
- },
3520
-
3521
- /**
3522
- * @param {string} name
3523
- * @returns {{ observer: ObservableItem, subscribers: Set } | null}
3524
- */
3525
- getWithSubscribers(name) {
3526
- return $stores.get(name) ?? null;
3527
- },
3528
-
3529
- /**
3530
- * Destroys a store : cleans up the observer, destroys all followers, and removes the entry.
3531
- *
3532
- * @param {string} name
3533
- */
3534
- delete(name) {
3535
- const item = $stores.get(name);
3536
- if (!item) {
3537
- DebugManager$1.warn('Store', `Store.delete('${name}') : store not found, nothing to delete.`);
3538
- return;
3539
- }
3540
- item.subscribers.forEach(follower => follower.destroy());
3541
- item.subscribers.clear();
3542
- item.observer.cleanup();
3543
- $stores.delete(name);
3544
- },
3545
- /**
3546
- * Creates an isolated store group with its own state namespace.
3547
- * Each group is a fully independent StoreFactory instance —
3548
- * no key conflicts, no shared state with the parent store.
3549
- *
3550
- * @param {string | ((group: ReturnType<typeof StoreFactory>) => void)} name - Group name for debugging, or setup callback if no name is provided
3551
- * @param {((group: ReturnType<typeof StoreFactory>) => void)} [callback] - Setup function receiving the isolated store instance
3552
- * @returns {ReturnType<typeof StoreFactory>}
3553
- *
3554
- * @example
3555
- * // With name (recommended)
3556
- * const EventStore = Store.group('events', (group) => {
3557
- * group.create('catalog', []);
3558
- * group.create('filters', { category: null, date: null });
3559
- * group.createResettable('selected', null);
3560
- * group.createComposed('filtered', () => {
3561
- * const catalog = EventStore.get('catalog').val();
3562
- * const filters = EventStore.get('filters').val();
3563
- * return catalog.filter(event => {
3564
- * if (filters.category && event.category !== filters.category) return false;
3565
- * return true;
3566
- * });
3567
- * }, ['catalog', 'filters']);
3568
- * });
3569
- *
3570
- * // Without name
3571
- * const CartStore = Store.group((group) => {
3572
- * group.create('items', []);
3573
- * });
3574
- *
3575
- * // Usage
3576
- * EventStore.use('catalog'); // two-way follower
3577
- * EventStore.follow('filtered'); // read-only follower
3578
- * EventStore.get('filters'); // raw observable
3579
- *
3580
- * // Cross-group composed
3581
- * const OrderStore = Store.group('orders', (group) => {
3582
- * group.createComposed('summary', () => {
3583
- * const items = CartStore.get('items').val();
3584
- * const events = EventStore.get('catalog').val();
3585
- * return { items, events };
3586
- * }, [CartStore.get('items'), EventStore.get('catalog')]);
3587
- * });
3588
- */
3589
- group(name, callback) {
3590
- if (typeof name === 'function') {
3591
- callback = name;
3592
- name = 'anonymous';
3593
- }
3594
- const store = StoreFactory();
3595
- callback && callback(store);
3596
- return store;
3597
- },
3598
- createPersistent(name, value, localstorage_key) {
3599
- localstorage_key = localstorage_key || name;
3600
- const observer = this.create(name, $getFromStorage(localstorage_key, value));
3601
- const saver = $saveToStorage(value);
3602
-
3603
- observer.subscribe((val) => saver(localstorage_key, val));
3604
- return observer;
3605
- },
3606
- createPersistentResettable(name, value, localstorage_key) {
3607
- localstorage_key = localstorage_key || name;
3608
- const observer = this.createResettable(name, $getFromStorage(localstorage_key, value));
3609
- const saver = $saveToStorage(value);
3610
- observer.subscribe((val) => saver(localstorage_key, val));
3611
-
3612
- const originalReset = observer.reset.bind(observer);
3613
- observer.reset = () => {
3614
- LocalStorage.remove(localstorage_key);
3615
- originalReset();
3616
- };
3617
-
3618
- return observer;
3619
- }
3620
- };
3621
-
3622
-
3623
- return new Proxy($api, {
3624
- get(target, prop) {
3625
- if (typeof prop === 'symbol' || prop.startsWith('$') || prop in target) {
3626
- return target[prop];
3627
- }
3628
- if (target.has(prop)) {
3629
- if ($followersCache.has(prop)) {
3630
- return $followersCache.get(prop);
3631
- }
3632
- const follower = target.follow(prop);
3633
- $followersCache.set(prop, follower);
3634
- return follower;
3635
- }
3636
- return undefined;
3637
- },
3638
- set(target, prop, value) {
3639
- DebugManager$1.error('Store', `Forbidden: You cannot overwrite the store key '${String(prop)}'. Use .use('${String(prop)}').set(value) instead.`);
3640
- throw new NativeDocumentError(`Store structure is immutable. Use .set() on the observable.`);
3641
- },
3642
- deleteProperty(target, prop) {
3643
- throw new NativeDocumentError(`Store keys cannot be deleted.`);
3644
- }
3645
- });
3646
- };
3647
-
3648
- const Store = StoreFactory();
3649
-
3650
- Store.create('locale', navigator.language.split('-')[0] || 'en');
3651
-
3652
- function oneChildAnchorOverwriting(anchor, parent) {
3653
-
3654
- anchor.remove = () => {
3655
- anchor.append.apply(anchor, parent.childNodes);
3656
- };
3657
- anchor.getParent = () => parent;
3658
-
3659
- anchor.appendChild = (child) => {
3660
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3661
- parent.appendChild(child);
3662
- };
3663
-
3664
- anchor.appendChildRaw = parent.appendChild.bind(parent);
3665
- anchor.append = anchor.appendChild;
3666
- anchor.appendRaw = anchor.appendChildRaw;
3667
-
3668
- anchor.insertAtStart = (child) => {
3669
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3670
- parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
3671
- };
3672
- anchor.insertAtStartRaw = (child) => {
3673
- parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
3674
- };
3675
-
3676
- anchor.appendElement = anchor.appendChild;
3677
-
3678
- anchor.removeChildren = () => {
3679
- parent.textContent = '';
3680
- };
3681
-
3682
- anchor.replaceContent = function(content) {
3683
- const child = Validator.isElement(content) ? content : ElementCreator.getChild(content);
3684
- parent.replaceChildren(child);
3685
- };
3686
-
3687
- anchor.replaceContentRaw = function(child) {
3688
- parent.replaceChildren(child);
3689
- };
3690
- anchor.setContent = anchor.replaceContent;
3691
-
3692
- anchor.insertBefore = (child, anchor) => {
3693
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3694
- parent.insertBefore(child, anchor);
3695
- };
3696
- anchor.insertBeforeRaw = (child, anchor) => {
3697
- parent.insertBefore(child, anchor);
3698
- };
3699
-
3700
- anchor.appendChildBefore = anchor.insertBefore;
3701
- anchor.appendChildBeforeRaw = anchor.insertBeforeRaw;
3702
-
3703
- anchor.clear = anchor.remove;
3704
- anchor.detach = anchor.remove;
3705
-
3706
- anchor.replaceChildren = function() {
3707
- parent.replaceChildren(...arguments);
3708
- };
3709
-
3710
- anchor.getByIndex = (index) => {
3711
- return parent.childNodes[index];
3712
- };
3713
- }
3714
-
3715
- function Anchor(name, isUniqueChild = false) {
3716
- const anchorFragment = new AnchorWithSentinel(name);
3717
-
3718
- anchorFragment.onConnectedOnce((parent) => {
3719
- if(isUniqueChild) {
3720
- oneChildAnchorOverwriting(anchorFragment, parent);
3721
- }
3722
- });
3723
-
3724
- anchorFragment.__Anchor__ = true;
3725
-
3726
- const anchorStart = anchorFragment.$start;
3727
- const anchorEnd = anchorFragment.$end;
3728
-
3729
- anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
3730
- anchorFragment.nativeAppendChild = anchorFragment.appendChild;
3731
- anchorFragment.nativeAppend = anchorFragment.append;
3732
-
3733
- const isParentUniqueChild = isUniqueChild
3734
- ? () => true: (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
3735
-
3736
- const insertBefore = (parent, child, target) => {
3737
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3738
- insertBeforeRaw(parent, childElement, target);
3739
- };
3740
-
3741
- const insertBeforeRaw = (parent, child, target) => {
3742
- if(parent === anchorFragment) {
3743
- parent.nativeInsertBefore(child, target);
3744
- return;
3745
- }
3746
- if(isParentUniqueChild(parent) && target === anchorEnd) {
3747
- parent.append(child, target);
3748
- return;
3749
- }
3750
- parent.insertBefore(child, target);
3751
- };
3752
-
3753
- anchorFragment.appendElement = function(child) {
3754
- const parentNode = anchorStart.parentNode;
3755
- if(parentNode === anchorFragment) {
3756
- parentNode.nativeInsertBefore(child, anchorEnd);
3757
- return;
3758
- }
3759
- parentNode.insertBefore(child, anchorEnd);
3760
- };
3761
-
3762
- anchorFragment.appendChild = function(child, before = null) {
3763
- const parent = anchorEnd.parentNode;
3764
- if(!parent) {
3765
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
3766
- return;
3767
- }
3768
- before = before ?? anchorEnd;
3769
- insertBefore(parent, child, before);
3770
- };
3771
-
3772
- anchorFragment.appendChildRaw = function(child, before = null) {
3773
- const parent = anchorEnd.parentNode;
3774
- if(!parent) {
3775
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
3776
- return;
3777
- }
3778
- before = before ?? anchorEnd;
3779
- insertBeforeRaw(parent, child, before);
3780
- };
3781
-
3782
- anchorFragment.getParent = () => anchorEnd.parentNode;
3783
- anchorFragment.append = anchorFragment.appendChild;
3784
- anchorFragment.appendRaw = anchorFragment.appendChildRaw;
3785
-
3786
- anchorFragment.insertAtStart = function(child) {
3787
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3788
- anchorFragment.insertAtStartRaw(child);
3789
- };
3790
-
3791
- anchorFragment.insertAtStartRaw = function(child) {
3792
- const parentNode = anchorStart.parentNode;
3793
- if(parentNode === anchorFragment) {
3794
- parentNode.nativeInsertBefore(child, anchorStart);
3795
- return;
3796
- }
3797
- parentNode.insertBefore(child, anchorStart);
3798
- };
3799
-
3800
- anchorFragment.removeChildren = function() {
3801
- const parent = anchorEnd.parentNode;
3802
- if(parent === anchorFragment) {
3803
- return;
3804
- }
3805
- if(isParentUniqueChild(parent)) {
3806
- parent.replaceChildren(anchorStart, anchorEnd);
3807
- return;
3808
- }
3809
-
3810
- let itemToRemove = anchorStart.nextSibling, tempItem;
3811
- while(itemToRemove && itemToRemove !== anchorEnd) {
3812
- tempItem = itemToRemove.nextSibling;
3813
- itemToRemove.remove();
3814
- itemToRemove = tempItem;
3815
- }
3816
- };
3817
-
3818
- anchorFragment.remove = function() {
3819
- const parent = anchorEnd.parentNode;
3820
- if(parent === anchorFragment) {
3821
- return;
3822
- }
3823
- if(isParentUniqueChild(parent)) {
3824
- anchorFragment.nativeAppend.apply(anchorFragment, parent.childNodes);
3825
- parent.replaceChildren(anchorStart, anchorEnd);
3826
- return;
3827
- }
3828
- let itemToRemove = anchorStart.nextSibling, tempItem;
3829
- while(itemToRemove && itemToRemove !== anchorEnd) {
3830
- tempItem = itemToRemove.nextSibling;
3831
- anchorFragment.nativeAppend(itemToRemove);
3832
- itemToRemove = tempItem;
3833
- }
3834
- };
3835
-
3836
- anchorFragment.removeWithAnchors = function() {
3837
- anchorFragment.removeChildren();
3838
- anchorStart.remove();
3839
- anchorEnd.remove();
3840
- };
3841
- anchorFragment.delete = anchorFragment.removeWithAnchors;
3842
-
3843
- anchorFragment.replaceContent = function(child) {
3844
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3845
- anchorFragment.replaceContentRaw(childElement);
3846
- };
3847
-
3848
- anchorFragment.replaceContentRaw = function(child) {
3849
- const parent = anchorEnd.parentNode;
3850
- if(!parent) {
3851
- return;
3852
- }
3853
- if(isParentUniqueChild(parent)) {
3854
- parent.replaceChildren(anchorStart, child, anchorEnd);
3855
- return;
3856
- }
3857
- anchorFragment.removeChildren();
3858
- parent.insertBefore(child, anchorEnd);
3859
- };
3860
-
3861
- anchorFragment.setContent = anchorFragment.replaceContent;
3862
- anchorFragment.setContentRaw = anchorFragment.replaceContentRaw;
3863
-
3864
- anchorFragment.insertBefore = anchorFragment.appendChild;
3865
- anchorFragment.insertBeforeRaw = anchorFragment.appendChildRaw;
3866
-
3867
- anchorFragment.endElement = function() {
3868
- return anchorEnd;
3869
- };
3870
-
3871
- anchorFragment.startElement = function() {
3872
- return anchorStart;
3873
- };
3874
-
3875
- anchorFragment.restore = function() {
3876
- anchorFragment.appendChild(anchorFragment);
3877
- };
3878
-
3879
- anchorFragment.clear = anchorFragment.remove;
3880
- anchorFragment.detach = anchorFragment.remove;
3881
-
3882
- anchorFragment.getByIndex = function(index) {
3883
- let currentNode = anchorStart;
3884
- for(let i = 0; i <= index; i++) {
3885
- if(!currentNode.nextSibling) {
3886
- return null;
3887
- }
3888
- currentNode = currentNode.nextSibling;
3889
- }
3890
- return currentNode !== anchorStart ? currentNode : null;
3891
- };
3892
-
3893
- return anchorFragment;
3894
- }
3895
- DocumentFragment.prototype.setAttribute = () => {};
3896
-
3897
- function NDElement(element) {
3898
- this.$element = element;
3899
- this.$attachements = null;
3900
- }
3901
-
3902
- NDElement.prototype.__$isNDElement = true;
3903
-
3904
- NDElement.prototype.ghostDom = function(element) {
3905
- if(!this.$attachements) {
3906
- this.$attachements = document.createDocumentFragment();
3907
- }
3908
- this.$attachements.appendChild(ElementCreator.getChild(element));
3909
- return this;
3910
- };
3911
-
3912
- NDElement.prototype.valueOf = function() {
3913
- return this.$element;
3914
- };
3915
-
3916
- NDElement.prototype.ref = function(target, name) {
3917
- target[name] = this.$element;
3918
- return this;
3919
- };
3920
-
3921
- NDElement.prototype.refSelf = function(target, name) {
3922
- target[name] = this;
3923
- // TODO: @DIM to check
3924
- // target[name] = new NDElement(this.$element);
3925
- return this;
3926
- };
3927
-
3928
- NDElement.prototype.unmountChildren = function() {
3929
- let element = this.$element;
3930
- for(let i = 0, length = element.children.length; i < length; i++) {
3931
- let elementChildren = element.children[i];
3932
- if(!elementChildren.$ndProx) {
3933
- elementChildren.nd?.remove();
3934
- }
3935
- elementChildren = null;
3936
- }
3937
- element = null;
3938
- return this;
3939
- };
3940
-
3941
- NDElement.prototype.remove = function() {
3942
- let element = this.$element;
3943
- element.nd.unmountChildren();
3944
- element.$ndProx = null;
3945
-
3946
- $lifeCycleObservers.delete(element);
3947
-
3948
- element = null;
3949
- return this;
3950
- };
3951
-
3952
- const $lifeCycleObservers = new WeakMap();
3953
- NDElement.prototype.lifecycle = function(states) {
3954
- const el = this.$element;
3955
- if (!$lifeCycleObservers.has(el)) {
3956
- $lifeCycleObservers.set(el, DocumentObserver.watch(el));
3957
- }
3958
- const observer = $lifeCycleObservers.get(el);
3959
-
3960
- if(states.mounted) {
3961
- this.$element.setAttribute('data--nd-mounted', '1');
3962
- observer.mounted(states.mounted);
3963
- }
3964
- if(states.unmounted) {
3965
- this.$element.setAttribute('data--nd-unmounted', '1');
3966
- observer.unmounted(states.unmounted);
3967
- }
3968
- return this;
3969
- };
3970
-
3971
- NDElement.prototype.mounted = function(callback) {
3972
- return this.lifecycle({ mounted: callback });
3973
- };
3974
-
3975
- NDElement.prototype.unmounted = function(callback) {
3976
- return this.lifecycle({ unmounted: callback });
3977
- };
3978
-
3979
- NDElement.prototype.beforeUnmount = function(id, callback) {
3980
- const el = this.$element;
3981
-
3982
- if(!DocumentObserver.beforeUnmount.has(el)) {
3983
- DocumentObserver.beforeUnmount.set(el, new Map());
3984
- const originalRemove = el.remove.bind(el);
3985
-
3986
- let $isUnmounting = false;
3987
-
3988
- el.remove = async () => {
3989
- if($isUnmounting) {
3990
- return;
3991
- }
3992
- $isUnmounting = true;
3993
-
3994
- try {
3995
- const callbacks = DocumentObserver.beforeUnmount.get(el);
3996
- for (const cb of callbacks.values()) {
3997
- await cb.call(this, el);
3998
- }
3999
- } finally {
4000
- originalRemove();
4001
- $isUnmounting = false;
4002
- }
4003
- };
4004
- }
4005
-
4006
- DocumentObserver.beforeUnmount.get(el).set(id, callback);
4007
- return this;
4008
- };
4009
-
4010
- NDElement.prototype.htmlElement = function() {
4011
- return this.$element;
4012
- };
4013
-
4014
- NDElement.prototype.node = NDElement.prototype.htmlElement;
4015
-
4016
- NDElement.prototype.shadow = function(mode, style = null) {
4017
- const $element = this.$element;
4018
- const children = Array.from($element.childNodes);
4019
- const shadowRoot = $element.attachShadow({ mode });
4020
- if(style) {
4021
- const styleNode = document.createElement("style");
4022
- styleNode.textContent = style;
4023
- shadowRoot.appendChild(styleNode);
4024
- }
4025
- $element.append = shadowRoot.append.bind(shadowRoot);
4026
- $element.appendChild = shadowRoot.appendChild.bind(shadowRoot);
4027
- shadowRoot.append(...children);
4028
-
4029
- return this;
4030
- };
4031
-
4032
- NDElement.prototype.openShadow = function(style = null) {
4033
- return this.shadow('open', style);
4034
- };
4035
-
4036
- NDElement.prototype.closedShadow = function(style = null) {
4037
- return this.shadow('closed', style);
4038
- };
4039
-
4040
- /**
4041
- * Extends the current NDElement instance with custom methods.
4042
- * Methods are bound to the instance and available for chaining.
4043
- *
4044
- * @param {Object} methods - Object containing method definitions
4045
- * @returns {this} The NDElement instance with added methods for chaining
4046
- * @example
4047
- * element.nd.with({
4048
- * highlight() {
4049
- * this.$element.style.background = 'yellow';
4050
- * return this;
4051
- * }
4052
- * }).highlight().onClick(() => console.log('Clicked'));
4053
- */
4054
- NDElement.prototype.with = function(methods) {
4055
- if (!methods || typeof methods !== 'object') {
4056
- throw new NativeDocumentError('extend() requires an object of methods');
4057
- }
4058
-
4059
- for (const name in methods) {
4060
- const method = methods[name];
4061
-
4062
- if (typeof method !== 'function') {
4063
- DebugManager$1.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
4064
- continue;
4065
- }
4066
-
4067
- this[name] = method.bind(this);
4068
- }
4069
-
4070
- return this;
4071
- };
4072
-
4073
- /**
4074
- * Extends the NDElement prototype with new methods available to all NDElement instances.
4075
- * Use this to add global methods to all NDElements.
4076
- *
4077
- * @param {Object} methods - Object containing method definitions to add to prototype
4078
- * @returns {typeof NDElement} The NDElement constructor
4079
- * @throws {NativeDocumentError} If methods is not an object or contains non-function values
4080
- * @example
4081
- * NDElement.extend({
4082
- * fadeIn() {
4083
- * this.$element.style.opacity = '1';
4084
- * return this;
4085
- * }
4086
- * });
4087
- * // Now all NDElements have .fadeIn() method
4088
- * Div().nd.fadeIn();
4089
- */
4090
- NDElement.extend = function(methods) {
4091
- if (!methods || typeof methods !== 'object') {
4092
- throw new NativeDocumentError('NDElement.extend() requires an object of methods');
4093
- }
4094
-
4095
- if (Array.isArray(methods)) {
4096
- throw new NativeDocumentError('NDElement.extend() requires an object, not an array');
4097
- }
4098
-
4099
- const protectedMethods = new Set([
4100
- 'constructor', 'valueOf', '$element', '$observer',
4101
- 'ref', 'remove', 'cleanup', 'with', 'extend', 'attach',
4102
- 'lifecycle', 'mounted', 'unmounted', 'unmountChildren'
4103
- ]);
4104
-
4105
- for (const name in methods) {
4106
- if (!Object.hasOwn(methods, name)) {
4107
- continue;
4108
- }
4109
-
4110
- const method = methods[name];
4111
-
4112
- if (typeof method !== 'function') {
4113
- DebugManager$1.warn('NDElement.extend', `"${name}" is not a function, skipping`);
4114
- continue;
4115
- }
4116
-
4117
- if (protectedMethods.has(name)) {
4118
- DebugManager$1.error('NDElement.extend', `Cannot override protected method "${name}"`);
4119
- throw new NativeDocumentError(`Cannot override protected method "${name}"`);
4120
- }
4121
-
4122
- if (NDElement.prototype[name]) {
4123
- DebugManager$1.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
4124
- }
4125
-
4126
- NDElement.prototype[name] = method;
4127
- }
4128
-
4129
- return NDElement;
4130
- };
4131
-
4132
- const COMMON_NODE_TYPES = {
4133
- ELEMENT: 1,
4134
- TEXT: 3,
4135
- COMMENT: 8,
4136
- DOCUMENT_FRAGMENT: 11
4137
- };
4138
-
4139
- const VALID_TYPES = [];
4140
- VALID_TYPES[COMMON_NODE_TYPES.ELEMENT] = true;
4141
- VALID_TYPES[COMMON_NODE_TYPES.TEXT] = true;
4142
- VALID_TYPES[COMMON_NODE_TYPES.DOCUMENT_FRAGMENT] = true;
4143
- VALID_TYPES[COMMON_NODE_TYPES.COMMENT] = true;
4144
-
4145
- const Validator = {
4146
- isObservable(value) {
4147
- return value && (value.__$isObservable || value.__$Observable);
4148
- },
4149
- isTemplateBinding(value) {
4150
- return value?.__$isTemplateBinding;
4151
- },
4152
- isObservableWhenResult(value) {
4153
- return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
4154
- },
4155
- isArrayObservable(value) {
4156
- return value?.__$isObservableArray;
4157
- },
4158
- isProxy(value) {
4159
- return value?.__isProxy__
4160
- },
4161
- isObservableOrProxy(value) {
4162
- return Validator.isObservable(value) || Validator.isProxy(value);
4163
- },
4164
- isAnchor(value) {
4165
- return value?.__Anchor__
4166
- },
4167
- isObservableChecker(value) {
4168
- return value?.__$isObservableChecker || value instanceof ObservableChecker;
4169
- },
4170
- isArray(value) {
4171
- return Array.isArray(value);
4172
- },
4173
- isString(value) {
4174
- return typeof value === 'string';
4175
- },
4176
- isNumber(value) {
4177
- return typeof value === 'number';
4178
- },
4179
- isBoolean(value) {
4180
- return typeof value === 'boolean';
4181
- },
4182
- isFunction(value) {
4183
- return typeof value === 'function';
4184
- },
4185
- isAsyncFunction(value) {
4186
- return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
4187
- },
4188
- isObject(value) {
4189
- return typeof value === 'object' && value !== null;
4190
- },
4191
- isJson(value) {
4192
- return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
4193
- },
4194
- isElement(value) {
4195
- return value && VALID_TYPES[value.nodeType];
4196
- },
4197
- isDOMNode(value) {
4198
- return VALID_TYPES[value.nodeType];
4199
- },
4200
- isFragment(value) {
4201
- return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
4202
- },
4203
- isStringOrObservable(value) {
4204
- return this.isString(value) || this.isObservable(value);
4205
- },
4206
- isValidChild(child) {
4207
- return child === null ||
4208
- this.isElement(child) ||
4209
- this.isObservable(child) ||
4210
- this.isNDElement(child) ||
4211
- ['string', 'number', 'boolean'].includes(typeof child);
4212
- },
4213
- isNDElement(child) {
4214
- return child?.__$isNDElement || child instanceof NDElement;
2671
+ // ----------------------------------------------------------------
2672
+ // Class attributes binder
2673
+ // ----------------------------------------------------------------
2674
+ const classListMethods = {
2675
+ getClasses() {
2676
+ return this.$element.className?.split(' ').filter(Boolean);
4215
2677
  },
4216
- isValidChildren(children) {
4217
- if (!Array.isArray(children)) {
4218
- children = [children];
2678
+ add(value) {
2679
+ const classes = this.getClasses();
2680
+ if(classes.indexOf(value) >= 0) {
2681
+ return;
4219
2682
  }
4220
-
4221
- const invalid = children.filter(child => !this.isValidChild(child));
4222
- return invalid.length === 0;
2683
+ classes.push(value);
2684
+ this.$element.className = classes.join(' ');
4223
2685
  },
4224
- validateChildren(children) {
4225
- if (!Array.isArray(children)) {
4226
- children = [children];
4227
- }
4228
-
4229
- const invalid = children.filter(child => !this.isValidChild(child));
4230
- if (invalid.length > 0) {
4231
- throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
2686
+ remove(value) {
2687
+ const classes = this.getClasses();
2688
+ const index = classes.indexOf(value);
2689
+ if(index < 0) {
2690
+ return;
4232
2691
  }
4233
-
4234
- return children;
2692
+ classes.splice(index, 1);
2693
+ this.$element.className = classes.join(' ');
4235
2694
  },
4236
- /**
4237
- * Check if the data contains observables.
4238
- * @param {Array|Object} data
4239
- * @returns {boolean}
4240
- */
4241
- containsObservables(data) {
4242
- if(!data) {
4243
- return false;
2695
+ toggle(value, force = undefined) {
2696
+ const classes = this.getClasses();
2697
+ const index = classes.indexOf(value);
2698
+ if(index >= 0) {
2699
+ if(force === true) {
2700
+ return;
2701
+ }
2702
+ classes.splice(index, 1);
4244
2703
  }
4245
- return Validator.isObject(data)
4246
- && Object.values(data).some(value => Validator.isObservable(value));
4247
- },
4248
- /**
4249
- * Check if the data contains an observable reference.
4250
- * @param {string} data
4251
- * @returns {boolean}
4252
- */
4253
- containsObservableReference(data) {
4254
- if(!data || typeof data !== 'string') {
4255
- return false;
2704
+ else {
2705
+ if(force === false) {
2706
+ return;
2707
+ }
2708
+ classes.push(value);
4256
2709
  }
4257
- return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
2710
+ this.$element.className = classes.join(' ');
4258
2711
  },
4259
- validateAttributes(attributes) {},
4260
-
4261
- validateEventCallback(callback) {
4262
- if (typeof callback !== 'function') {
4263
- throw new NativeDocumentError('Event callback must be a function');
4264
- }
2712
+ contains(value) {
2713
+ return this.getClasses().indexOf(value) >= 0;
4265
2714
  }
4266
2715
  };
4267
2716
 
4268
- function createMultiSourceFilter(sources, callbackFn){
4269
- const observables = sources.filter(Validator.isObservable);
4270
-
4271
- const getValues = () => sources.map(src =>
4272
- Validator.isObservable(src) ? src.val() : src
4273
- );
4274
-
4275
- return {
4276
- dependencies: observables.length > 0 ? observables : null,
4277
- callback: (value) => callbackFn(value, getValues())
4278
- };
4279
- }
4280
-
4281
- function match(patternObservableOrValue, asRegexObservableOrValue = true, flagsObservableOrValue = ''){
4282
- return createMultiSourceFilter(
4283
- [patternObservableOrValue, asRegexObservableOrValue, flagsObservableOrValue],
4284
- (value, [pattern, asRegex, flags]) => {
4285
- if (!pattern) return true;
4286
-
4287
- if (asRegex){
4288
- try {
4289
- const regex = new RegExp(pattern, flags);
4290
- return regex.test(String(value));
4291
- } catch (error){
4292
- DebugManager$1.warn('Invalid regex pattern:', pattern, error);
4293
- return false;
4294
- }
4295
- }
4296
-
4297
- if (!flags || flags === ''){
4298
- return String(value).toLowerCase().includes(String(pattern).toLowerCase());
4299
- }
4300
- return String(value).includes(String(pattern));
4301
- }
4302
- );
4303
- }
4304
-
4305
- /**
4306
- * Conditionally shows an element based on an observable condition.
4307
- * The element is mounted/unmounted from the DOM as the condition changes.
4308
- *
4309
- * @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
4310
- * @param {NdChild|(() => NdChild)} child - Element or content to show/hide
4311
- * @param {Object} [options={}] - Configuration options
4312
- * @param {string|null} [options.comment=null] - Comment for debugging
4313
- * @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
4314
- * @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
4315
- * @example
4316
- * const isVisible = Observable(false);
4317
- * ShowIf(isVisible, Div({}, 'Hello World'));
4318
- */
4319
- const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
4320
- if(!Validator.isObservable(condition)) {
4321
- if(typeof condition === "boolean") {
4322
- return condition ? ElementCreator.getChild(child) : null;
4323
- }
4324
-
4325
- return DebugManager$1.warn('ShowIf', "ShowIf : condition must be an Observable or boolean / "+comment, condition);
2717
+ Object.defineProperty(HTMLElement.prototype, 'classes', {
2718
+ configurable: true,
2719
+ get() {
2720
+ return {
2721
+ $element: this,
2722
+ ...classListMethods
2723
+ };
4326
2724
  }
4327
- const element = Anchor('Show if : '+(comment || ''));
4328
-
4329
- let childElement = null;
4330
- const getChildElement = () => {
4331
- if(childElement && shouldKeepInCache) {
4332
- return childElement;
4333
- }
4334
- childElement = ElementCreator.getChild(child);
4335
- if(Validator.isFragment(childElement)) {
4336
- childElement = Array.from(childElement.childNodes);
4337
- }
4338
- return childElement;
4339
- };
4340
-
4341
- const currentValue = condition.val();
2725
+ });
4342
2726
 
4343
- if(currentValue) {
4344
- element.appendChild(getChildElement());
2727
+ const normalizeComponentArgs = function(props, children = null) {
2728
+ if(props && children) {
2729
+ return { props, children };
2730
+ }
2731
+ if(typeof props !== 'object' || Array.isArray(props) || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
2732
+ return { props: children, children: props }
4345
2733
  }
2734
+ return { props, children };
2735
+ };
4346
2736
 
4347
- condition.subscribe((value) => {
4348
- if(!!value) {
4349
- element.appendChild(getChildElement());
4350
- return;
4351
- }
4352
- element.remove();
4353
- });
2737
+ const createHtmlElement = (element, _attributes, _children = null) => {
2738
+ let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
4354
2739
 
2740
+ ElementCreator.processAttributes(element, attributes);
2741
+ ElementCreator.processChildren(children, element);
4355
2742
  return element;
4356
2743
  };
4357
2744
 
2745
+ /**
2746
+ *
2747
+ * @param {string} name
2748
+ * @param {?Function=} customWrapper
2749
+ * @returns {Function}
2750
+ */
2751
+ function HtmlElementWrapper(name, customWrapper = null) {
2752
+ if(name) {
2753
+ if(customWrapper) {
2754
+ let node = null;
2755
+ let createElement = (attr, children) => {
2756
+ node = document.createElement(name);
2757
+ createElement = (attr, children) => {
2758
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children);
2759
+ };
2760
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children); };
2761
+
2762
+ return (attr, children) => createElement(attr, children)
2763
+ }
2764
+
2765
+ let node = null;
2766
+ let createElement = (attr, children) => {
2767
+ node = document.createElement(name);
2768
+ createElement = (attr, children) => {
2769
+ return createHtmlElement(node.cloneNode(), attr, children);
2770
+ };
2771
+ return createHtmlElement(node.cloneNode(), attr, children);
2772
+ };
2773
+
2774
+ return (attr, children) => createElement(attr, children)
2775
+ }
2776
+ return (children, name = '') => {
2777
+ const anchor = Anchor(name);
2778
+ anchor.append(children);
2779
+ return anchor;
2780
+ };
2781
+ }
2782
+
4358
2783
  /**
4359
2784
  * Creates a `<div>` element.
4360
2785
  * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
@@ -5074,7 +3499,7 @@ var NativeComponents = (function (exports) {
5074
3499
 
5075
3500
  Alert.preset = function(name, callback) {
5076
3501
  if (Alert.prototype[name] || Alert[name]) {
5077
- DebugManager$1.warn(`Warning: the ${name} method already exist in Alert.`);
3502
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Alert.`);
5078
3503
  return;
5079
3504
  }
5080
3505
  Alert[name] = (content, props) => callback(new Alert(content, props));
@@ -5259,253 +3684,90 @@ var NativeComponents = (function (exports) {
5259
3684
  * @param {ValidChildren} icon - The icon to display
5260
3685
  * @returns {Alert}
5261
3686
  */
5262
- Alert.prototype.icon = function(icon) {
5263
- this.$description.icon = icon;
5264
- return this;
5265
- };
5266
-
5267
- /**
5268
- * Shows or hides the icon
5269
- * @param {boolean} [show=true] - Whether to show the icon
5270
- * @returns {Alert}
5271
- */
5272
- Alert.prototype.showIcon = function(show = true) {
5273
- this.$description.showIcon = show;
5274
- };
5275
-
5276
- /**
5277
- * Sets whether the alert can be closed
5278
- * @param {boolean} [closable=true] - Whether the alert is closable
5279
- * @returns {Alert}
5280
- */
5281
- Alert.prototype.closable = function(closable = true) {
5282
- this.$description.closable = !!closable;
5283
- if(closable) {
5284
- this.showIf(closable);
5285
- }
5286
- return this;
5287
- };
5288
-
5289
- /**
5290
- * Sets whether the alert is dismissible (alias for closable)
5291
- * @param {boolean} [dismissible=true] - Whether the alert is dismissible
5292
- * @returns {Alert}
5293
- */
5294
- Alert.prototype.dismissible = function(dismissible = true) {
5295
- return this.closable(dismissible);
5296
- };
5297
-
5298
- /**
5299
- * Sets auto-dismiss delay for the alert
5300
- * @param {number} delay - Delay in milliseconds before auto-dismissing
5301
- * @returns {Alert}
5302
- */
5303
- Alert.prototype.autoDismiss = function(delay) {
5304
- this.$description.autoDismiss = delay;
5305
- return this;
5306
- };
5307
-
5308
- /**
5309
- * Closes the alert
5310
- */
5311
- Alert.prototype.close = function() {
5312
- this.$description.showIf?.set(false);
5313
- this.emit('hide');
5314
- };
5315
-
5316
- /**
5317
- * Shows the alert
5318
- */
5319
- Alert.prototype.show = function() {
5320
- this.$description.showIf?.set(true);
5321
- this.emit('show');
5322
- };
5323
-
5324
- /**
5325
- * Hides the alert
5326
- */
5327
- Alert.prototype.hide = Alert.prototype.close;
5328
-
5329
- /**
5330
- * Registers a handler for the close event
5331
- * @param {(element: Alert) => void} handler - The event handler
5332
- * @returns {Alert}
5333
- */
5334
- Alert.prototype.onClose = function(handler) {
5335
- this.on('close', handler);
5336
- return this;
5337
- };
5338
-
5339
- /**
5340
- * Registers a handler for the show event
5341
- * @param {(element: Alert) => void} handler - The event handler
5342
- * @returns {Alert}
5343
- */
5344
- Alert.prototype.onShow = function(handler) {
5345
- this.on('show', handler);
5346
- return this;
5347
- };
5348
-
5349
- function Button(label, props = {}) {
5350
- if(!(this instanceof Button)) {
5351
- return new Button(label, props);
5352
- }
5353
-
5354
- BaseComponent.call(this, props);
5355
-
5356
- this.$description = {
5357
- label: label,
5358
- type: null,
5359
- variant: null,
5360
- size: null,
5361
- icon: null,
5362
- iconPosition: 'left',
5363
- loading: null,
5364
- disabled: null,
5365
- template: null,
5366
- block: null,
5367
- borderRadiusType: null,
5368
- outline: null,
5369
- props
5370
- };
5371
-
5372
- this.$element = null;
5373
- }
5374
-
5375
- Button.defaultTemplate = null;
5376
-
5377
- Button.use = function(template = {}) {
5378
- Button.defaultTemplate = template;
5379
- };
5380
-
5381
- BaseComponent.extends(Button);
5382
-
5383
- Button.preset = function(name, callback) {
5384
- if (Button.prototype[name] || Button[name]) {
5385
- DebugManager$1.warn(`Warning: the ${name} method already exist in Button.`);
5386
- return;
5387
- }
5388
- Button[name] = (label, props) => callback(new Button(label, props));
5389
- };
5390
-
5391
- Button.presets = function(presets) {
5392
- for (const name in presets) {
5393
- Button.preset(name, presets[name]);
5394
- }
5395
- };
5396
-
5397
- Button.prototype.type = function(type) {
5398
- this.$description.type = type;
5399
- return this;
5400
- };
5401
-
5402
- Button.prototype.variant = function(variant) {
5403
- this.$description.variant = variant;
5404
- return this;
5405
- };
5406
- Button.prototype.primary = function() {
5407
- return this.variant('primary');
5408
- };
5409
- Button.prototype.secondary = function() {
5410
- return this.variant('secondary');
5411
- };
5412
- Button.prototype.danger = function() {
5413
- return this.variant('danger');
5414
- };
5415
- Button.prototype.success = function() {
5416
- return this.variant('success');
5417
- };
5418
- Button.prototype.warning = function() {
5419
- return this.variant('warning');
5420
- };
5421
- Button.prototype.ghost = function() {
5422
- return this.variant('ghost');
5423
- };
5424
- Button.prototype.link = function() {
5425
- return this.variant('link');
5426
- };
5427
- Button.prototype.outline = function() {
5428
- this.$description.outline = true;
5429
- return this;
5430
- };
5431
-
5432
- Button.prototype.size = function(size) {
5433
- this.$description.size = size;
5434
- return this;
5435
- };
5436
- Button.prototype.small = function() {
5437
- return this.size('small');
5438
- };
5439
- Button.prototype.large = function() {
5440
- return this.size('large');
5441
- };
5442
- Button.prototype.medium = function() {
5443
- return this.size('medium');
5444
- };
5445
-
5446
- Button.prototype.icon = function(icon, iconPosition = 'leading') {
5447
- this.$description.icon = icon;
5448
- this.$description.iconPosition = iconPosition;
5449
- return this;
5450
- };
5451
-
5452
- Button.prototype.iconAtLeading = function() {
5453
- this.$description.iconPosition = 'leading';
5454
- return this;
5455
- };
5456
-
5457
- Button.prototype.iconAtTrailing = function() {
5458
- this.$description.iconPosition = 'trailing';
5459
- return this;
5460
- };
5461
- Button.prototype.iconAtTop = function() {
5462
- this.$description.iconPosition = 'top';
3687
+ Alert.prototype.icon = function(icon) {
3688
+ this.$description.icon = icon;
5463
3689
  return this;
5464
3690
  };
5465
3691
 
5466
- Button.prototype.iconAtBottom = function() {
5467
- this.$description.iconPosition = 'bottom';
5468
- return this;
3692
+ /**
3693
+ * Shows or hides the icon
3694
+ * @param {boolean} [show=true] - Whether to show the icon
3695
+ * @returns {Alert}
3696
+ */
3697
+ Alert.prototype.showIcon = function(show = true) {
3698
+ this.$description.showIcon = show;
5469
3699
  };
5470
3700
 
5471
- Button.prototype.iconOnly = function() {
5472
- this.$description.iconOnly = true;
3701
+ /**
3702
+ * Sets whether the alert can be closed
3703
+ * @param {boolean} [closable=true] - Whether the alert is closable
3704
+ * @returns {Alert}
3705
+ */
3706
+ Alert.prototype.closable = function(closable = true) {
3707
+ this.$description.closable = !!closable;
3708
+ if(closable) {
3709
+ this.showIf(closable);
3710
+ }
5473
3711
  return this;
5474
3712
  };
5475
3713
 
5476
- Button.prototype.loading = function(loading = true) {
5477
- this.$description.loading = BaseComponent.obs(loading);
5478
- return this;
3714
+ /**
3715
+ * Sets whether the alert is dismissible (alias for closable)
3716
+ * @param {boolean} [dismissible=true] - Whether the alert is dismissible
3717
+ * @returns {Alert}
3718
+ */
3719
+ Alert.prototype.dismissible = function(dismissible = true) {
3720
+ return this.closable(dismissible);
5479
3721
  };
5480
3722
 
5481
- Button.prototype.disabled = function(disabled = true) {
5482
- this.$description.disabled = BaseComponent.obs(disabled);
3723
+ /**
3724
+ * Sets auto-dismiss delay for the alert
3725
+ * @param {number} delay - Delay in milliseconds before auto-dismissing
3726
+ * @returns {Alert}
3727
+ */
3728
+ Alert.prototype.autoDismiss = function(delay) {
3729
+ this.$description.autoDismiss = delay;
5483
3730
  return this;
5484
3731
  };
5485
3732
 
5486
- Button.prototype.render = function(renderFunction) {
5487
- this.$description.render = renderFunction;
5488
- return this;
3733
+ /**
3734
+ * Closes the alert
3735
+ */
3736
+ Alert.prototype.close = function() {
3737
+ this.$description.showIf?.set(false);
3738
+ this.emit('hide');
5489
3739
  };
5490
3740
 
5491
- Button.prototype.rounded = function() {
5492
- this.$description.borderRadiusType = 'rounded';
5493
- return this;
5494
- };
5495
- Button.prototype.pill = function() {
5496
- this.$description.borderRadiusType = 'pill';
5497
- return this;
5498
- };
5499
- Button.prototype.circle = function() {
5500
- this.$description.borderRadiusType = 'circle';
5501
- return this;
3741
+ /**
3742
+ * Shows the alert
3743
+ */
3744
+ Alert.prototype.show = function() {
3745
+ this.$description.showIf?.set(true);
3746
+ this.emit('show');
5502
3747
  };
5503
- Button.prototype.smooth = function() {
5504
- this.$description.borderRadiusType = 'smooth';
3748
+
3749
+ /**
3750
+ * Hides the alert
3751
+ */
3752
+ Alert.prototype.hide = Alert.prototype.close;
3753
+
3754
+ /**
3755
+ * Registers a handler for the close event
3756
+ * @param {(element: Alert) => void} handler - The event handler
3757
+ * @returns {Alert}
3758
+ */
3759
+ Alert.prototype.onClose = function(handler) {
3760
+ this.on('close', handler);
5505
3761
  return this;
5506
3762
  };
5507
- Button.prototype.block = function() {
5508
- this.$description.block = true;
3763
+
3764
+ /**
3765
+ * Registers a handler for the show event
3766
+ * @param {(element: Alert) => void} handler - The event handler
3767
+ * @returns {Alert}
3768
+ */
3769
+ Alert.prototype.onShow = function(handler) {
3770
+ this.on('show', handler);
5509
3771
  return this;
5510
3772
  };
5511
3773
 
@@ -5551,7 +3813,7 @@ var NativeComponents = (function (exports) {
5551
3813
 
5552
3814
  Avatar.preset = function(name, callback) {
5553
3815
  if (Avatar.prototype[name] || Avatar[name]) {
5554
- DebugManager$1.warn(`Warning: the ${name} method already exists in Avatar.`);
3816
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Avatar.`);
5555
3817
  return;
5556
3818
  }
5557
3819
  Avatar[name] = (label, props) => callback(new Avatar(label, props));
@@ -5973,7 +4235,7 @@ var NativeComponents = (function (exports) {
5973
4235
 
5974
4236
  Badge.preset = function(name, callback) {
5975
4237
  if (Badge.prototype[name] || Badge[name]) {
5976
- DebugManager$1.warn(`Warning: the ${name} method already exists in Badge.`);
4238
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Badge.`);
5977
4239
  return;
5978
4240
  }
5979
4241
  Badge[name] = (content, props) => callback(new Badge(content, props));
@@ -6091,7 +4353,7 @@ var NativeComponents = (function (exports) {
6091
4353
 
6092
4354
  Breadcrumb.preset = function(name, callback) {
6093
4355
  if (Breadcrumb.prototype[name] || Breadcrumb[name]) {
6094
- DebugManager$1.warn(`Warning: the ${name} method already exist in Breadcrumb.`);
4356
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Breadcrumb.`);
6095
4357
  return;
6096
4358
  }
6097
4359
  Breadcrumb[name] = (props) => callback(new Breadcrumb(props));
@@ -6145,6 +4407,169 @@ var NativeComponents = (function (exports) {
6145
4407
  return this;
6146
4408
  };
6147
4409
 
4410
+ function Button(label, props = {}) {
4411
+ if(!(this instanceof Button)) {
4412
+ return new Button(label, props);
4413
+ }
4414
+
4415
+ BaseComponent.call(this, props);
4416
+
4417
+ this.$description = {
4418
+ label: label,
4419
+ type: null,
4420
+ variant: null,
4421
+ size: null,
4422
+ icon: null,
4423
+ iconPosition: 'left',
4424
+ loading: null,
4425
+ disabled: null,
4426
+ template: null,
4427
+ block: null,
4428
+ borderRadiusType: null,
4429
+ outline: null,
4430
+ props
4431
+ };
4432
+
4433
+ this.$element = null;
4434
+ }
4435
+
4436
+ Button.defaultTemplate = null;
4437
+
4438
+ Button.use = function(template = {}) {
4439
+ Button.defaultTemplate = template;
4440
+ };
4441
+
4442
+ BaseComponent.extends(Button);
4443
+
4444
+ Button.preset = function(name, callback) {
4445
+ if (Button.prototype[name] || Button[name]) {
4446
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Button.`);
4447
+ return;
4448
+ }
4449
+ Button[name] = (label, props) => callback(new Button(label, props));
4450
+ };
4451
+
4452
+ Button.presets = function(presets) {
4453
+ for (const name in presets) {
4454
+ Button.preset(name, presets[name]);
4455
+ }
4456
+ };
4457
+
4458
+ Button.prototype.type = function(type) {
4459
+ this.$description.type = type;
4460
+ return this;
4461
+ };
4462
+
4463
+ Button.prototype.variant = function(variant) {
4464
+ this.$description.variant = variant;
4465
+ return this;
4466
+ };
4467
+ Button.prototype.primary = function() {
4468
+ return this.variant('primary');
4469
+ };
4470
+ Button.prototype.secondary = function() {
4471
+ return this.variant('secondary');
4472
+ };
4473
+ Button.prototype.danger = function() {
4474
+ return this.variant('danger');
4475
+ };
4476
+ Button.prototype.success = function() {
4477
+ return this.variant('success');
4478
+ };
4479
+ Button.prototype.warning = function() {
4480
+ return this.variant('warning');
4481
+ };
4482
+ Button.prototype.ghost = function() {
4483
+ return this.variant('ghost');
4484
+ };
4485
+ Button.prototype.link = function() {
4486
+ return this.variant('link');
4487
+ };
4488
+ Button.prototype.outline = function() {
4489
+ this.$description.outline = true;
4490
+ return this;
4491
+ };
4492
+
4493
+ Button.prototype.size = function(size) {
4494
+ this.$description.size = size;
4495
+ return this;
4496
+ };
4497
+ Button.prototype.small = function() {
4498
+ return this.size('small');
4499
+ };
4500
+ Button.prototype.large = function() {
4501
+ return this.size('large');
4502
+ };
4503
+ Button.prototype.medium = function() {
4504
+ return this.size('medium');
4505
+ };
4506
+
4507
+ Button.prototype.icon = function(icon, iconPosition = 'leading') {
4508
+ this.$description.icon = icon;
4509
+ this.$description.iconPosition = iconPosition;
4510
+ return this;
4511
+ };
4512
+
4513
+ Button.prototype.iconAtLeading = function() {
4514
+ this.$description.iconPosition = 'leading';
4515
+ return this;
4516
+ };
4517
+
4518
+ Button.prototype.iconAtTrailing = function() {
4519
+ this.$description.iconPosition = 'trailing';
4520
+ return this;
4521
+ };
4522
+ Button.prototype.iconAtTop = function() {
4523
+ this.$description.iconPosition = 'top';
4524
+ return this;
4525
+ };
4526
+
4527
+ Button.prototype.iconAtBottom = function() {
4528
+ this.$description.iconPosition = 'bottom';
4529
+ return this;
4530
+ };
4531
+
4532
+ Button.prototype.iconOnly = function() {
4533
+ this.$description.iconOnly = true;
4534
+ return this;
4535
+ };
4536
+
4537
+ Button.prototype.loading = function(loading = true) {
4538
+ this.$description.loading = BaseComponent.obs(loading);
4539
+ return this;
4540
+ };
4541
+
4542
+ Button.prototype.disabled = function(disabled = true) {
4543
+ this.$description.disabled = BaseComponent.obs(disabled);
4544
+ return this;
4545
+ };
4546
+
4547
+ Button.prototype.render = function(renderFunction) {
4548
+ this.$description.render = renderFunction;
4549
+ return this;
4550
+ };
4551
+
4552
+ Button.prototype.rounded = function() {
4553
+ this.$description.borderRadiusType = 'rounded';
4554
+ return this;
4555
+ };
4556
+ Button.prototype.pill = function() {
4557
+ this.$description.borderRadiusType = 'pill';
4558
+ return this;
4559
+ };
4560
+ Button.prototype.circle = function() {
4561
+ this.$description.borderRadiusType = 'circle';
4562
+ return this;
4563
+ };
4564
+ Button.prototype.smooth = function() {
4565
+ this.$description.borderRadiusType = 'smooth';
4566
+ return this;
4567
+ };
4568
+ Button.prototype.block = function() {
4569
+ this.$description.block = true;
4570
+ return this;
4571
+ };
4572
+
6148
4573
  function Card(config = {}) {
6149
4574
  if(!(this instanceof Card)) {
6150
4575
  return new Card(config);
@@ -6900,7 +5325,7 @@ var NativeComponents = (function (exports) {
6900
5325
 
6901
5326
  Divider.preset = function(name, callback) {
6902
5327
  if (Divider.prototype[name] || Divider[name]) {
6903
- DebugManager$1.warn(`Warning: the ${name} method already exists in Divider.`);
5328
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Divider.`);
6904
5329
  return;
6905
5330
  }
6906
5331
  Divider[name] = (label, props) => callback(new Divider(label, props));
@@ -7319,7 +5744,7 @@ var NativeComponents = (function (exports) {
7319
5744
 
7320
5745
  Dropdown.preset = function(name, callback) {
7321
5746
  if (Dropdown.prototype[name] || Dropdown[name]) {
7322
- DebugManager$1.warn(`Warning: the ${name} method already exist in Dropdown.`);
5747
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Dropdown.`);
7323
5748
  return;
7324
5749
  }
7325
5750
  Dropdown[name] = (props) => callback(new Dropdown(props));
@@ -8540,10 +6965,10 @@ var NativeComponents = (function (exports) {
8540
6965
  errorsPosition: 'bottom',
8541
6966
  errorsMapper: null,
8542
6967
  renderErrors: null,
8543
- submitting: Observable(false),
8544
- errors: Observable(null),
8545
- isDirty: Observable(false),
8546
- isValid: Observable(false),
6968
+ submitting: $$1(false),
6969
+ errors: $$1(null),
6970
+ isDirty: $$1(false),
6971
+ isValid: $$1(false),
8547
6972
  props
8548
6973
  };
8549
6974
  }
@@ -8585,7 +7010,7 @@ var NativeComponents = (function (exports) {
8585
7010
  dirties.push(field.$description.isDirty);
8586
7011
  }
8587
7012
 
8588
- Observable.computed(() => {
7013
+ $$1.computed(() => {
8589
7014
  const isDirty = dirties.some((item) => item.val());
8590
7015
  this.$description.isDirty.set(isDirty);
8591
7016
  }, dirties);
@@ -11374,7 +9799,7 @@ var NativeComponents = (function (exports) {
11374
9799
 
11375
9800
  Modal.preset = function(name, callback) {
11376
9801
  if (Modal.prototype[name] || Modal[name]) {
11377
- DebugManager$1.warn(`Warning: the ${name} method already exist in Modal.`);
9802
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Modal.`);
11378
9803
  return;
11379
9804
  }
11380
9805
  Modal[name] = (content, props) => callback(new Modal(content, props));
@@ -11625,7 +10050,7 @@ var NativeComponents = (function (exports) {
11625
10050
 
11626
10051
  Pagination.preset = function(name, callback) {
11627
10052
  if (Pagination.prototype[name] || Pagination[name]) {
11628
- DebugManager$1.warn(`Warning: the ${name} method already exist in Pagination.`);
10053
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Pagination.`);
11629
10054
  return;
11630
10055
  }
11631
10056
  Pagination[name] = (props) => callback(new Pagination(props));
@@ -11920,7 +10345,7 @@ var NativeComponents = (function (exports) {
11920
10345
 
11921
10346
  Popover.preset = function(name, callback) {
11922
10347
  if (Popover.prototype[name] || Popover[name]) {
11923
- DebugManager$1.warn(`Warning: the ${name} method already exist in Popover.`);
10348
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Popover.`);
11924
10349
  return;
11925
10350
  }
11926
10351
  Popover[name] = (content, props) => callback(new Popover(content, props));
@@ -12222,7 +10647,7 @@ var NativeComponents = (function (exports) {
12222
10647
 
12223
10648
  Progress.preset = function(name, callback) {
12224
10649
  if (Progress.prototype[name] || Progress[name]) {
12225
- DebugManager$1.warn(`Warning: the ${name} method already exists in Progress.`);
10650
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Progress.`);
12226
10651
  return;
12227
10652
  }
12228
10653
  Progress[name] = (props) => callback(new Progress(props));
@@ -12524,7 +10949,7 @@ var NativeComponents = (function (exports) {
12524
10949
 
12525
10950
  VStack.preset = function(name, callback) {
12526
10951
  if (VStack.prototype[name] || VStack[name]) {
12527
- DebugManager$1.warn(`Warning: the ${name} method already exists in VStack.`);
10952
+ DebugManager$2.warn(`Warning: the ${name} method already exists in VStack.`);
12528
10953
  return;
12529
10954
  }
12530
10955
  VStack[name] = (content, props) => callback(new VStack(content, props));
@@ -12699,7 +11124,7 @@ var NativeComponents = (function (exports) {
12699
11124
 
12700
11125
  FixedStack.preset = function(name, callback) {
12701
11126
  if(FixedStack.prototype[name] || FixedStack[name]) {
12702
- DebugManager$1.warn(`Warning: the ${name} method already exists in FixedStack.`);
11127
+ DebugManager$2.warn(`Warning: the ${name} method already exists in FixedStack.`);
12703
11128
  return;
12704
11129
  }
12705
11130
  FixedStack[name] = (content, props) => callback(new FixedStack(content, props));
@@ -12729,7 +11154,7 @@ var NativeComponents = (function (exports) {
12729
11154
 
12730
11155
  HStack.preset = function(name, callback) {
12731
11156
  if (HStack.prototype[name] || HStack[name]) {
12732
- DebugManager$1.warn(`Warning: the ${name} method already exists in HStack.`);
11157
+ DebugManager$2.warn(`Warning: the ${name} method already exists in HStack.`);
12733
11158
  return;
12734
11159
  }
12735
11160
  HStack[name] = (content, props) => callback(new HStack(content, props));
@@ -12759,7 +11184,7 @@ var NativeComponents = (function (exports) {
12759
11184
 
12760
11185
  AbsoluteStack.preset = function(name, callback) {
12761
11186
  if(AbsoluteStack.prototype[name] || AbsoluteStack[name]) {
12762
- DebugManager$1.warn(`Warning: the ${name} method already exists in AbsoluteStack.`);
11187
+ DebugManager$2.warn(`Warning: the ${name} method already exists in AbsoluteStack.`);
12763
11188
  return;
12764
11189
  }
12765
11190
  AbsoluteStack[name] = (content, props) => callback(new AbsoluteStack(content, props));
@@ -12789,7 +11214,7 @@ var NativeComponents = (function (exports) {
12789
11214
 
12790
11215
  RelativeStack.preset = function(name, callback) {
12791
11216
  if(RelativeStack.prototype[name] || RelativeStack[name]) {
12792
- DebugManager$1.warn(`Warning: the ${name} method already exists in RelativeStack.`);
11217
+ DebugManager$2.warn(`Warning: the ${name} method already exists in RelativeStack.`);
12793
11218
  return;
12794
11219
  }
12795
11220
  RelativeStack[name] = (content, props) => callback(new RelativeStack(content, props));
@@ -12834,7 +11259,7 @@ var NativeComponents = (function (exports) {
12834
11259
 
12835
11260
  Skeleton.preset = function(name, callback) {
12836
11261
  if (Skeleton.prototype[name] || Skeleton[name]) {
12837
- DebugManager$1.warn(`Warning: the ${name} method already exists in Skeleton.`);
11262
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Skeleton.`);
12838
11263
  return;
12839
11264
  }
12840
11265
  Skeleton[name] = (props) => callback(new Skeleton(props));
@@ -13198,7 +11623,7 @@ var NativeComponents = (function (exports) {
13198
11623
 
13199
11624
  Spinner.preset = function(name, callback) {
13200
11625
  if (Spinner.prototype[name] || Spinner[name]) {
13201
- DebugManager$1.warn(`Warning: the ${name} method already exists in Spinner.`);
11626
+ DebugManager$2.warn(`Warning: the ${name} method already exists in Spinner.`);
13202
11627
  return;
13203
11628
  }
13204
11629
  Spinner[name] = (props) => callback(new Spinner(props));
@@ -13768,7 +12193,7 @@ var NativeComponents = (function (exports) {
13768
12193
 
13769
12194
  Stepper.preset = function(name, callback) {
13770
12195
  if (Stepper.prototype[name] || Stepper[name]) {
13771
- DebugManager$1.warn(`Warning: the ${name} method already exist in Stepper.`);
12196
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Stepper.`);
13772
12197
  return;
13773
12198
  }
13774
12199
  Stepper[name] = (props) => callback(new Stepper(props));
@@ -14721,7 +13146,7 @@ var NativeComponents = (function (exports) {
14721
13146
 
14722
13147
  DataTable.prototype.selectedRows = function($obs) {
14723
13148
  if(!$obs.__$isObservableArray) {
14724
- DebugManager$1.warn('Database', 'selectedRow should take an Observable array');
13149
+ DebugManager$2.warn('Database', 'selectedRow should take an Observable array');
14725
13150
  }
14726
13151
  this.$description.$selectedRows = $obs;
14727
13152
  return this;
@@ -15268,7 +13693,7 @@ var NativeComponents = (function (exports) {
15268
13693
 
15269
13694
  Tooltip.preset = function(name, callback) {
15270
13695
  if (Tooltip.prototype[name] || Tooltip[name]) {
15271
- DebugManager$1.warn(`Warning: the ${name} method already exist in Tooltip.`);
13696
+ DebugManager$2.warn(`Warning: the ${name} method already exist in Tooltip.`);
15272
13697
  return;
15273
13698
  }
15274
13699
  Tooltip[name] = (content, props) => callback(new Tooltip(content, props));