native-document 1.0.149 → 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 (102) 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 +1120 -2738
  5. package/dist/native-document.dev.js +5148 -5191
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/elements.js +1 -4
  9. package/index.js +0 -4
  10. package/package.json +1 -1
  11. package/rollup.config.js +1 -1
  12. package/src/components/$traits/has-items/HasItems.js +1 -1
  13. package/src/components/BaseComponent.js +1 -1
  14. package/src/components/accordion/AccordionItem.js +1 -1
  15. package/src/components/avatar/Avatar.js +0 -2
  16. package/src/components/breadcrumb/BreadCrumb.js +1 -1
  17. package/src/components/context-menu/ContextMenu.js +1 -1
  18. package/src/components/dropdown/Dropdown.js +1 -1
  19. package/src/components/dropdown/DropdownGroup.js +1 -1
  20. package/src/components/form/FormControl.js +2 -1
  21. package/src/components/form/field/DefaultRender.js +1 -1
  22. package/src/components/form/field/Field.js +2 -1
  23. package/src/components/form/field/FieldCollection.js +2 -1
  24. package/src/components/form/field/types/CheckboxField.js +1 -1
  25. package/src/components/form/field/types/FileField.js +1 -1
  26. package/src/components/form/field/types/RadioField.js +1 -1
  27. package/src/components/form/field/types/file-field-mode/FileItemPreview.js +1 -1
  28. package/src/components/form/validation/Validation.js +1 -1
  29. package/src/components/list/ListItem.js +1 -1
  30. package/src/components/menu/Menu.js +1 -1
  31. package/src/components/menu/MenuGroup.js +1 -1
  32. package/src/components/menu/MenuItem.js +1 -1
  33. package/src/components/modal/Modal.js +1 -1
  34. package/src/components/pagination/Pagination.js +1 -1
  35. package/src/components/popover/Popover.js +1 -1
  36. package/src/components/progress/Progress.js +0 -1
  37. package/src/components/splitter/Splitter.js +1 -1
  38. package/src/components/splitter/SplitterGutter.js +1 -1
  39. package/src/components/splitter/SplitterPanel.js +1 -1
  40. package/src/components/stepper/Stepper.js +1 -1
  41. package/src/components/stepper/StepperStep.js +1 -1
  42. package/src/components/switch/Switch.js +1 -1
  43. package/src/components/table/DataTable.js +1 -1
  44. package/src/components/table/index.js +0 -2
  45. package/src/components/tabs/Tabs.js +1 -1
  46. package/src/components/toast/Toast.js +1 -1
  47. package/src/components/tooltip/Tooltip.js +1 -1
  48. package/src/core/elements/anchor/one-child-anchor-overwriting.js +1 -1
  49. package/src/core/elements/fragment.js +8 -0
  50. package/src/core/elements/index.js +1 -9
  51. package/src/core/utils/prototypes.js +0 -46
  52. package/src/i18n/service/I18nService.js +1 -1
  53. package/src/i18n/service/functions.js +1 -1
  54. package/src/ui/components/accordion/AccordionRender.js +1 -0
  55. package/src/ui/components/alert/AlertRender.js +2 -1
  56. package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +1 -0
  57. package/src/ui/components/badge/BadgeRender.js +1 -0
  58. package/src/ui/components/breadcrumb/BreadcrumbRender.js +1 -0
  59. package/src/ui/components/contextmenu/ContextmenuRender.js +0 -2
  60. package/src/ui/components/dropdown/DropdownRender.js +1 -1
  61. package/src/ui/components/form/FieldCollectionRender.js +1 -1
  62. package/src/ui/components/form/FormControlRender.js +2 -1
  63. package/src/ui/components/form/fields/AutocompleteFieldRender.js +3 -3
  64. package/src/ui/components/form/fields/CheckboxFieldRender.js +1 -1
  65. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +1 -1
  66. package/src/ui/components/form/fields/DateFieldRender.js +2 -1
  67. package/src/ui/components/form/fields/FieldRender.js +2 -1
  68. package/src/ui/components/form/fields/HiddenFieldRender.js +0 -1
  69. package/src/ui/components/form/fields/PasswordFieldRender.js +1 -1
  70. package/src/ui/components/form/fields/RadioFieldRender.js +1 -1
  71. package/src/ui/components/form/fields/RangeFieldRender.js +1 -0
  72. package/src/ui/components/form/fields/SelectFieldRender.js +2 -2
  73. package/src/ui/components/form/fields/SliderFieldRender.js +2 -2
  74. package/src/ui/components/form/fields/TimeFieldRender.js +1 -0
  75. package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +2 -2
  76. package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +2 -2
  77. package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +1 -2
  78. package/src/ui/components/menu/MenuGroupRender.js +0 -1
  79. package/src/ui/components/menu/MenuItemRender.js +1 -1
  80. package/src/ui/components/menu/MenuLinkRender.js +1 -1
  81. package/src/ui/components/menu/MenuRender.js +1 -0
  82. package/src/ui/components/modal/ModalRender.js +1 -2
  83. package/src/ui/components/pagination/PaginationRender.js +2 -2
  84. package/src/ui/components/popover/PopoverRender.js +1 -2
  85. package/src/ui/components/skeleton/SkeletonRender.js +1 -0
  86. package/src/ui/components/spinner/SpinnerRender.js +2 -1
  87. package/src/ui/components/splitter/SplitterRender.js +1 -0
  88. package/src/ui/components/stacks/PositionStackRender.js +1 -0
  89. package/src/ui/components/stacks/StackRender.js +0 -1
  90. package/src/ui/components/stacks/v-stack/VStackRender.js +1 -0
  91. package/src/ui/components/stepper/StepperRender.js +2 -1
  92. package/src/ui/components/stepper/StepperStepRender.js +1 -1
  93. package/src/ui/components/switch/SwitchRender.js +1 -0
  94. package/src/ui/components/table/data-table/DataTableRender.js +2 -1
  95. package/src/ui/components/table/data-table/bulk-actions.js +1 -2
  96. package/src/ui/components/table/data-table/pagination.js +1 -1
  97. package/src/ui/components/table/data-table/tables.js +1 -1
  98. package/src/ui/components/table/simple-table/SimpleTableRender.js +3 -2
  99. package/src/ui/components/tabs/TabsRender.js +1 -1
  100. package/src/ui/components/toast/ToastRender.js +2 -1
  101. package/src/ui/theme.js +0 -6
  102. package/src/ui/theme.scss +1 -0
@@ -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,2704 +1693,1099 @@ 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
-
2196
- NodeCloner.prototype.cloneNode = function(data) {
2197
- return this.$element.cloneNode(false);
2198
- };
2199
1879
 
2200
- NodeCloner.prototype.attach = function(methodName, callback) {
2201
- this.$ndMethods = this.$ndMethods || {};
2202
- this.$ndMethods[methodName] = callback;
2203
- return this;
2204
- };
1880
+ anchorFragment.removeWithAnchors = function() {
1881
+ anchorFragment.removeChildren();
1882
+ anchorStart.remove();
1883
+ anchorEnd.remove();
1884
+ };
1885
+ anchorFragment.delete = anchorFragment.removeWithAnchors;
2205
1886
 
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
- };
2215
-
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
- };
2231
-
2232
- DocumentFragment.prototype.__IS_FRAGMENT = true;
2233
-
2234
- Function.prototype.args = function(...args) {
2235
- return withValidation(this);
2236
- };
2237
-
2238
- Function.prototype.cached = function(...args) {
2239
- let $cache;
2240
- let getCache = () => $cache;
2241
- return () => {
2242
- if(!$cache) {
2243
- $cache = this.apply(this, args);
2244
- if($cache.cloneNode) {
2245
- getCache = () => $cache.cloneNode(true);
2246
- } else if($cache.$element) {
2247
- getCache = () => new NDElement($cache.$element.cloneNode(true));
2248
- }
2249
- }
2250
- return getCache();
1887
+ anchorFragment.replaceContent = function(child) {
1888
+ const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
1889
+ anchorFragment.replaceContentRaw(childElement);
2251
1890
  };
2252
- };
2253
1891
 
2254
- Function.prototype.errorBoundary = function(callback) {
2255
- const handler = (...args) => {
2256
- try {
2257
- return this.apply(this, args);
2258
- } catch(e) {
2259
- return callback(e, {caller: handler, args: args });
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;
2260
1900
  }
1901
+ anchorFragment.removeChildren();
1902
+ parent.insertBefore(child, anchorEnd);
2261
1903
  };
2262
- return handler;
2263
- };
2264
-
2265
- String.prototype.use = function(args) {
2266
- const value = this;
2267
-
2268
- return Observable.computed(() => {
2269
- return value.replace(/\$\{(.*?)}/g, (match, key) => {
2270
- const data = args[key];
2271
- if(Validator.isObservable(data)) {
2272
- return data.val();
2273
- }
2274
- return data;
2275
- });
2276
- }, Object.values(args));
2277
- };
2278
1904
 
2279
- String.prototype.resolveObservableTemplate = function() {
2280
- if(!Validator.containsObservableReference(this)) {
2281
- return this.valueOf();
2282
- }
2283
- return this.split(/(\{\{#ObItem::\([0-9]+\)\}\})/g).filter(Boolean).map((value) => {
2284
- if(!Validator.containsObservableReference(value)) {
2285
- return value;
2286
- }
2287
- const [_, id] = value.match(/\{\{#ObItem::\(([0-9]+)\)\}\}/);
2288
- return Observable.getById(id);
2289
- });
2290
- };
1905
+ anchorFragment.setContent = anchorFragment.replaceContent;
1906
+ anchorFragment.setContentRaw = anchorFragment.replaceContentRaw;
2291
1907
 
2292
- const cssPropertyAccumulator = function(initialValue = {}) {
2293
- let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
1908
+ anchorFragment.insertBefore = anchorFragment.appendChild;
1909
+ anchorFragment.insertBeforeRaw = anchorFragment.appendChildRaw;
2294
1910
 
2295
- return {
2296
- add(key, value) {
2297
- if(Array.isArray(data)) {
2298
- data.push(key+': '+value);
2299
- return;
2300
- }
2301
- if(Validator.isObject(key)) {
2302
- value = key;
2303
- for(const property in value) {
2304
- data[property] = value[property];
2305
- }
2306
- return;
2307
- }
2308
- data[key] = value;
2309
- },
2310
- value() {
2311
- if(Array.isArray(data)) {
2312
- return data.join(';').concat(';');
2313
- }
2314
- return { ...data };
2315
- },
1911
+ anchorFragment.endElement = function() {
1912
+ return anchorEnd;
2316
1913
  };
2317
- };
2318
-
2319
- const classPropertyAccumulator = function(initialValue = []) {
2320
- let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
2321
1914
 
2322
- return {
2323
- add(key, value = true) {
2324
- if(Validator.isJson(key)) {
2325
- for(const property in key) {
2326
- if(key[property]) {
2327
- data[property] = key[property];
2328
- }
2329
- }
2330
- return;
2331
- }
2332
- if(value != null || key.__$Observable) {
2333
- if(Array.isArray(data)) {
2334
- data = data.reduce((acc, item) => {
2335
- acc[item] = true;
2336
- return acc;
2337
- }, {});
2338
- }
2339
- if(key.__$Observable) {
2340
- const uniqueId = `obs-${Math.random().toString(36).substr(2, 9)}`;
2341
- data[uniqueId] = key;
2342
- }
2343
- else {
2344
- data[key] = value;
2345
- }
2346
- return;
2347
- }
2348
- if(Array.isArray(data)) {
2349
- data.push(key);
2350
- return;
2351
- }
2352
- data[key] = value;
2353
- },
2354
- value() {
2355
- if(Array.isArray(data)) {
2356
- return data.join(' ');
2357
- }
2358
- return { ...data };
2359
- },
1915
+ anchorFragment.startElement = function() {
1916
+ return anchorStart;
2360
1917
  };
2361
- };
2362
-
2363
- const mutationMethods = ['push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice'];
2364
- const noMutationMethods = ['map', 'forEach', 'filter', 'reduce', 'some', 'every', 'find', 'findIndex', 'concat', 'includes', 'indexOf'];
2365
-
2366
- /**
2367
- *
2368
- * @param target
2369
- * @param {{propagation: boolean, deep: boolean, reset: boolean}|null} configs
2370
- * @constructor
2371
- */
2372
- const ObservableArray = function (target, configs = null) {
2373
- if(!Array.isArray(target)) {
2374
- throw new NativeDocumentError('Observable.array : target must be an array');
2375
- }
2376
-
2377
- ObservableItem.call(this, target, configs);
2378
- };
2379
-
2380
- ObservableArray.prototype = Object.create(ObservableItem.prototype);
2381
- ObservableArray.prototype.constructor = ObservableArray;
2382
- ObservableArray.prototype.__$isObservableArray = true;
2383
-
2384
1918
 
2385
- Object.defineProperty(ObservableArray.prototype, 'length', {
2386
- get() {
2387
- return this.$currentValue.length;
2388
- }
2389
- });
1919
+ anchorFragment.restore = function() {
1920
+ anchorFragment.appendChild(anchorFragment);
1921
+ };
2390
1922
 
1923
+ anchorFragment.clear = anchorFragment.remove;
1924
+ anchorFragment.detach = anchorFragment.remove;
2391
1925
 
2392
- ObservableArray.prototype.$mutate = function(action, args, mutateFn) {
2393
- if(this.$mutationInterceptor) {
2394
- const value = this.$mutationInterceptor(args, { action });
2395
- if(args !== undefined) {
2396
- args = value;
1926
+ anchorFragment.getByIndex = function(index) {
1927
+ let currentNode = anchorStart;
1928
+ for(let i = 0; i <= index; i++) {
1929
+ if(!currentNode.nextSibling) {
1930
+ return null;
1931
+ }
1932
+ currentNode = currentNode.nextSibling;
2397
1933
  }
2398
- }
2399
- mutateFn(args);
2400
- };
2401
-
2402
- mutationMethods.forEach((method) => {
2403
- ObservableArray.prototype[method] = function(...values) {
2404
- return this.$mutate(method, values, (argsToUse) => {
2405
- const result = this.$currentValue[method].apply(this.$currentValue, argsToUse);
2406
- this.trigger({ action: method, args: argsToUse, result });
2407
- return result;
2408
- })
1934
+ return currentNode !== anchorStart ? currentNode : null;
2409
1935
  };
2410
- });
2411
1936
 
2412
- noMutationMethods.forEach((method) => {
2413
- ObservableArray.prototype[method] = function(...values) {
2414
- return this.$currentValue[method].apply(this.$currentValue, values);
2415
- };
2416
- });
1937
+ return anchorFragment;
1938
+ }
1939
+ DocumentFragment.prototype.setAttribute = () => {};
2417
1940
 
1941
+ function NDElement(element) {
1942
+ this.$element = element;
1943
+ this.$attachements = null;
1944
+ }
2418
1945
 
2419
- const $clearEvent = { action: 'clear' };
1946
+ NDElement.prototype.__$isNDElement = true;
2420
1947
 
2421
- /**
2422
- * Removes all items from the array and triggers an update.
2423
- *
2424
- * @returns {boolean} True if array was cleared, false if it was already empty
2425
- * @example
2426
- * const items = Observable.array([1, 2, 3]);
2427
- * items.clear(); // []
2428
- */
2429
- ObservableArray.prototype.clear = function() {
2430
- if(this.$currentValue.length === 0) {
2431
- return;
1948
+ NDElement.prototype.ghostDom = function(element) {
1949
+ if(!this.$attachements) {
1950
+ this.$attachements = document.createDocumentFragment();
2432
1951
  }
2433
- this.$mutate('clear', [], () => {
2434
- this.$currentValue.length = 0;
2435
- this.trigger($clearEvent);
2436
- });
2437
- return true;
1952
+ this.$attachements.appendChild(ElementCreator.getChild(element));
1953
+ return this;
2438
1954
  };
2439
1955
 
2440
- /**
2441
- * Returns the element at the specified index in the array.
2442
- *
2443
- * @param {number} index - Zero-based index of the element to retrieve
2444
- * @returns {*} The element at the specified index
2445
- * @example
2446
- * const items = Observable.array(['a', 'b', 'c']);
2447
- * items.at(1); // 'b'
2448
- */
2449
- ObservableArray.prototype.at = function(index) {
2450
- return this.$currentValue[index];
1956
+ NDElement.prototype.valueOf = function() {
1957
+ return this.$element;
2451
1958
  };
2452
1959
 
2453
-
2454
- /**
2455
- * Merges multiple values into the array and triggers an update.
2456
- * Similar to push but with a different operation name.
2457
- *
2458
- * @param {Array} values - Array of values to merge
2459
- * @example
2460
- * const items = Observable.array([1, 2]);
2461
- * items.merge([3, 4]); // [1, 2, 3, 4]
2462
- */
2463
- ObservableArray.prototype.merge = function(values) {
2464
- this.$mutate('merge', values, (valuesToMerge) => {
2465
- this.$currentValue.push.apply(this.$currentValue, valuesToMerge);
2466
- this.trigger({ action: 'merge', args: valuesToMerge });
2467
- });
1960
+ NDElement.prototype.ref = function(target, name) {
1961
+ target[name] = this.$element;
1962
+ return this;
2468
1963
  };
2469
1964
 
2470
- /**
2471
- * Counts the number of elements that satisfy the provided condition.
2472
- *
2473
- * @param {(value: *, index: number) => Boolean} condition - Function that tests each element (item, index) => boolean
2474
- * @returns {number} The count of elements that satisfy the condition
2475
- * @example
2476
- * const numbers = Observable.array([1, 2, 3, 4, 5]);
2477
- * numbers.count(n => n > 3); // 2
2478
- */
2479
- ObservableArray.prototype.count = function(condition) {
2480
- let count = 0;
2481
- this.$currentValue.forEach((item, index) => {
2482
- if(condition(item, index)) {
2483
- count++;
2484
- }
2485
- });
2486
- return count;
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;
2487
1970
  };
2488
1971
 
2489
- /**
2490
- * Swaps two elements at the specified indices and triggers an update.
2491
- *
2492
- * @param {number} indexA - Index of the first element
2493
- * @param {number} indexB - Index of the second element
2494
- * @returns {boolean} True if swap was successful, false if indices are out of bounds
2495
- * @example
2496
- * const items = Observable.array(['a', 'b', 'c']);
2497
- * items.swap(0, 2); // ['c', 'b', 'a']
2498
- */
2499
- ObservableArray.prototype.swap = function(indexA, indexB) {
2500
- this.$mutate('swap', [indexA, indexB], ([indexA, indexB]) => {
2501
- const value = this.$currentValue;
2502
- const length = value.length;
2503
- if(indexB < indexA) {
2504
- const temp = indexA;
2505
- indexA = indexB;
2506
- indexB = temp;
2507
- }
2508
- if(length < indexA || length < indexB) {
2509
- return false;
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();
2510
1978
  }
2511
- const elementA = value[indexA];
2512
- const elementB = value[indexB];
2513
-
2514
- value[indexA] = elementB;
2515
- value[indexB] = elementA;
2516
- this.trigger({ action: 'swap', args: [indexA, indexB], result: [elementA, elementB] });
2517
- });
2518
- return true;
1979
+ elementChildren = null;
1980
+ }
1981
+ element = null;
1982
+ return this;
2519
1983
  };
2520
1984
 
2521
- ObservableArray.prototype.swapItems = function(itemA, itemB) {
2522
- const indexA = this.$currentValue.indexOf(itemA);
2523
- const indexB = this.$currentValue.indexOf(itemB);
1985
+ NDElement.prototype.remove = function() {
1986
+ let element = this.$element;
1987
+ element.nd.unmountChildren();
1988
+ element.$ndProx = null;
2524
1989
 
2525
- return this.swap(indexA, indexB);
2526
- };
1990
+ $lifeCycleObservers.delete(element);
2527
1991
 
2528
- ObservableArray.prototype.insertAfter = function(data, target) {
2529
- const targetIndex = this.$currentValue.indexOf(target);
2530
- return this.splice(targetIndex + 1, 0, data);
1992
+ element = null;
1993
+ return this;
2531
1994
  };
2532
1995
 
2533
- /**
2534
- * Removes the element at the specified index and triggers an update.
2535
- *
2536
- * @param {number} index - Index of the element to remove
2537
- * @returns {Array} Array containing the removed element, or empty array if index is invalid
2538
- * @example
2539
- * const items = Observable.array(['a', 'b', 'c']);
2540
- * items.remove(1); // ['b'] - Array is now ['a', 'c']
2541
- */
2542
- ObservableArray.prototype.remove = function(index) {
2543
- let deleted = [];
2544
- this.$mutate('remove', [index], ([idx]) => {
2545
- deleted = this.$currentValue.splice(idx, 1);
2546
- if(deleted.length === 0) {
2547
- return;
2548
- }
2549
- this.trigger({action: 'remove', args: [idx], result: deleted[0]});
2550
- });
2551
- return deleted;
2552
- };
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);
2553
2003
 
2554
- /**
2555
- * Removes the first occurrence of the specified item from the array.
2556
- *
2557
- * @param {*} item - The item to remove
2558
- * @returns {Array} Array containing the removed element, or empty array if item not found
2559
- * @example
2560
- * const items = Observable.array(['a', 'b', 'c']);
2561
- * items.removeItem('b'); // ['b'] - Array is now ['a', 'c']
2562
- */
2563
- ObservableArray.prototype.removeItem = function(item) {
2564
- const indexOfItem = this.$currentValue.indexOf(item);
2565
- if(indexOfItem === -1) {
2566
- return [];
2004
+ if(states.mounted) {
2005
+ this.$element.setAttribute('data--nd-mounted', '1');
2006
+ observer.mounted(states.mounted);
2007
+ }
2008
+ if(states.unmounted) {
2009
+ this.$element.setAttribute('data--nd-unmounted', '1');
2010
+ observer.unmounted(states.unmounted);
2567
2011
  }
2568
- return this.remove(indexOfItem);
2012
+ return this;
2569
2013
  };
2570
2014
 
2571
- /**
2572
- * Checks if the array is empty.
2573
- *
2574
- * @returns {boolean} True if array has no elements
2575
- * @example
2576
- * const items = Observable.array([]);
2577
- * items.isEmpty(); // true
2578
- */
2579
- ObservableArray.prototype.empty = function() {
2580
- return this.$currentValue.length === 0;
2015
+ NDElement.prototype.mounted = function(callback) {
2016
+ return this.lifecycle({ mounted: callback });
2581
2017
  };
2582
2018
 
2583
- /**
2584
- * Triggers a populate operation with the current array, iteration count, and callback.
2585
- * Used internally for rendering optimizations.
2586
- *
2587
- * @param {number} iteration - Iteration count for rendering
2588
- * @param {Function} callback - Callback function for rendering items
2589
- */
2590
- ObservableArray.prototype.populateAndRender = function(iteration, callback) {
2591
- this.trigger({ action: 'populate', args: [this.$currentValue, iteration, callback] });
2019
+ NDElement.prototype.unmounted = function(callback) {
2020
+ return this.lifecycle({ unmounted: callback });
2592
2021
  };
2593
2022
 
2023
+ NDElement.prototype.beforeUnmount = function(id, callback) {
2024
+ const el = this.$element;
2594
2025
 
2595
- /**
2596
- * Creates a filtered view of the array based on predicates.
2597
- * The filtered array updates automatically when source data or predicates change.
2598
- *
2599
- * @param {Object} predicates - Object mapping property names to filter conditions or functions
2600
- * @returns {ObservableArray} A new observable array containing filtered items
2601
- * @example
2602
- * const users = Observable.array([
2603
- * { name: 'John', age: 25 },
2604
- * { name: 'Jane', age: 30 }
2605
- * ]);
2606
- *
2607
- * const adults = users.where({ age: (val) => val >= 18 });
2608
- */
2609
- ObservableArray.prototype.where = function(predicates) {
2610
- if(typeof predicates === 'function') {
2611
- predicates = { _: predicates };
2612
- }
2613
- const sourceArray = this;
2614
- const observableDependencies = [sourceArray];
2615
- const filterCallbacks = {};
2616
-
2617
- for (const [key, rawPredicate] of Object.entries(predicates)) {
2618
- const predicate = Validator.isObservable(rawPredicate) ? match(rawPredicate, false) : rawPredicate;
2619
- if (predicate && typeof predicate === 'object' && 'callback' in predicate) {
2620
- filterCallbacks[key] = predicate.callback;
2621
-
2622
- if (predicate.dependencies) {
2623
- const deps = Array.isArray(predicate.dependencies)
2624
- ? predicate.dependencies
2625
- : [predicate.dependencies];
2626
- observableDependencies.push.apply(observableDependencies, deps);
2627
- }
2628
- } else if(typeof predicate === 'function') {
2629
- filterCallbacks[key] = predicate;
2630
- } else {
2631
- filterCallbacks[key] = (value) => value === predicate;
2632
- }
2633
- }
2026
+ if(!DocumentObserver.beforeUnmount.has(el)) {
2027
+ DocumentObserver.beforeUnmount.set(el, new Map());
2028
+ const originalRemove = el.remove.bind(el);
2634
2029
 
2635
- const viewArray = Observable.array();
2030
+ let $isUnmounting = false;
2636
2031
 
2637
- const filters = Object.entries(filterCallbacks);
2638
- const updateView = () => {
2639
- const filtered = sourceArray.val().filter(item => {
2640
- for (const [key, callback] of filters) {
2641
- if(key === '_') {
2642
- if (!callback(item)) return false;
2643
- } else {
2644
- if (!callback(item[key])) return false;
2645
- }
2032
+ el.remove = async () => {
2033
+ if($isUnmounting) {
2034
+ return;
2646
2035
  }
2647
- return true;
2648
- });
2649
-
2650
- viewArray.set(filtered);
2651
- };
2652
-
2653
- observableDependencies.forEach(dep => dep.subscribe(updateView));
2654
-
2655
- updateView();
2656
-
2657
- return viewArray;
2658
- };
2659
-
2660
- /**
2661
- * Creates a filtered view where at least one of the specified fields matches the filter.
2662
- *
2663
- * @param {Array<string>} fields - Array of field names to check
2664
- * @param {FilterResult} filter - Filter condition with callback and dependencies
2665
- * @returns {ObservableArray} A new observable array containing filtered items
2666
- * @example
2667
- * const products = Observable.array([
2668
- * { name: 'Apple', category: 'Fruit' },
2669
- * { name: 'Carrot', category: 'Vegetable' }
2670
- * ]);
2671
- * const searchTerm = Observable('App');
2672
- * const filtered = products.whereSome(['name', 'category'], match(searchTerm));
2673
- */
2674
- ObservableArray.prototype.whereSome = function(fields, filter) {
2675
- return this.where({
2676
- _: {
2677
- dependencies: filter.dependencies,
2678
- callback: (item) => fields.some(field => filter.callback(item[field]))
2679
- }
2680
- });
2681
- };
2682
-
2683
- /**
2684
- * Creates a filtered view where all specified fields match the filter.
2685
- *
2686
- * @param {Array<string>} fields - Array of field names to check
2687
- * @param {FilterResult} filter - Filter condition with callback and dependencies
2688
- * @returns {ObservableArray} A new observable array containing filtered items
2689
- * @example
2690
- * const items = Observable.array([
2691
- * { status: 'active', verified: true },
2692
- * { status: 'active', verified: false }
2693
- * ]);
2694
- * const activeFilter = equals('active');
2695
- * const filtered = items.whereEvery(['status', 'verified'], activeFilter);
2696
- */
2697
- ObservableArray.prototype.whereEvery = function(fields, filter) {
2698
- return this.where({
2699
- _: {
2700
- dependencies: filter.dependencies,
2701
- callback: (item) => fields.every(field => filter.callback(item[field]))
2702
- }
2703
- });
2704
- };
2705
-
2706
- ObservableArray.prototype.deepSubscribe = function(callback) {
2707
- const updatedValue = nextTick(() => callback(this.val()));
2708
- const $listeners = new WeakMap();
2709
-
2710
- const bindItem = (item) => {
2711
- if ($listeners.has(item)) {
2712
- return;
2713
- }
2714
- if (item?.__$isObservableArray) {
2715
- $listeners.set(item, item.deepSubscribe(updatedValue));
2716
- return;
2717
- }
2718
- if (item?.__$isObservable) {
2719
- item.subscribe(updatedValue);
2720
- $listeners.set(item, () => item.unsubscribe(updatedValue));
2721
- }
2722
- };
2723
-
2724
- const unbindItem = (item) => {
2725
- const unsub = $listeners.get(item);
2726
- if (unsub) {
2727
- unsub();
2728
- $listeners.delete(item);
2729
- }
2730
- };
2731
-
2732
- this.$currentValue.forEach(bindItem);
2733
- this.subscribe(updatedValue);
2734
-
2735
- this.subscribe((items, _, operations) => {
2736
- switch (operations?.action) {
2737
- case 'push':
2738
- case 'unshift':
2739
- operations.args.forEach(bindItem);
2740
- break;
2036
+ $isUnmounting = true;
2741
2037
 
2742
- case 'splice': {
2743
- const [start, deleteCount, ...newItems] = operations.args;
2744
- operations.result?.forEach(unbindItem);
2745
- newItems.forEach(bindItem);
2746
- break;
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;
2747
2046
  }
2047
+ };
2048
+ }
2748
2049
 
2749
- case 'remove':
2750
- unbindItem(operations.result);
2751
- break;
2752
-
2753
- case 'merge':
2754
- operations.args.forEach(bindItem);
2755
- break;
2756
-
2757
- case 'clear':
2758
- this.$currentValue.forEach(unbindItem);
2759
- break;
2760
- }
2761
- });
2050
+ DocumentObserver.beforeUnmount.get(el).set(id, callback);
2051
+ return this;
2052
+ };
2762
2053
 
2763
- return () => {
2764
- this.$currentValue.forEach(unbindItem);
2765
- };
2054
+ NDElement.prototype.htmlElement = function() {
2055
+ return this.$element;
2766
2056
  };
2767
2057
 
2058
+ NDElement.prototype.node = NDElement.prototype.htmlElement;
2768
2059
 
2769
- ObservableArray.prototype.sync = function(targetObservable) {
2770
- if (!targetObservable || !targetObservable.__$isObservableArray) {
2771
- throw new NativeDocumentError('ObservableArray.sync : target must be an ObservableArray');
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);
2772
2068
  }
2069
+ $element.append = shadowRoot.append.bind(shadowRoot);
2070
+ $element.appendChild = shadowRoot.appendChild.bind(shadowRoot);
2071
+ shadowRoot.append(...children);
2773
2072
 
2774
- targetObservable.set([...this.$currentValue]);
2775
-
2776
- const sync = (currentValue, _, operations) => {
2777
- if (!operations) {
2778
- targetObservable.set([...currentValue]);
2779
- return;
2780
- }
2781
-
2782
- const { action, args } = operations;
2783
- targetObservable[action].apply(targetObservable, args);
2784
- };
2785
- this.subscribe(sync);
2786
-
2787
- return () => this.unsubscribe(sync);
2073
+ return this;
2788
2074
  };
2789
2075
 
2790
- ObservableArray.prototype.clone = function() {
2791
- return new ObservableArray(this.resolve());
2076
+ NDElement.prototype.openShadow = function(style = null) {
2077
+ return this.shadow('open', style);
2792
2078
  };
2793
2079
 
2794
- /**
2795
- * Creates an observable array with reactive array methods.
2796
- * All mutations trigger updates automatically.
2797
- *
2798
- * @param {Array} [target=[]] - Initial array value
2799
- * @param {Object|null} [configs=null] - Configuration options
2800
- * // @param {boolean} [configs.propagation=true] - Whether to propagate changes to parent observables
2801
- * // @param {boolean} [configs.deep=false] - Whether to make nested objects observable
2802
- * @param {boolean} [configs.reset=false] - Whether to store initial value for reset()
2803
- * @returns {ObservableArray} An observable array with reactive methods
2804
- * @example
2805
- * const items = Observable.array([1, 2, 3]);
2806
- * items.push(4); // Triggers update
2807
- * items.subscribe((arr) => console.log(arr));
2808
- */
2809
- Observable.array = function(target = [], configs = null) {
2810
- return new ObservableArray(target, configs);
2080
+ NDElement.prototype.closedShadow = function(style = null) {
2081
+ return this.shadow('closed', style);
2811
2082
  };
2812
2083
 
2813
2084
  /**
2085
+ * Extends the current NDElement instance with custom methods.
2086
+ * Methods are bound to the instance and available for chaining.
2814
2087
  *
2815
- * @param {Function} callback
2816
- * @returns {Function}
2088
+ * @param {Object} methods - Object containing method definitions
2089
+ * @returns {this} The NDElement instance with added methods for chaining
2090
+ * @example
2091
+ * element.nd.with({
2092
+ * highlight() {
2093
+ * this.$element.style.background = 'yellow';
2094
+ * return this;
2095
+ * }
2096
+ * }).highlight().onClick(() => console.log('Clicked'));
2817
2097
  */
2818
- Observable.batch = function(callback) {
2819
- const $observer = Observable(0);
2820
- const batch = function() {
2821
- if(Validator.isAsyncFunction(callback)) {
2822
- return (callback(...arguments)).then(() => {
2823
- $observer.trigger();
2824
- }).catch(error => { throw error; });
2825
- }
2826
- callback(...arguments);
2827
- $observer.trigger();
2828
- };
2829
- batch.$observer = $observer;
2830
- return batch;
2831
- };
2832
-
2833
- const ObservableObject = function(target, configs) {
2834
- ObservableItem.call(this, target);
2835
- this.$observables = {};
2836
- this.configs = configs;
2837
-
2838
- this.$load(target);
2839
-
2840
- for(const name in target) {
2841
- if(!Object.hasOwn(this, name)) {
2842
- Object.defineProperty(this, name, {
2843
- get: () => this.$observables[name],
2844
- set: (value) => this.$observables[name].set(value)
2845
- });
2846
- }
2098
+ NDElement.prototype.with = function(methods) {
2099
+ if (!methods || typeof methods !== 'object') {
2100
+ throw new NativeDocumentError('extend() requires an object of methods');
2847
2101
  }
2848
2102
 
2849
- };
2850
-
2851
- ObservableObject.prototype = Object.create(ObservableItem.prototype);
2852
-
2853
- Object.defineProperty(ObservableObject, '$value', {
2854
- get() {
2855
- return this.val();
2856
- },
2857
- set(value) {
2858
- this.set(value);
2859
- }
2860
- });
2103
+ for (const name in methods) {
2104
+ const method = methods[name];
2861
2105
 
2862
- ObservableObject.prototype.__$isObservableObject = true;
2863
- ObservableObject.prototype.__isProxy__ = true;
2864
-
2865
- ObservableObject.prototype.$load = function(initialValue) {
2866
- const configs = this.configs;
2867
- for(const key in initialValue) {
2868
- const itemValue = initialValue[key];
2869
- if(Array.isArray(itemValue)) {
2870
- if(configs?.deep !== false) {
2871
- const mappedItemValue = itemValue.map(item => {
2872
- if(Validator.isJson(item)) {
2873
- return Observable.json(item, configs);
2874
- }
2875
- if(Validator.isArray(item)) {
2876
- return Observable.array(item, configs);
2877
- }
2878
- return Observable(item, configs);
2879
- });
2880
- this.$observables[key] = Observable.array(mappedItemValue, configs);
2881
- continue;
2882
- }
2883
- this.$observables[key] = Observable.array(itemValue, configs);
2884
- continue;
2885
- }
2886
- if(Validator.isObservable(itemValue) || Validator.isProxy(itemValue)) {
2887
- this.$observables[key] = itemValue;
2106
+ if (typeof method !== 'function') {
2107
+ DebugManager$2.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
2888
2108
  continue;
2889
2109
  }
2890
- this.$observables[key] = (typeof itemValue === 'object') ? Observable.object(itemValue, configs) : Observable(itemValue, configs);
2891
- }
2892
- };
2893
2110
 
2894
- ObservableObject.prototype.val = function() {
2895
- const result = {};
2896
- for(const key in this.$observables) {
2897
- const dataItem = this.$observables[key];
2898
- if(Validator.isObservable(dataItem)) {
2899
- let value = dataItem.val();
2900
- if(Array.isArray(value)) {
2901
- value = value.map(item => {
2902
- if(Validator.isObservable(item)) {
2903
- return item.val();
2904
- }
2905
- if(Validator.isProxy(item)) {
2906
- return item.$value;
2907
- }
2908
- return item;
2909
- });
2910
- }
2911
- result[key] = value;
2912
- } else if(Validator.isProxy(dataItem)) {
2913
- result[key] = dataItem.$value;
2914
- } else {
2915
- result[key] = dataItem;
2916
- }
2111
+ this[name] = method.bind(this);
2917
2112
  }
2918
- return result;
2113
+
2114
+ return this;
2919
2115
  };
2920
- ObservableObject.prototype.$val = ObservableObject.prototype.val;
2921
2116
 
2922
- ObservableObject.prototype.get = function(property) {
2923
- const item = this.$observables[property];
2924
- if(Validator.isObservable(item)) {
2925
- return item.val();
2926
- }
2927
- if(Validator.isProxy(item)) {
2928
- return item.$value;
2117
+ /**
2118
+ * Extends the NDElement prototype with new methods available to all NDElement instances.
2119
+ * Use this to add global methods to all NDElements.
2120
+ *
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
2124
+ * @example
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();
2133
+ */
2134
+ NDElement.extend = function(methods) {
2135
+ if (!methods || typeof methods !== 'object') {
2136
+ throw new NativeDocumentError('NDElement.extend() requires an object of methods');
2929
2137
  }
2930
- return item;
2931
- };
2932
- ObservableObject.prototype.$get = ObservableObject.prototype.get;
2933
2138
 
2934
- ObservableObject.prototype.set = function(newData) {
2935
- const data = Validator.isProxy(newData) ? newData.$value : newData;
2936
- const configs = this.configs;
2139
+ if (Array.isArray(methods)) {
2140
+ throw new NativeDocumentError('NDElement.extend() requires an object, not an array');
2141
+ }
2937
2142
 
2938
- for(const key in data) {
2939
- const targetItem = this.$observables[key];
2940
- const newValueOrigin = newData[key];
2941
- const newValue = data[key];
2143
+ const protectedMethods = new Set([
2144
+ 'constructor', 'valueOf', '$element', '$observer',
2145
+ 'ref', 'remove', 'cleanup', 'with', 'extend', 'attach',
2146
+ 'lifecycle', 'mounted', 'unmounted', 'unmountChildren'
2147
+ ]);
2942
2148
 
2943
- if(Validator.isObservable(targetItem)) {
2944
- if(!Validator.isArray(newValue)) {
2945
- targetItem.set(newValue);
2946
- continue;
2947
- }
2948
- const firstElementFromOriginalValue = newValueOrigin.at(0);
2949
- if(Validator.isObservable(firstElementFromOriginalValue) || Validator.isProxy(firstElementFromOriginalValue)) {
2950
- const newValues = newValue.map(item => {
2951
- if(Validator.isProxy(firstElementFromOriginalValue)) {
2952
- return Observable.init(item, configs);
2953
- }
2954
- return Observable(item, configs);
2955
- });
2956
- targetItem.set(newValues);
2957
- continue;
2958
- }
2959
- targetItem.set([...newValue]);
2960
- continue;
2961
- }
2962
- if(Validator.isProxy(targetItem)) {
2963
- targetItem.update(newValue);
2149
+ for (const name in methods) {
2150
+ if (!Object.hasOwn(methods, name)) {
2964
2151
  continue;
2965
2152
  }
2966
- this[key] = newValue;
2967
- }
2968
- };
2969
- ObservableObject.prototype.$set = ObservableObject.prototype.set;
2970
- ObservableObject.prototype.$updateWith = ObservableObject.prototype.set;
2971
-
2972
- ObservableObject.prototype.observables = function() {
2973
- return Object.values(this.$observables);
2974
- };
2975
- ObservableObject.prototype.$observables = ObservableObject.prototype.observables;
2976
2153
 
2977
- ObservableObject.prototype.keys = function() {
2978
- return Object.keys(this.$observables);
2979
- };
2980
- ObservableObject.prototype.$keys = ObservableObject.prototype.keys;
2981
- ObservableObject.prototype.clone = function() {
2982
- return Observable.init(this.val(), this.configs);
2983
- };
2984
- ObservableObject.prototype.$clone = ObservableObject.prototype.clone;
2985
- ObservableObject.prototype.reset = function() {
2986
- for(const key in this.$observables) {
2987
- this.$observables[key].reset();
2988
- }
2989
- };
2990
- ObservableObject.prototype.originalSubscribe = ObservableObject.prototype.subscribe;
2991
- ObservableObject.prototype.subscribe = function(callback) {
2992
- const observables = this.observables();
2993
- const updatedValue = nextTick(() => this.trigger());
2154
+ const method = methods[name];
2994
2155
 
2995
- this.originalSubscribe(callback);
2156
+ if (typeof method !== 'function') {
2157
+ DebugManager$2.warn('NDElement.extend', `"${name}" is not a function, skipping`);
2158
+ continue;
2159
+ }
2996
2160
 
2997
- for (let i = 0, length = observables.length; i < length; i++) {
2998
- const observable = observables[i];
2999
- if (observable.__$isObservableArray) {
3000
- observable.deepSubscribe(updatedValue);
3001
- 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}"`);
3002
2164
  }
3003
- observable.subscribe(updatedValue);
3004
- }
3005
- };
3006
- ObservableObject.prototype.configs = function() {
3007
- return this.configs;
3008
- };
3009
2165
 
3010
- ObservableObject.prototype.update = ObservableObject.prototype.set;
2166
+ if (NDElement.prototype[name]) {
2167
+ DebugManager$2.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
2168
+ }
3011
2169
 
3012
- Observable.init = function(initialValue, configs = null) {
3013
- return new ObservableObject(initialValue, configs)
3014
- };
2170
+ NDElement.prototype[name] = method;
2171
+ }
3015
2172
 
3016
- /**
3017
- *
3018
- * @param {any[]} data
3019
- * @return Proxy[]
3020
- */
3021
- Observable.arrayOfObject = function(data) {
3022
- return data.map(item => Observable.object(item));
2173
+ return NDElement;
3023
2174
  };
3024
2175
 
3025
- /**
3026
- * Get the value of an observable or an object of observables.
3027
- * @param {ObservableItem|Object<ObservableItem>} data
3028
- * @returns {{}|*|null}
3029
- */
3030
- Observable.value = function(data) {
3031
- if(data?.__$isObservableArray) {
3032
- const result = [];
3033
- for(let i = 0, length = data.length; i < length; i++) {
3034
- const item = data.at(i);
3035
- result.push(Observable.value(item));
3036
- }
3037
- return result;
3038
- }
3039
- if(data?.__$Observable) {
3040
- return data.val();
3041
- }
3042
- if(Validator.isProxy(data)) {
3043
- return data.$value;
3044
- }
3045
- return data;
2176
+ const COMMON_NODE_TYPES = {
2177
+ ELEMENT: 1,
2178
+ TEXT: 3,
2179
+ COMMENT: 8,
2180
+ DOCUMENT_FRAGMENT: 11
3046
2181
  };
3047
2182
 
3048
- ObservableItem.prototype.resolve = function () {
3049
- return Observable.value(this);
3050
- };
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;
3051
2188
 
3052
- Observable.object = Observable.init;
3053
- Observable.json = Observable.init;
3054
-
3055
- /**
3056
- * Creates a computed observable that automatically updates when its dependencies change.
3057
- * The callback is re-executed whenever any dependency observable changes.
3058
- *
3059
- * @param {Function} callback - Function that returns the computed value
3060
- * @param {Array<ObservableItem|ObservableChecker|ObservableProxy>|Function} [dependencies=[]] - Array of observables to watch, or batch function
3061
- * @returns {ObservableItem} A new observable that updates automatically
3062
- * @example
3063
- * const firstName = Observable('John');
3064
- * const lastName = Observable('Doe');
3065
- * const fullName = Observable.computed(
3066
- * () => `${firstName.val()} ${lastName.val()}`,
3067
- * [firstName, lastName]
3068
- * );
3069
- *
3070
- * // With batch function
3071
- * const batch = Observable.batch(() => { ... });
3072
- * const computed = Observable.computed(() => { ... }, batch);
3073
- */
3074
- Observable.computed = function(callback, dependencies = []) {
3075
- const initialValue = callback();
3076
- const observable = new ObservableItem(initialValue);
3077
- const getValues = () => dependencies.map((item) => item.val());
3078
- const updatedValue = nextTick(() => observable.set(callback(...getValues())));
3079
-
3080
- if(Validator.isFunction(dependencies)) {
3081
- if(!Validator.isObservable(dependencies.$observer)) {
3082
- throw new NativeDocumentError('Observable.computed : dependencies must be valid batch function');
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];
3083
2263
  }
3084
- dependencies.$observer.subscribe(updatedValue);
3085
- return observable;
3086
- }
3087
2264
 
3088
- dependencies.forEach(dependency => {
3089
- if(Validator.isProxy(dependency)) {
3090
- dependency.$observables.forEach((observable) => {
3091
- observable.subscribe(updatedValue);
3092
- });
3093
- return;
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];
3094
2271
  }
3095
- dependency.subscribe(updatedValue);
3096
- });
3097
-
3098
- return observable;
3099
- };
3100
2272
 
3101
- const $computed = (fn, dependencies) => Observable.computed(fn, dependencies);
3102
- const $checker = (obs, fn) => obs.transform(fn);
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
+ }
3103
2277
 
3104
- //
3105
- // is... -> ObservableChecker<boolean>
3106
- //
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) {},
3107
2304
 
3108
- ObservableItem.prototype.isEqualTo = function (value) {
3109
- if (value?.__$Observable) {
3110
- return $computed((a, b) => a === b, [this, value]);
2305
+ validateEventCallback(callback) {
2306
+ if (typeof callback !== 'function') {
2307
+ throw new NativeDocumentError('Event callback must be a function');
2308
+ }
3111
2309
  }
3112
- return $checker(this, x => x === value);
3113
2310
  };
3114
2311
 
3115
- ObservableItem.prototype.isNotEqualTo = function (value) {
3116
- if (value?.__$Observable) {
3117
- return $computed((a, b) => a !== b, [this, value]);
3118
- }
3119
- return $checker(this, x => x !== value);
3120
- };
2312
+ const cssPropertyAccumulator = function(initialValue = {}) {
2313
+ let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
3121
2314
 
3122
- ObservableItem.prototype.isGreaterThan = function (value) {
3123
- if (value?.__$Observable) {
3124
- return $computed((a, b) => a > b, [this, value]);
3125
- }
3126
- return $checker(this, x => x > value);
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
+ };
3127
2337
  };
3128
2338
 
3129
- ObservableItem.prototype.isGreaterThanOrEqualTo = function (value) {
3130
- if (value?.__$Observable) {
3131
- return $computed((a, b) => a >= b, [this, value]);
3132
- }
3133
- return $checker(this, x => x >= value);
3134
- };
2339
+ const classPropertyAccumulator = function(initialValue = []) {
2340
+ let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
3135
2341
 
3136
- ObservableItem.prototype.isLessThan = function (value) {
3137
- if (value?.__$Observable) {
3138
- return $computed((a, b) => a < b, [this, value]);
3139
- }
3140
- return $checker(this, x => x < value);
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
+ };
3141
2381
  };
3142
2382
 
3143
- ObservableItem.prototype.isLessThanOrEqualTo = function (value) {
3144
- if (value?.__$Observable) {
3145
- return $computed((a, b) => a <= b, [this, value]);
3146
- }
3147
- return $checker(this, x => x <= value);
3148
- };
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
+ }
3149
2402
 
3150
- ObservableItem.prototype.isBetween = function (min, max) {
3151
- if (min.__$Observable && max.__$Observable) {
3152
- return $computed((x, a, b) => x >= a && x <= b, [this, min, max]);
3153
- }
3154
- if (min.__$Observable) {
3155
- return $computed((x, a) => x >= a && x <= max, [this, min]);
3156
- }
3157
- if (max.__$Observable) {
3158
- return $computed((x, b) => x >= min && x <= b, [this, max]);
2403
+ return DebugManager$2.warn('ShowIf', "ShowIf : condition must be an Observable or boolean / "+comment, condition);
3159
2404
  }
3160
- return $checker(this, x => x >= min && x <= max);
3161
- };
3162
-
3163
- ObservableItem.prototype.isNull = function () {
3164
- return $checker(this, x => x == null);
3165
- };
3166
-
3167
- ObservableItem.prototype.isTruthy = function () {
3168
- return $checker(this, x => !!x);
3169
- };
3170
-
3171
- ObservableItem.prototype.isFalsy = function () {
3172
- return $checker(this, x => !x);
3173
- };
2405
+ const element = Anchor('Show if : '+(comment || ''));
3174
2406
 
3175
- ObservableItem.prototype.isStartingWith = function (str) {
3176
- if (str?.__$Observable) {
3177
- return $computed((a, b) => String(a).startsWith(b), [this, str]);
3178
- }
3179
- return $checker(this, x => String(x).startsWith(str));
3180
- };
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
+ };
3181
2418
 
3182
- ObservableItem.prototype.isEndingWith = function (str) {
3183
- if (str?.__$Observable) {
3184
- return $computed((a, b) => String(a).endsWith(b), [this, str]);
3185
- }
3186
- return $checker(this, x => String(x).endsWith(str));
3187
- };
2419
+ const currentValue = condition.val();
3188
2420
 
3189
- ObservableItem.prototype.isMatchingPattern = function (regex) {
3190
- if (regex?.__$Observable) {
3191
- return $computed((a, b) => new RegExp(b).test(String(a)), [this, regex]);
2421
+ if(currentValue) {
2422
+ element.appendChild(getChildElement());
3192
2423
  }
3193
- return $checker(this, x => regex.test(String(x)));
3194
- };
3195
2424
 
3196
- ObservableItem.prototype.isEmpty = function () {
3197
- return $checker(this, x => x == null || x === '' || (Array.isArray(x) && x.length === 0));
3198
- };
2425
+ condition.subscribe((value) => {
2426
+ if(!!value) {
2427
+ element.appendChild(getChildElement());
2428
+ return;
2429
+ }
2430
+ element.remove();
2431
+ });
3199
2432
 
3200
- ObservableItem.prototype.isNotEmpty = function () {
3201
- return $checker(this, x => x == null || x === '' || (Array.isArray(x) && x.length !== 0));
2433
+ return element;
3202
2434
  };
3203
2435
 
3204
- ObservableItem.prototype.isIncludes = function (value) {
3205
- if (value?.__$Observable) {
3206
- return $computed((a, b) => {
3207
- if (Array.isArray(a)) return a.includes(b);
3208
- return String(a).includes(String(b));
3209
- }, [this, value]);
3210
- }
3211
- return $checker(this, x => {
3212
- if (Array.isArray(x)) return x.includes(value);
3213
- return String(x).includes(String(value));
3214
- });
3215
- };
3216
-
3217
- ObservableItem.prototype.isIncludedIn = function (array) {
3218
- if (array?.__$Observable) {
3219
- return $computed((a, b) => b.includes(a), [this, array]);
3220
- }
3221
- return $checker(this, x => array.includes(x));
3222
- };
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",
3223
2500
 
3224
- ObservableItem.prototype.isOneOf = ObservableItem.prototype.isIncludedIn;
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
+ ];
3225
2516
 
3226
- ObservableItem.prototype.isHaving = function (key) {
3227
- if (key?.__$Observable) {
3228
- return $computed((a, b) => b in Object(a), [this, key]);
3229
- }
3230
- return $checker(this, x => key in Object(x));
3231
- };
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
+ ];
3232
2540
 
3233
- //
3234
- // to... -> ObservableChecker<any>
3235
- //
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
+ ];
3236
2584
 
3237
- ObservableItem.prototype.toUpperCase = function () {
3238
- return $checker(this, x => String(x).toUpperCase());
2585
+ const property = {
2586
+ configurable: true,
2587
+ get() {
2588
+ return new NDElement(this);
2589
+ }
3239
2590
  };
3240
2591
 
3241
- ObservableItem.prototype.toLowerCase = function () {
3242
- return $checker(this, x => String(x).toLowerCase());
3243
- };
2592
+ Object.defineProperty(HTMLElement.prototype, 'nd', property);
3244
2593
 
3245
- ObservableItem.prototype.toTrimmed = function () {
3246
- return $checker(this, x => String(x).trim());
3247
- };
2594
+ Object.defineProperty(DocumentFragment.prototype, 'nd', property);
3248
2595
 
3249
- ObservableItem.prototype.toBoolean = function () {
3250
- return $checker(this, x => !!x);
3251
- };
2596
+ Object.defineProperty(NDElement.prototype, 'nd', {
2597
+ configurable: true,
2598
+ get: function() {
2599
+ return this;
2600
+ }
2601
+ });
3252
2602
 
3253
- ObservableItem.prototype.toLiteral = function (template, placeholder = '${v}') {
3254
- return $checker(this, x => template.replace(placeholder, x));
3255
- };
3256
2603
 
3257
- ObservableItem.prototype.toFormatted = ObservableItem.prototype.toLiteral;
3258
2604
 
3259
- ObservableItem.prototype.toProperty = function (key) {
3260
- const keys = key.split('.');
3261
- return $checker(this, x => {
3262
- let value = x;
3263
- for (const k of keys) {
3264
- if (value == null) return undefined;
3265
- value = value[k];
3266
- }
3267
- return value;
3268
- });
3269
- };
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
+ });
3270
2615
 
3271
- ObservableItem.prototype.toLength = function () {
3272
- return $checker(this, x => (x == null ? 0 : x.length));
3273
- };
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
+ });
3274
2627
 
3275
- ObservableItem.prototype.toClamped = function (min, max) {
3276
- if (min.__$Observable && max.__$Observable) {
3277
- return $computed((x, a, b) => Math.min(Math.max(x, a), b), [this, min, max]);
3278
- }
3279
- if (min.__$Observable) {
3280
- return $computed((x, a) => Math.min(Math.max(x, a), max), [this, min]);
3281
- }
3282
- if (max.__$Observable) {
3283
- return $computed((x, b) => Math.min(Math.max(x, min), b), [this, max]);
3284
- }
3285
- return $checker(this, x => Math.min(Math.max(x, min), max));
3286
- };
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
+ });
3287
2635
 
3288
- ObservableItem.prototype.toPercent = function (total) {
3289
- if (total?.__$Observable) {
3290
- return $computed((a, b) => (b === 0 ? 0 : (a / b) * 100), [this, total]);
3291
- }
3292
- return $checker(this, x => (total === 0 ? 0 : (x / total) * 100));
2636
+ NDElement.prototype.on = function(name, callback, options) {
2637
+ this.$element.addEventListener(name.toLowerCase(), callback, options);
2638
+ return this;
3293
2639
  };
3294
2640
 
3295
- const StoreFactory = function() {
3296
-
3297
- const $stores = new Map();
3298
- const $followersCache = new Map();
3299
-
3300
- /**
3301
- * Internal helper — retrieves a store entry or throws if not found.
3302
- */
3303
- const $getStoreOrThrow = (method, name) => {
3304
- const item = $stores.get(name);
3305
- if (!item) {
3306
- DebugManager$2.error('Store', `Store.${method}('${name}') : store not found. Did you call Store.create('${name}') first?`);
3307
- throw new NativeDocumentError(
3308
- `Store.${method}('${name}') : store not found.`
3309
- );
3310
- }
3311
- return item;
2641
+ const _prevent = function(element, eventName, callback) {
2642
+ const handler = (event) => {
2643
+ event.preventDefault();
2644
+ callback && callback.call(element, event);
3312
2645
  };
2646
+ element.addEventListener(eventName, handler);
2647
+ return this;
2648
+ };
3313
2649
 
3314
- /**
3315
- * Internal helper blocks write operations on a read-only observer.
3316
- */
3317
- const $applyReadOnly = (observer, name, context) => {
3318
- const readOnlyError = (method) => () => {
3319
- DebugManager$2.error('Store', `Store.${context}('${name}') is read-only. '${method}()' is not allowed.`);
3320
- throw new NativeDocumentError(
3321
- `Store.${context}('${name}') is read-only.`
3322
- );
3323
- };
3324
- observer.set = readOnlyError('set');
3325
- observer.toggle = readOnlyError('toggle');
3326
- observer.reset = readOnlyError('reset');
2650
+ const _stop = function(element, eventName, callback) {
2651
+ const handler = (event) => {
2652
+ event.stopPropagation();
2653
+ callback && callback.call(element, event);
3327
2654
  };
2655
+ element.addEventListener(eventName, handler);
2656
+ return this;
2657
+ };
3328
2658
 
3329
- const $createObservable = (value, options = {}) => {
3330
- if(Array.isArray(value)) {
3331
- return Observable.array(value, options);
3332
- }
3333
- if(typeof value === 'object') {
3334
- return Observable.object(value, options);
3335
- }
3336
- 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);
3337
2664
  };
2665
+ element.addEventListener(eventName, handler);
2666
+ return this;
2667
+ };
3338
2668
 
3339
- const $api = {
3340
- /**
3341
- * Create a new state and return the observer.
3342
- * Throws if a store with the same name already exists.
3343
- *
3344
- * @param {string} name
3345
- * @param {*} value
3346
- * @returns {ObservableItem}
3347
- */
3348
- create(name, value) {
3349
- if ($stores.has(name)) {
3350
- DebugManager$2.warn('Store', `Store.create('${name}') : a store with this name already exists. Use Store.get('${name}') to retrieve it.`);
3351
- throw new NativeDocumentError(
3352
- `Store.create('${name}') : a store with this name already exists.`
3353
- );
3354
- }
3355
- const observer = $createObservable(value);
3356
- $stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: false });
3357
- return observer;
3358
- },
3359
2669
 
3360
- /**
3361
- * Create a new resettable state and return the observer.
3362
- * The store can be reset to its initial value via Store.reset(name).
3363
- * Throws if a store with the same name already exists.
3364
- *
3365
- * @param {string} name
3366
- * @param {*} value
3367
- * @returns {ObservableItem}
3368
- */
3369
- createResettable(name, value) {
3370
- if ($stores.has(name)) {
3371
- DebugManager$2.warn('Store', `Store.createResettable('${name}') : a store with this name already exists.`);
3372
- throw new NativeDocumentError(
3373
- `Store.createResettable('${name}') : a store with this name already exists.`
3374
- );
3375
- }
3376
- const observer = $createObservable(value, { reset: true });
3377
- $stores.set(name, { observer, subscribers: new Set(), resettable: true, composed: false });
3378
- return observer;
3379
- },
3380
2670
 
3381
- /**
3382
- * Create a computed store derived from other stores.
3383
- * The value is automatically recalculated when any dependency changes.
3384
- * This store is read-only — Store.use() and Store.set() will throw.
3385
- * Throws if a store with the same name already exists.
3386
- *
3387
- * @param {string} name
3388
- * @param {() => *} computation - Function that returns the computed value
3389
- * @param {string[]} dependencies - Names of the stores to watch
3390
- * @returns {ObservableItem}
3391
- *
3392
- * @example
3393
- * Store.create('products', [{ id: 1, price: 10 }]);
3394
- * Store.create('cart', [{ productId: 1, quantity: 2 }]);
3395
- *
3396
- * Store.createComposed('total', () => {
3397
- * const products = Store.get('products').val();
3398
- * const cart = Store.get('cart').val();
3399
- * return cart.reduce((sum, item) => {
3400
- * const product = products.find(p => p.id === item.productId);
3401
- * return sum + (product.price * item.quantity);
3402
- * }, 0);
3403
- * }, ['products', 'cart']);
3404
- */
3405
- createComposed(name, computation, dependencies) {
3406
- if ($stores.has(name)) {
3407
- DebugManager$2.warn('Store', `Store.createComposed('${name}') : a store with this name already exists.`);
3408
- throw new NativeDocumentError(
3409
- `Store.createComposed('${name}') : a store with this name already exists.`
3410
- );
3411
- }
3412
- if (typeof computation !== 'function') {
3413
- throw new NativeDocumentError(
3414
- `Store.createComposed('${name}') : computation must be a function.`
3415
- );
3416
- }
3417
- if (!Array.isArray(dependencies) || dependencies.length === 0) {
3418
- throw new NativeDocumentError(
3419
- `Store.createComposed('${name}') : dependencies must be a non-empty array of store names.`
3420
- );
3421
- }
3422
-
3423
- // Resolve dependency observers
3424
- const depObservers = dependencies.map(depName => {
3425
- if(typeof depName !== 'string') {
3426
- return depName;
3427
- }
3428
- const depItem = $stores.get(depName);
3429
- if (!depItem) {
3430
- DebugManager$2.error('Store', `Store.createComposed('${name}') : dependency '${depName}' not found. Create it first.`);
3431
- throw new NativeDocumentError(
3432
- `Store.createComposed('${name}') : dependency store '${depName}' not found.`
3433
- );
3434
- }
3435
- return depItem.observer;
3436
- });
3437
-
3438
- // Create computed observable from dependency observers
3439
- const observer = Observable.computed(computation, depObservers);
3440
-
3441
- $stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: true });
3442
- return observer;
3443
- },
3444
-
3445
- /**
3446
- * Returns true if a store with the given name exists.
3447
- *
3448
- * @param {string} name
3449
- * @returns {boolean}
3450
- */
3451
- has(name) {
3452
- return $stores.has(name);
3453
- },
3454
-
3455
- /**
3456
- * Resets a resettable store to its initial value and notifies all subscribers.
3457
- * Throws if the store was not created with createResettable().
3458
- *
3459
- * @param {string} name
3460
- */
3461
- reset(name) {
3462
- const item = $getStoreOrThrow('reset', name);
3463
- if (item.composed) {
3464
- DebugManager$2.error('Store', `Store.reset('${name}') : composed stores cannot be reset. Their value is derived from dependencies.`);
3465
- throw new NativeDocumentError(
3466
- `Store.reset('${name}') : composed stores cannot be reset.`
3467
- );
3468
- }
3469
- if (!item.resettable) {
3470
- DebugManager$2.error('Store', `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`);
3471
- throw new NativeDocumentError(
3472
- `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`
3473
- );
3474
- }
3475
- item.observer.reset();
3476
- },
3477
-
3478
- /**
3479
- * Returns a two-way synchronized follower of the store.
3480
- * Writing to the follower propagates the value back to the store and all its subscribers.
3481
- * Throws if called on a composed store — use Store.follow() instead.
3482
- * Call follower.destroy() or follower.dispose() to unsubscribe.
3483
- *
3484
- * @param {string} name
3485
- * @returns {ObservableItem}
3486
- */
3487
- use(name) {
3488
- const item = $getStoreOrThrow('use', name);
3489
-
3490
- if (item.composed) {
3491
- DebugManager$2.error('Store', `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`);
3492
- throw new NativeDocumentError(
3493
- `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`
3494
- );
3495
- }
3496
-
3497
- const { observer: originalObserver, subscribers } = item;
3498
- const observerFollower = $createObservable(originalObserver.val());
3499
-
3500
- const onStoreChange = value => observerFollower.set(value);
3501
- const onFollowerChange = value => originalObserver.set(value);
3502
-
3503
- originalObserver.subscribe(onStoreChange);
3504
- observerFollower.subscribe(onFollowerChange);
3505
-
3506
- observerFollower.destroy = () => {
3507
- originalObserver.unsubscribe(onStoreChange);
3508
- observerFollower.unsubscribe(onFollowerChange);
3509
- subscribers.delete(observerFollower);
3510
- observerFollower.cleanup();
3511
- };
3512
- observerFollower.dispose = observerFollower.destroy;
3513
-
3514
- subscribers.add(observerFollower);
3515
- return observerFollower;
3516
- },
3517
-
3518
- /**
3519
- * Returns a read-only follower of the store.
3520
- * The follower reflects store changes but cannot write back to the store.
3521
- * Any attempt to call .set(), .toggle() or .reset() will throw.
3522
- * Call follower.destroy() or follower.dispose() to unsubscribe.
3523
- *
3524
- * @param {string} name
3525
- * @returns {ObservableItem}
3526
- */
3527
- follow(name) {
3528
- const { observer: originalObserver, subscribers } = $getStoreOrThrow('follow', name);
3529
- const observerFollower = $createObservable(originalObserver.val());
3530
-
3531
- const onStoreChange = value => observerFollower.set(value);
3532
- originalObserver.subscribe(onStoreChange);
3533
-
3534
- $applyReadOnly(observerFollower, name, 'follow');
3535
-
3536
- observerFollower.destroy = () => {
3537
- originalObserver.unsubscribe(onStoreChange);
3538
- subscribers.delete(observerFollower);
3539
- observerFollower.cleanup();
3540
- };
3541
- observerFollower.dispose = observerFollower.destroy;
3542
-
3543
- subscribers.add(observerFollower);
3544
- return observerFollower;
3545
- },
3546
-
3547
- /**
3548
- * Returns the raw store observer directly (no follower, no cleanup contract).
3549
- * Use this for direct read access when you don't need to unsubscribe.
3550
- * WARNING : mutations on this observer impact all subscribers immediately.
3551
- *
3552
- * @param {string} name
3553
- * @returns {ObservableItem|null}
3554
- */
3555
- get(name) {
3556
- const item = $stores.get(name);
3557
- if (!item) {
3558
- DebugManager$2.warn('Store', `Store.get('${name}') : store not found.`);
3559
- return null;
3560
- }
3561
- return item.observer;
3562
- },
3563
-
3564
- /**
3565
- * @param {string} name
3566
- * @returns {{ observer: ObservableItem, subscribers: Set } | null}
3567
- */
3568
- getWithSubscribers(name) {
3569
- return $stores.get(name) ?? null;
3570
- },
3571
-
3572
- /**
3573
- * Destroys a store : cleans up the observer, destroys all followers, and removes the entry.
3574
- *
3575
- * @param {string} name
3576
- */
3577
- delete(name) {
3578
- const item = $stores.get(name);
3579
- if (!item) {
3580
- DebugManager$2.warn('Store', `Store.delete('${name}') : store not found, nothing to delete.`);
2671
+ // ----------------------------------------------------------------
2672
+ // Class attributes binder
2673
+ // ----------------------------------------------------------------
2674
+ const classListMethods = {
2675
+ getClasses() {
2676
+ return this.$element.className?.split(' ').filter(Boolean);
2677
+ },
2678
+ add(value) {
2679
+ const classes = this.getClasses();
2680
+ if(classes.indexOf(value) >= 0) {
2681
+ return;
2682
+ }
2683
+ classes.push(value);
2684
+ this.$element.className = classes.join(' ');
2685
+ },
2686
+ remove(value) {
2687
+ const classes = this.getClasses();
2688
+ const index = classes.indexOf(value);
2689
+ if(index < 0) {
2690
+ return;
2691
+ }
2692
+ classes.splice(index, 1);
2693
+ this.$element.className = classes.join(' ');
2694
+ },
2695
+ toggle(value, force = undefined) {
2696
+ const classes = this.getClasses();
2697
+ const index = classes.indexOf(value);
2698
+ if(index >= 0) {
2699
+ if(force === true) {
3581
2700
  return;
3582
2701
  }
3583
- item.subscribers.forEach(follower => follower.destroy());
3584
- item.subscribers.clear();
3585
- item.observer.cleanup();
3586
- $stores.delete(name);
3587
- },
3588
- /**
3589
- * Creates an isolated store group with its own state namespace.
3590
- * Each group is a fully independent StoreFactory instance —
3591
- * no key conflicts, no shared state with the parent store.
3592
- *
3593
- * @param {string | ((group: ReturnType<typeof StoreFactory>) => void)} name - Group name for debugging, or setup callback if no name is provided
3594
- * @param {((group: ReturnType<typeof StoreFactory>) => void)} [callback] - Setup function receiving the isolated store instance
3595
- * @returns {ReturnType<typeof StoreFactory>}
3596
- *
3597
- * @example
3598
- * // With name (recommended)
3599
- * const EventStore = Store.group('events', (group) => {
3600
- * group.create('catalog', []);
3601
- * group.create('filters', { category: null, date: null });
3602
- * group.createResettable('selected', null);
3603
- * group.createComposed('filtered', () => {
3604
- * const catalog = EventStore.get('catalog').val();
3605
- * const filters = EventStore.get('filters').val();
3606
- * return catalog.filter(event => {
3607
- * if (filters.category && event.category !== filters.category) return false;
3608
- * return true;
3609
- * });
3610
- * }, ['catalog', 'filters']);
3611
- * });
3612
- *
3613
- * // Without name
3614
- * const CartStore = Store.group((group) => {
3615
- * group.create('items', []);
3616
- * });
3617
- *
3618
- * // Usage
3619
- * EventStore.use('catalog'); // two-way follower
3620
- * EventStore.follow('filtered'); // read-only follower
3621
- * EventStore.get('filters'); // raw observable
3622
- *
3623
- * // Cross-group composed
3624
- * const OrderStore = Store.group('orders', (group) => {
3625
- * group.createComposed('summary', () => {
3626
- * const items = CartStore.get('items').val();
3627
- * const events = EventStore.get('catalog').val();
3628
- * return { items, events };
3629
- * }, [CartStore.get('items'), EventStore.get('catalog')]);
3630
- * });
3631
- */
3632
- group(name, callback) {
3633
- if (typeof name === 'function') {
3634
- callback = name;
3635
- name = 'anonymous';
3636
- }
3637
- const store = StoreFactory();
3638
- callback && callback(store);
3639
- return store;
3640
- },
3641
- createPersistent(name, value, localstorage_key) {
3642
- localstorage_key = localstorage_key || name;
3643
- const observer = this.create(name, $getFromStorage(localstorage_key, value));
3644
- const saver = $saveToStorage(value);
3645
-
3646
- observer.subscribe((val) => saver(localstorage_key, val));
3647
- return observer;
3648
- },
3649
- createPersistentResettable(name, value, localstorage_key) {
3650
- localstorage_key = localstorage_key || name;
3651
- const observer = this.createResettable(name, $getFromStorage(localstorage_key, value));
3652
- const saver = $saveToStorage(value);
3653
- observer.subscribe((val) => saver(localstorage_key, val));
3654
-
3655
- const originalReset = observer.reset.bind(observer);
3656
- observer.reset = () => {
3657
- LocalStorage.remove(localstorage_key);
3658
- originalReset();
3659
- };
3660
-
3661
- return observer;
2702
+ classes.splice(index, 1);
3662
2703
  }
3663
- };
3664
-
3665
-
3666
- return new Proxy($api, {
3667
- get(target, prop) {
3668
- if (typeof prop === 'symbol' || prop.startsWith('$') || prop in target) {
3669
- return target[prop];
3670
- }
3671
- if (target.has(prop)) {
3672
- if ($followersCache.has(prop)) {
3673
- return $followersCache.get(prop);
3674
- }
3675
- const follower = target.follow(prop);
3676
- $followersCache.set(prop, follower);
3677
- return follower;
2704
+ else {
2705
+ if(force === false) {
2706
+ return;
3678
2707
  }
3679
- return undefined;
3680
- },
3681
- set(target, prop, value) {
3682
- DebugManager$2.error('Store', `Forbidden: You cannot overwrite the store key '${String(prop)}'. Use .use('${String(prop)}').set(value) instead.`);
3683
- throw new NativeDocumentError(`Store structure is immutable. Use .set() on the observable.`);
3684
- },
3685
- deleteProperty(target, prop) {
3686
- throw new NativeDocumentError(`Store keys cannot be deleted.`);
2708
+ classes.push(value);
3687
2709
  }
3688
- });
2710
+ this.$element.className = classes.join(' ');
2711
+ },
2712
+ contains(value) {
2713
+ return this.getClasses().indexOf(value) >= 0;
2714
+ }
3689
2715
  };
3690
2716
 
3691
- const Store = StoreFactory();
3692
-
3693
- Store.create('locale', navigator.language.split('-')[0] || 'en');
3694
-
3695
- /**
3696
- * Conditionally shows an element based on an observable condition.
3697
- * The element is mounted/unmounted from the DOM as the condition changes.
3698
- *
3699
- * @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
3700
- * @param {NdChild|(() => NdChild)} child - Element or content to show/hide
3701
- * @param {Object} [options={}] - Configuration options
3702
- * @param {string|null} [options.comment=null] - Comment for debugging
3703
- * @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
3704
- * @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
3705
- * @example
3706
- * const isVisible = Observable(false);
3707
- * ShowIf(isVisible, Div({}, 'Hello World'));
3708
- */
3709
- const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
3710
- if(!Validator.isObservable(condition)) {
3711
- if(typeof condition === "boolean") {
3712
- return condition ? ElementCreator.getChild(child) : null;
3713
- }
3714
-
3715
- return DebugManager$2.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
+ };
3716
2724
  }
3717
- const element = Anchor('Show if : '+(comment || ''));
3718
-
3719
- let childElement = null;
3720
- const getChildElement = () => {
3721
- if(childElement && shouldKeepInCache) {
3722
- return childElement;
3723
- }
3724
- childElement = ElementCreator.getChild(child);
3725
- if(Validator.isFragment(childElement)) {
3726
- childElement = Array.from(childElement.childNodes);
3727
- }
3728
- return childElement;
3729
- };
3730
-
3731
- const currentValue = condition.val();
2725
+ });
3732
2726
 
3733
- if(currentValue) {
3734
- element.appendChild(getChildElement());
2727
+ const normalizeComponentArgs = function(props, children = null) {
2728
+ if(props && children) {
2729
+ return { props, children };
3735
2730
  }
3736
-
3737
- condition.subscribe((value) => {
3738
- if(!!value) {
3739
- element.appendChild(getChildElement());
3740
- return;
3741
- }
3742
- element.remove();
3743
- });
3744
-
3745
- return element;
3746
- };
3747
-
3748
- /**
3749
- * Creates a `<div>` element.
3750
- * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
3751
- */
3752
- const Div = HtmlElementWrapper('div');
3753
-
3754
- function oneChildAnchorOverwriting(anchor, parent) {
3755
-
3756
- anchor.remove = () => {
3757
- anchor.append.apply(anchor, parent.childNodes);
3758
- };
3759
- anchor.getParent = () => parent;
3760
-
3761
- anchor.appendChild = (child) => {
3762
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3763
- parent.appendChild(child);
3764
- };
3765
-
3766
- anchor.appendChildRaw = parent.appendChild.bind(parent);
3767
- anchor.append = anchor.appendChild;
3768
- anchor.appendRaw = anchor.appendChildRaw;
3769
-
3770
- anchor.insertAtStart = (child) => {
3771
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3772
- parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
3773
- };
3774
- anchor.insertAtStartRaw = (child) => {
3775
- parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
3776
- };
3777
-
3778
- anchor.appendElement = anchor.appendChild;
3779
-
3780
- anchor.removeChildren = () => {
3781
- parent.textContent = '';
3782
- };
3783
-
3784
- anchor.replaceContent = function(content) {
3785
- const child = Validator.isElement(content) ? content : ElementCreator.getChild(content);
3786
- parent.replaceChildren(child);
3787
- };
3788
-
3789
- anchor.replaceContentRaw = function(child) {
3790
- parent.replaceChildren(child);
3791
- };
3792
- anchor.setContent = anchor.replaceContent;
3793
-
3794
- anchor.insertBefore = (child, anchor) => {
3795
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3796
- parent.insertBefore(child, anchor);
3797
- };
3798
- anchor.insertBeforeRaw = (child, anchor) => {
3799
- parent.insertBefore(child, anchor);
3800
- };
3801
-
3802
- anchor.appendChildBefore = anchor.insertBefore;
3803
- anchor.appendChildBeforeRaw = anchor.insertBeforeRaw;
3804
-
3805
- anchor.clear = anchor.remove;
3806
- anchor.detach = anchor.remove;
3807
-
3808
- anchor.replaceChildren = function() {
3809
- parent.replaceChildren(...arguments);
3810
- };
3811
-
3812
- anchor.getByIndex = (index) => {
3813
- return parent.childNodes[index];
3814
- };
3815
- }
3816
-
3817
- function Anchor(name, isUniqueChild = false) {
3818
- const anchorFragment = new AnchorWithSentinel(name);
3819
-
3820
- anchorFragment.onConnectedOnce((parent) => {
3821
- if(isUniqueChild) {
3822
- oneChildAnchorOverwriting(anchorFragment, parent);
3823
- }
3824
- });
3825
-
3826
- anchorFragment.__Anchor__ = true;
3827
-
3828
- const anchorStart = anchorFragment.$start;
3829
- const anchorEnd = anchorFragment.$end;
3830
-
3831
- anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
3832
- anchorFragment.nativeAppendChild = anchorFragment.appendChild;
3833
- anchorFragment.nativeAppend = anchorFragment.append;
3834
-
3835
- const isParentUniqueChild = isUniqueChild
3836
- ? () => true: (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
3837
-
3838
- const insertBefore = (parent, child, target) => {
3839
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3840
- insertBeforeRaw(parent, childElement, target);
3841
- };
3842
-
3843
- const insertBeforeRaw = (parent, child, target) => {
3844
- if(parent === anchorFragment) {
3845
- parent.nativeInsertBefore(child, target);
3846
- return;
3847
- }
3848
- if(isParentUniqueChild(parent) && target === anchorEnd) {
3849
- parent.append(child, target);
3850
- return;
3851
- }
3852
- parent.insertBefore(child, target);
3853
- };
3854
-
3855
- anchorFragment.appendElement = function(child) {
3856
- const parentNode = anchorStart.parentNode;
3857
- if(parentNode === anchorFragment) {
3858
- parentNode.nativeInsertBefore(child, anchorEnd);
3859
- return;
3860
- }
3861
- parentNode.insertBefore(child, anchorEnd);
3862
- };
3863
-
3864
- anchorFragment.appendChild = function(child, before = null) {
3865
- const parent = anchorEnd.parentNode;
3866
- if(!parent) {
3867
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
3868
- return;
3869
- }
3870
- before = before ?? anchorEnd;
3871
- insertBefore(parent, child, before);
3872
- };
3873
-
3874
- anchorFragment.appendChildRaw = function(child, before = null) {
3875
- const parent = anchorEnd.parentNode;
3876
- if(!parent) {
3877
- DebugManager.error('Anchor', 'Anchor : parent not found', child);
3878
- return;
3879
- }
3880
- before = before ?? anchorEnd;
3881
- insertBeforeRaw(parent, child, before);
3882
- };
3883
-
3884
- anchorFragment.getParent = () => anchorEnd.parentNode;
3885
- anchorFragment.append = anchorFragment.appendChild;
3886
- anchorFragment.appendRaw = anchorFragment.appendChildRaw;
3887
-
3888
- anchorFragment.insertAtStart = function(child) {
3889
- child = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3890
- anchorFragment.insertAtStartRaw(child);
3891
- };
3892
-
3893
- anchorFragment.insertAtStartRaw = function(child) {
3894
- const parentNode = anchorStart.parentNode;
3895
- if(parentNode === anchorFragment) {
3896
- parentNode.nativeInsertBefore(child, anchorStart);
3897
- return;
3898
- }
3899
- parentNode.insertBefore(child, anchorStart);
3900
- };
3901
-
3902
- anchorFragment.removeChildren = function() {
3903
- const parent = anchorEnd.parentNode;
3904
- if(parent === anchorFragment) {
3905
- return;
3906
- }
3907
- if(isParentUniqueChild(parent)) {
3908
- parent.replaceChildren(anchorStart, anchorEnd);
3909
- return;
3910
- }
3911
-
3912
- let itemToRemove = anchorStart.nextSibling, tempItem;
3913
- while(itemToRemove && itemToRemove !== anchorEnd) {
3914
- tempItem = itemToRemove.nextSibling;
3915
- itemToRemove.remove();
3916
- itemToRemove = tempItem;
3917
- }
3918
- };
3919
-
3920
- anchorFragment.remove = function() {
3921
- const parent = anchorEnd.parentNode;
3922
- if(parent === anchorFragment) {
3923
- return;
3924
- }
3925
- if(isParentUniqueChild(parent)) {
3926
- anchorFragment.nativeAppend.apply(anchorFragment, parent.childNodes);
3927
- parent.replaceChildren(anchorStart, anchorEnd);
3928
- return;
3929
- }
3930
- let itemToRemove = anchorStart.nextSibling, tempItem;
3931
- while(itemToRemove && itemToRemove !== anchorEnd) {
3932
- tempItem = itemToRemove.nextSibling;
3933
- anchorFragment.nativeAppend(itemToRemove);
3934
- itemToRemove = tempItem;
3935
- }
3936
- };
3937
-
3938
- anchorFragment.removeWithAnchors = function() {
3939
- anchorFragment.removeChildren();
3940
- anchorStart.remove();
3941
- anchorEnd.remove();
3942
- };
3943
- anchorFragment.delete = anchorFragment.removeWithAnchors;
3944
-
3945
- anchorFragment.replaceContent = function(child) {
3946
- const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
3947
- anchorFragment.replaceContentRaw(childElement);
3948
- };
3949
-
3950
- anchorFragment.replaceContentRaw = function(child) {
3951
- const parent = anchorEnd.parentNode;
3952
- if(!parent) {
3953
- return;
3954
- }
3955
- if(isParentUniqueChild(parent)) {
3956
- parent.replaceChildren(anchorStart, child, anchorEnd);
3957
- return;
3958
- }
3959
- anchorFragment.removeChildren();
3960
- parent.insertBefore(child, anchorEnd);
3961
- };
3962
-
3963
- anchorFragment.setContent = anchorFragment.replaceContent;
3964
- anchorFragment.setContentRaw = anchorFragment.replaceContentRaw;
3965
-
3966
- anchorFragment.insertBefore = anchorFragment.appendChild;
3967
- anchorFragment.insertBeforeRaw = anchorFragment.appendChildRaw;
3968
-
3969
- anchorFragment.endElement = function() {
3970
- return anchorEnd;
3971
- };
3972
-
3973
- anchorFragment.startElement = function() {
3974
- return anchorStart;
3975
- };
3976
-
3977
- anchorFragment.restore = function() {
3978
- anchorFragment.appendChild(anchorFragment);
3979
- };
3980
-
3981
- anchorFragment.clear = anchorFragment.remove;
3982
- anchorFragment.detach = anchorFragment.remove;
3983
-
3984
- anchorFragment.getByIndex = function(index) {
3985
- let currentNode = anchorStart;
3986
- for(let i = 0; i <= index; i++) {
3987
- if(!currentNode.nextSibling) {
3988
- return null;
3989
- }
3990
- currentNode = currentNode.nextSibling;
3991
- }
3992
- return currentNode !== anchorStart ? currentNode : null;
3993
- };
3994
-
3995
- return anchorFragment;
3996
- }
3997
- DocumentFragment.prototype.setAttribute = () => {};
3998
-
3999
- function NDElement(element) {
4000
- this.$element = element;
4001
- this.$attachements = null;
4002
- }
4003
-
4004
- NDElement.prototype.__$isNDElement = true;
4005
-
4006
- NDElement.prototype.ghostDom = function(element) {
4007
- if(!this.$attachements) {
4008
- this.$attachements = document.createDocumentFragment();
4009
- }
4010
- this.$attachements.appendChild(ElementCreator.getChild(element));
4011
- return this;
4012
- };
4013
-
4014
- NDElement.prototype.valueOf = function() {
4015
- return this.$element;
4016
- };
4017
-
4018
- NDElement.prototype.ref = function(target, name) {
4019
- target[name] = this.$element;
4020
- return this;
4021
- };
4022
-
4023
- NDElement.prototype.refSelf = function(target, name) {
4024
- target[name] = this;
4025
- // TODO: @DIM to check
4026
- // target[name] = new NDElement(this.$element);
4027
- return this;
4028
- };
4029
-
4030
- NDElement.prototype.unmountChildren = function() {
4031
- let element = this.$element;
4032
- for(let i = 0, length = element.children.length; i < length; i++) {
4033
- let elementChildren = element.children[i];
4034
- if(!elementChildren.$ndProx) {
4035
- elementChildren.nd?.remove();
4036
- }
4037
- elementChildren = null;
4038
- }
4039
- element = null;
4040
- return this;
4041
- };
4042
-
4043
- NDElement.prototype.remove = function() {
4044
- let element = this.$element;
4045
- element.nd.unmountChildren();
4046
- element.$ndProx = null;
4047
-
4048
- $lifeCycleObservers.delete(element);
4049
-
4050
- element = null;
4051
- return this;
4052
- };
4053
-
4054
- const $lifeCycleObservers = new WeakMap();
4055
- NDElement.prototype.lifecycle = function(states) {
4056
- const el = this.$element;
4057
- if (!$lifeCycleObservers.has(el)) {
4058
- $lifeCycleObservers.set(el, DocumentObserver.watch(el));
4059
- }
4060
- const observer = $lifeCycleObservers.get(el);
4061
-
4062
- if(states.mounted) {
4063
- this.$element.setAttribute('data--nd-mounted', '1');
4064
- observer.mounted(states.mounted);
4065
- }
4066
- if(states.unmounted) {
4067
- this.$element.setAttribute('data--nd-unmounted', '1');
4068
- observer.unmounted(states.unmounted);
4069
- }
4070
- return this;
4071
- };
4072
-
4073
- NDElement.prototype.mounted = function(callback) {
4074
- return this.lifecycle({ mounted: callback });
4075
- };
4076
-
4077
- NDElement.prototype.unmounted = function(callback) {
4078
- return this.lifecycle({ unmounted: callback });
4079
- };
4080
-
4081
- NDElement.prototype.beforeUnmount = function(id, callback) {
4082
- const el = this.$element;
4083
-
4084
- if(!DocumentObserver.beforeUnmount.has(el)) {
4085
- DocumentObserver.beforeUnmount.set(el, new Map());
4086
- const originalRemove = el.remove.bind(el);
4087
-
4088
- let $isUnmounting = false;
4089
-
4090
- el.remove = async () => {
4091
- if($isUnmounting) {
4092
- return;
4093
- }
4094
- $isUnmounting = true;
4095
-
4096
- try {
4097
- const callbacks = DocumentObserver.beforeUnmount.get(el);
4098
- for (const cb of callbacks.values()) {
4099
- await cb.call(this, el);
4100
- }
4101
- } finally {
4102
- originalRemove();
4103
- $isUnmounting = false;
4104
- }
4105
- };
4106
- }
4107
-
4108
- DocumentObserver.beforeUnmount.get(el).set(id, callback);
4109
- return this;
4110
- };
4111
-
4112
- NDElement.prototype.htmlElement = function() {
4113
- return this.$element;
4114
- };
4115
-
4116
- NDElement.prototype.node = NDElement.prototype.htmlElement;
4117
-
4118
- NDElement.prototype.shadow = function(mode, style = null) {
4119
- const $element = this.$element;
4120
- const children = Array.from($element.childNodes);
4121
- const shadowRoot = $element.attachShadow({ mode });
4122
- if(style) {
4123
- const styleNode = document.createElement("style");
4124
- styleNode.textContent = style;
4125
- shadowRoot.appendChild(styleNode);
4126
- }
4127
- $element.append = shadowRoot.append.bind(shadowRoot);
4128
- $element.appendChild = shadowRoot.appendChild.bind(shadowRoot);
4129
- shadowRoot.append(...children);
4130
-
4131
- return this;
4132
- };
4133
-
4134
- NDElement.prototype.openShadow = function(style = null) {
4135
- return this.shadow('open', style);
4136
- };
4137
-
4138
- NDElement.prototype.closedShadow = function(style = null) {
4139
- return this.shadow('closed', style);
4140
- };
4141
-
4142
- /**
4143
- * Extends the current NDElement instance with custom methods.
4144
- * Methods are bound to the instance and available for chaining.
4145
- *
4146
- * @param {Object} methods - Object containing method definitions
4147
- * @returns {this} The NDElement instance with added methods for chaining
4148
- * @example
4149
- * element.nd.with({
4150
- * highlight() {
4151
- * this.$element.style.background = 'yellow';
4152
- * return this;
4153
- * }
4154
- * }).highlight().onClick(() => console.log('Clicked'));
4155
- */
4156
- NDElement.prototype.with = function(methods) {
4157
- if (!methods || typeof methods !== 'object') {
4158
- throw new NativeDocumentError('extend() requires an object of methods');
4159
- }
4160
-
4161
- for (const name in methods) {
4162
- const method = methods[name];
4163
-
4164
- if (typeof method !== 'function') {
4165
- DebugManager$2.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
4166
- continue;
4167
- }
4168
-
4169
- this[name] = method.bind(this);
4170
- }
4171
-
4172
- return this;
4173
- };
4174
-
4175
- /**
4176
- * Extends the NDElement prototype with new methods available to all NDElement instances.
4177
- * Use this to add global methods to all NDElements.
4178
- *
4179
- * @param {Object} methods - Object containing method definitions to add to prototype
4180
- * @returns {typeof NDElement} The NDElement constructor
4181
- * @throws {NativeDocumentError} If methods is not an object or contains non-function values
4182
- * @example
4183
- * NDElement.extend({
4184
- * fadeIn() {
4185
- * this.$element.style.opacity = '1';
4186
- * return this;
4187
- * }
4188
- * });
4189
- * // Now all NDElements have .fadeIn() method
4190
- * Div().nd.fadeIn();
4191
- */
4192
- NDElement.extend = function(methods) {
4193
- if (!methods || typeof methods !== 'object') {
4194
- throw new NativeDocumentError('NDElement.extend() requires an object of methods');
4195
- }
4196
-
4197
- if (Array.isArray(methods)) {
4198
- throw new NativeDocumentError('NDElement.extend() requires an object, not an array');
4199
- }
4200
-
4201
- const protectedMethods = new Set([
4202
- 'constructor', 'valueOf', '$element', '$observer',
4203
- 'ref', 'remove', 'cleanup', 'with', 'extend', 'attach',
4204
- 'lifecycle', 'mounted', 'unmounted', 'unmountChildren'
4205
- ]);
4206
-
4207
- for (const name in methods) {
4208
- if (!Object.hasOwn(methods, name)) {
4209
- continue;
4210
- }
4211
-
4212
- const method = methods[name];
4213
-
4214
- if (typeof method !== 'function') {
4215
- DebugManager$2.warn('NDElement.extend', `"${name}" is not a function, skipping`);
4216
- continue;
4217
- }
4218
-
4219
- if (protectedMethods.has(name)) {
4220
- DebugManager$2.error('NDElement.extend', `Cannot override protected method "${name}"`);
4221
- throw new NativeDocumentError(`Cannot override protected method "${name}"`);
4222
- }
4223
-
4224
- if (NDElement.prototype[name]) {
4225
- DebugManager$2.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
4226
- }
4227
-
4228
- NDElement.prototype[name] = method;
4229
- }
4230
-
4231
- return NDElement;
4232
- };
4233
-
4234
- const COMMON_NODE_TYPES = {
4235
- ELEMENT: 1,
4236
- TEXT: 3,
4237
- COMMENT: 8,
4238
- DOCUMENT_FRAGMENT: 11
4239
- };
4240
-
4241
- const VALID_TYPES = [];
4242
- VALID_TYPES[COMMON_NODE_TYPES.ELEMENT] = true;
4243
- VALID_TYPES[COMMON_NODE_TYPES.TEXT] = true;
4244
- VALID_TYPES[COMMON_NODE_TYPES.DOCUMENT_FRAGMENT] = true;
4245
- VALID_TYPES[COMMON_NODE_TYPES.COMMENT] = true;
4246
-
4247
- const Validator = {
4248
- isObservable(value) {
4249
- return value && (value.__$isObservable || value.__$Observable);
4250
- },
4251
- isTemplateBinding(value) {
4252
- return value?.__$isTemplateBinding;
4253
- },
4254
- isObservableWhenResult(value) {
4255
- return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
4256
- },
4257
- isArrayObservable(value) {
4258
- return value?.__$isObservableArray;
4259
- },
4260
- isProxy(value) {
4261
- return value?.__isProxy__
4262
- },
4263
- isObservableOrProxy(value) {
4264
- return Validator.isObservable(value) || Validator.isProxy(value);
4265
- },
4266
- isAnchor(value) {
4267
- return value?.__Anchor__
4268
- },
4269
- isObservableChecker(value) {
4270
- return value?.__$isObservableChecker || value instanceof ObservableChecker;
4271
- },
4272
- isArray(value) {
4273
- return Array.isArray(value);
4274
- },
4275
- isString(value) {
4276
- return typeof value === 'string';
4277
- },
4278
- isNumber(value) {
4279
- return typeof value === 'number';
4280
- },
4281
- isBoolean(value) {
4282
- return typeof value === 'boolean';
4283
- },
4284
- isFunction(value) {
4285
- return typeof value === 'function';
4286
- },
4287
- isAsyncFunction(value) {
4288
- return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
4289
- },
4290
- isObject(value) {
4291
- return typeof value === 'object' && value !== null;
4292
- },
4293
- isJson(value) {
4294
- return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
4295
- },
4296
- isElement(value) {
4297
- return value && VALID_TYPES[value.nodeType];
4298
- },
4299
- isDOMNode(value) {
4300
- return VALID_TYPES[value.nodeType];
4301
- },
4302
- isFragment(value) {
4303
- return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
4304
- },
4305
- isStringOrObservable(value) {
4306
- return this.isString(value) || this.isObservable(value);
4307
- },
4308
- isValidChild(child) {
4309
- return child === null ||
4310
- this.isElement(child) ||
4311
- this.isObservable(child) ||
4312
- this.isNDElement(child) ||
4313
- ['string', 'number', 'boolean'].includes(typeof child);
4314
- },
4315
- isNDElement(child) {
4316
- return child?.__$isNDElement || child instanceof NDElement;
4317
- },
4318
- isValidChildren(children) {
4319
- if (!Array.isArray(children)) {
4320
- children = [children];
4321
- }
4322
-
4323
- const invalid = children.filter(child => !this.isValidChild(child));
4324
- return invalid.length === 0;
4325
- },
4326
- validateChildren(children) {
4327
- if (!Array.isArray(children)) {
4328
- children = [children];
4329
- }
4330
-
4331
- const invalid = children.filter(child => !this.isValidChild(child));
4332
- if (invalid.length > 0) {
4333
- throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
4334
- }
4335
-
4336
- return children;
4337
- },
4338
- /**
4339
- * Check if the data contains observables.
4340
- * @param {Array|Object} data
4341
- * @returns {boolean}
4342
- */
4343
- containsObservables(data) {
4344
- if(!data) {
4345
- return false;
4346
- }
4347
- return Validator.isObject(data)
4348
- && Object.values(data).some(value => Validator.isObservable(value));
4349
- },
4350
- /**
4351
- * Check if the data contains an observable reference.
4352
- * @param {string} data
4353
- * @returns {boolean}
4354
- */
4355
- containsObservableReference(data) {
4356
- if(!data || typeof data !== 'string') {
4357
- return false;
4358
- }
4359
- return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
4360
- },
4361
- validateAttributes(attributes) {},
4362
-
4363
- validateEventCallback(callback) {
4364
- if (typeof callback !== 'function') {
4365
- throw new NativeDocumentError('Event callback must be a function');
4366
- }
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 }
4367
2733
  }
2734
+ return { props, children };
4368
2735
  };
4369
2736
 
4370
- function createMultiSourceFilter(sources, callbackFn){
4371
- const observables = sources.filter(Validator.isObservable);
4372
-
4373
- const getValues = () => sources.map(src =>
4374
- Validator.isObservable(src) ? src.val() : src
4375
- );
2737
+ const createHtmlElement = (element, _attributes, _children = null) => {
2738
+ let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
4376
2739
 
4377
- return {
4378
- dependencies: observables.length > 0 ? observables : null,
4379
- callback: (value) => callbackFn(value, getValues())
4380
- };
4381
- }
2740
+ ElementCreator.processAttributes(element, attributes);
2741
+ ElementCreator.processChildren(children, element);
2742
+ return element;
2743
+ };
4382
2744
 
4383
- function match(patternObservableOrValue, asRegexObservableOrValue = true, flagsObservableOrValue = ''){
4384
- return createMultiSourceFilter(
4385
- [patternObservableOrValue, asRegexObservableOrValue, flagsObservableOrValue],
4386
- (value, [pattern, asRegex, flags]) => {
4387
- if (!pattern) return true;
4388
-
4389
- if (asRegex){
4390
- try {
4391
- const regex = new RegExp(pattern, flags);
4392
- return regex.test(String(value));
4393
- } catch (error){
4394
- DebugManager$2.warn('Invalid regex pattern:', pattern, error);
4395
- return false;
4396
- }
4397
- }
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); };
4398
2761
 
4399
- if (!flags || flags === ''){
4400
- return String(value).toLowerCase().includes(String(pattern).toLowerCase());
4401
- }
4402
- return String(value).includes(String(pattern));
2762
+ return (attr, children) => createElement(attr, children)
4403
2763
  }
4404
- );
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
+ };
4405
2781
  }
4406
2782
 
2783
+ /**
2784
+ * Creates a `<div>` element.
2785
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
2786
+ */
2787
+ const Div = HtmlElementWrapper('div');
2788
+
4407
2789
  /**
4408
2790
  *
4409
2791
  * @class
@@ -5303,252 +3685,89 @@ var NativeComponents = (function (exports) {
5303
3685
  * @returns {Alert}
5304
3686
  */
5305
3687
  Alert.prototype.icon = function(icon) {
5306
- this.$description.icon = icon;
5307
- return this;
5308
- };
5309
-
5310
- /**
5311
- * Shows or hides the icon
5312
- * @param {boolean} [show=true] - Whether to show the icon
5313
- * @returns {Alert}
5314
- */
5315
- Alert.prototype.showIcon = function(show = true) {
5316
- this.$description.showIcon = show;
5317
- };
5318
-
5319
- /**
5320
- * Sets whether the alert can be closed
5321
- * @param {boolean} [closable=true] - Whether the alert is closable
5322
- * @returns {Alert}
5323
- */
5324
- Alert.prototype.closable = function(closable = true) {
5325
- this.$description.closable = !!closable;
5326
- if(closable) {
5327
- this.showIf(closable);
5328
- }
5329
- return this;
5330
- };
5331
-
5332
- /**
5333
- * Sets whether the alert is dismissible (alias for closable)
5334
- * @param {boolean} [dismissible=true] - Whether the alert is dismissible
5335
- * @returns {Alert}
5336
- */
5337
- Alert.prototype.dismissible = function(dismissible = true) {
5338
- return this.closable(dismissible);
5339
- };
5340
-
5341
- /**
5342
- * Sets auto-dismiss delay for the alert
5343
- * @param {number} delay - Delay in milliseconds before auto-dismissing
5344
- * @returns {Alert}
5345
- */
5346
- Alert.prototype.autoDismiss = function(delay) {
5347
- this.$description.autoDismiss = delay;
5348
- return this;
5349
- };
5350
-
5351
- /**
5352
- * Closes the alert
5353
- */
5354
- Alert.prototype.close = function() {
5355
- this.$description.showIf?.set(false);
5356
- this.emit('hide');
5357
- };
5358
-
5359
- /**
5360
- * Shows the alert
5361
- */
5362
- Alert.prototype.show = function() {
5363
- this.$description.showIf?.set(true);
5364
- this.emit('show');
5365
- };
5366
-
5367
- /**
5368
- * Hides the alert
5369
- */
5370
- Alert.prototype.hide = Alert.prototype.close;
5371
-
5372
- /**
5373
- * Registers a handler for the close event
5374
- * @param {(element: Alert) => void} handler - The event handler
5375
- * @returns {Alert}
5376
- */
5377
- Alert.prototype.onClose = function(handler) {
5378
- this.on('close', handler);
5379
- return this;
5380
- };
5381
-
5382
- /**
5383
- * Registers a handler for the show event
5384
- * @param {(element: Alert) => void} handler - The event handler
5385
- * @returns {Alert}
5386
- */
5387
- Alert.prototype.onShow = function(handler) {
5388
- this.on('show', handler);
5389
- return this;
5390
- };
5391
-
5392
- function Button(label, props = {}) {
5393
- if(!(this instanceof Button)) {
5394
- return new Button(label, props);
5395
- }
5396
-
5397
- BaseComponent.call(this, props);
5398
-
5399
- this.$description = {
5400
- label: label,
5401
- type: null,
5402
- variant: null,
5403
- size: null,
5404
- icon: null,
5405
- iconPosition: 'left',
5406
- loading: null,
5407
- disabled: null,
5408
- template: null,
5409
- block: null,
5410
- borderRadiusType: null,
5411
- outline: null,
5412
- props
5413
- };
5414
-
5415
- this.$element = null;
5416
- }
5417
-
5418
- Button.defaultTemplate = null;
5419
-
5420
- Button.use = function(template = {}) {
5421
- Button.defaultTemplate = template;
5422
- };
5423
-
5424
- BaseComponent.extends(Button);
5425
-
5426
- Button.preset = function(name, callback) {
5427
- if (Button.prototype[name] || Button[name]) {
5428
- DebugManager$2.warn(`Warning: the ${name} method already exist in Button.`);
5429
- return;
5430
- }
5431
- Button[name] = (label, props) => callback(new Button(label, props));
5432
- };
5433
-
5434
- Button.presets = function(presets) {
5435
- for (const name in presets) {
5436
- Button.preset(name, presets[name]);
5437
- }
5438
- };
5439
-
5440
- Button.prototype.type = function(type) {
5441
- this.$description.type = type;
5442
- return this;
5443
- };
5444
-
5445
- Button.prototype.variant = function(variant) {
5446
- this.$description.variant = variant;
5447
- return this;
5448
- };
5449
- Button.prototype.primary = function() {
5450
- return this.variant('primary');
5451
- };
5452
- Button.prototype.secondary = function() {
5453
- return this.variant('secondary');
5454
- };
5455
- Button.prototype.danger = function() {
5456
- return this.variant('danger');
5457
- };
5458
- Button.prototype.success = function() {
5459
- return this.variant('success');
5460
- };
5461
- Button.prototype.warning = function() {
5462
- return this.variant('warning');
5463
- };
5464
- Button.prototype.ghost = function() {
5465
- return this.variant('ghost');
5466
- };
5467
- Button.prototype.link = function() {
5468
- return this.variant('link');
5469
- };
5470
- Button.prototype.outline = function() {
5471
- this.$description.outline = true;
5472
- return this;
5473
- };
5474
-
5475
- Button.prototype.size = function(size) {
5476
- this.$description.size = size;
5477
- return this;
5478
- };
5479
- Button.prototype.small = function() {
5480
- return this.size('small');
5481
- };
5482
- Button.prototype.large = function() {
5483
- return this.size('large');
5484
- };
5485
- Button.prototype.medium = function() {
5486
- return this.size('medium');
5487
- };
5488
-
5489
- Button.prototype.icon = function(icon, iconPosition = 'leading') {
5490
- this.$description.icon = icon;
5491
- this.$description.iconPosition = iconPosition;
5492
- return this;
5493
- };
5494
-
5495
- Button.prototype.iconAtLeading = function() {
5496
- this.$description.iconPosition = 'leading';
5497
- return this;
5498
- };
5499
-
5500
- Button.prototype.iconAtTrailing = function() {
5501
- this.$description.iconPosition = 'trailing';
5502
- return this;
5503
- };
5504
- Button.prototype.iconAtTop = function() {
5505
- this.$description.iconPosition = 'top';
3688
+ this.$description.icon = icon;
5506
3689
  return this;
5507
3690
  };
5508
3691
 
5509
- Button.prototype.iconAtBottom = function() {
5510
- this.$description.iconPosition = 'bottom';
5511
- 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;
5512
3699
  };
5513
3700
 
5514
- Button.prototype.iconOnly = function() {
5515
- 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
+ }
5516
3711
  return this;
5517
3712
  };
5518
3713
 
5519
- Button.prototype.loading = function(loading = true) {
5520
- this.$description.loading = BaseComponent.obs(loading);
5521
- 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);
5522
3721
  };
5523
3722
 
5524
- Button.prototype.disabled = function(disabled = true) {
5525
- 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;
5526
3730
  return this;
5527
3731
  };
5528
3732
 
5529
- Button.prototype.render = function(renderFunction) {
5530
- this.$description.render = renderFunction;
5531
- return this;
3733
+ /**
3734
+ * Closes the alert
3735
+ */
3736
+ Alert.prototype.close = function() {
3737
+ this.$description.showIf?.set(false);
3738
+ this.emit('hide');
5532
3739
  };
5533
3740
 
5534
- Button.prototype.rounded = function() {
5535
- this.$description.borderRadiusType = 'rounded';
5536
- return this;
5537
- };
5538
- Button.prototype.pill = function() {
5539
- this.$description.borderRadiusType = 'pill';
5540
- return this;
5541
- };
5542
- Button.prototype.circle = function() {
5543
- this.$description.borderRadiusType = 'circle';
5544
- return this;
3741
+ /**
3742
+ * Shows the alert
3743
+ */
3744
+ Alert.prototype.show = function() {
3745
+ this.$description.showIf?.set(true);
3746
+ this.emit('show');
5545
3747
  };
5546
- Button.prototype.smooth = function() {
5547
- 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);
5548
3761
  return this;
5549
3762
  };
5550
- Button.prototype.block = function() {
5551
- 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);
5552
3771
  return this;
5553
3772
  };
5554
3773
 
@@ -6188,6 +4407,169 @@ var NativeComponents = (function (exports) {
6188
4407
  return this;
6189
4408
  };
6190
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
+
6191
4573
  function Card(config = {}) {
6192
4574
  if(!(this instanceof Card)) {
6193
4575
  return new Card(config);
@@ -8583,10 +6965,10 @@ var NativeComponents = (function (exports) {
8583
6965
  errorsPosition: 'bottom',
8584
6966
  errorsMapper: null,
8585
6967
  renderErrors: null,
8586
- submitting: Observable(false),
8587
- errors: Observable(null),
8588
- isDirty: Observable(false),
8589
- isValid: Observable(false),
6968
+ submitting: $$1(false),
6969
+ errors: $$1(null),
6970
+ isDirty: $$1(false),
6971
+ isValid: $$1(false),
8590
6972
  props
8591
6973
  };
8592
6974
  }
@@ -8628,7 +7010,7 @@ var NativeComponents = (function (exports) {
8628
7010
  dirties.push(field.$description.isDirty);
8629
7011
  }
8630
7012
 
8631
- Observable.computed(() => {
7013
+ $$1.computed(() => {
8632
7014
  const isDirty = dirties.some((item) => item.val());
8633
7015
  this.$description.isDirty.set(isDirty);
8634
7016
  }, dirties);