native-document 1.0.169 → 1.0.173

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 (134) hide show
  1. package/CHANGELOG.md +100 -2
  2. package/docs/vitepress-conventions.md +2 -2
  3. package/index.d.ts +1 -1
  4. package/package.json +11 -4
  5. package/src/components/BaseComponent.js +43 -1
  6. package/src/components/accordion/Accordion.js +1 -0
  7. package/src/components/accordion/AccordionItem.js +1 -0
  8. package/src/components/alert/Alert.js +4 -0
  9. package/src/components/avatar/Avatar.js +1 -0
  10. package/src/components/avatar/AvatarGroup.js +1 -0
  11. package/src/components/badge/Badge.js +1 -0
  12. package/src/components/breadcrumb/BreadCrumb.js +4 -0
  13. package/src/components/button/Button.js +1 -0
  14. package/src/components/card/Card.js +1 -0
  15. package/src/components/context-menu/ContextMenu.js +2 -0
  16. package/src/components/context-menu/ContextMenuGroup.js +2 -0
  17. package/src/components/context-menu/ContextMenuItem.js +2 -0
  18. package/src/components/divider/Divider.js +2 -0
  19. package/src/components/dropdown/Dropdown.js +1 -0
  20. package/src/components/dropdown/DropdownDivider.js +1 -0
  21. package/src/components/dropdown/DropdownGroup.js +1 -0
  22. package/src/components/dropdown/DropdownItem.js +1 -0
  23. package/src/components/dropdown/DropdownTrigger.js +1 -0
  24. package/src/components/form/FormControl.js +1 -0
  25. package/src/components/form/field/Field.js +1 -0
  26. package/src/components/form/field/types/StringField.js +1 -1
  27. package/src/components/icon/Icon.js +1 -0
  28. package/src/components/list/ListItem.js +1 -0
  29. package/src/components/menu/Menu.js +3 -0
  30. package/src/components/menu/MenuDivider.js +1 -0
  31. package/src/components/menu/MenuGroup.js +1 -0
  32. package/src/components/menu/MenuItem.js +1 -0
  33. package/src/components/menu/MenuLink.js +1 -0
  34. package/src/components/modal/Modal.js +4 -0
  35. package/src/components/pagination/Pagination.js +1 -0
  36. package/src/components/popover/Popover.js +1 -0
  37. package/src/components/popover/PopoverFooter.js +1 -0
  38. package/src/components/popover/PopoverHeader.js +1 -0
  39. package/src/components/progress/Progress.js +5 -0
  40. package/src/components/skeleton/Skeleton.js +4 -0
  41. package/src/components/slider/Slider.js +1 -0
  42. package/src/components/spacer/Spacer.js +1 -0
  43. package/src/components/spinner/Spinner.js +1 -0
  44. package/src/components/splitter/Splitter.js +1 -0
  45. package/src/components/splitter/SplitterGutter.js +6 -0
  46. package/src/components/splitter/SplitterPanel.js +1 -0
  47. package/src/components/stacks/AbsoluteStack.js +1 -0
  48. package/src/components/stacks/FixedStack.js +1 -0
  49. package/src/components/stacks/HStack.js +1 -0
  50. package/src/components/stacks/PositionStack.js +1 -0
  51. package/src/components/stacks/RelativeStack.js +1 -0
  52. package/src/components/stacks/Stack.js +1 -0
  53. package/src/components/stacks/VStack.js +1 -0
  54. package/src/components/stepper/Stepper.js +1 -0
  55. package/src/components/stepper/StepperStep.js +1 -0
  56. package/src/components/switch/Switch.js +1 -0
  57. package/src/components/table/DataTable.js +1 -0
  58. package/src/components/table/SimpleTable.js +1 -0
  59. package/src/components/tabs/Tabs.js +1 -0
  60. package/src/components/toast/Toast.js +1 -0
  61. package/src/components/tooltip/Tooltip.js +1 -0
  62. package/src/core/data/MemoryManager.js +6 -1
  63. package/src/core/data/ObservableItem.js +33 -15
  64. package/src/core/data/ObservableObject.js +1 -2
  65. package/src/core/elements/anchor/anchor.js +4 -3
  66. package/src/core/elements/anchor/one-child-anchor-overwriting.js +4 -4
  67. package/src/core/elements/content-formatter.js +19 -0
  68. package/src/core/elements/control/for-each-array-cache.js +59 -0
  69. package/src/core/elements/control/for-each-array.js +15 -23
  70. package/src/core/wrappers/AttributesWrapper.js +12 -12
  71. package/src/core/wrappers/ElementCreator.js +33 -10
  72. package/src/core/wrappers/HtmlElementWrapper.js +17 -13
  73. package/src/core/wrappers/NDElement.js +23 -8
  74. package/src/core/wrappers/NdPrototype.js +64 -39
  75. package/src/core/wrappers/constants.js +12 -12
  76. package/src/core/wrappers/prototypes/nd-element-extensions.js +127 -57
  77. package/src/core/wrappers/template-cloner/NodeCloner.js +10 -6
  78. package/src/core/wrappers/template-cloner/TemplateCloner.js +7 -4
  79. package/src/fetch/NativeFetch.js +1 -0
  80. package/src/ui/components/accordion/AccordionItemRender.js +29 -7
  81. package/src/ui/components/alert/AlertRender.js +6 -0
  82. package/src/ui/components/breadcrumb/BreadcrumbRender.js +9 -1
  83. package/src/ui/components/button/ButtonRender.js +3 -0
  84. package/src/ui/components/contextmenu/ContextmenuRender.js +2 -0
  85. package/src/ui/components/dropdown/DropdownRender.js +3 -0
  86. package/src/ui/components/dropdown/item/DropdownItemRender.js +6 -1
  87. package/src/ui/components/form/FieldCollectionRender.js +4 -0
  88. package/src/ui/components/form/fields/CheckboxFieldRender.js +4 -0
  89. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +4 -0
  90. package/src/ui/components/form/fields/FieldRender.js +1 -1
  91. package/src/ui/components/form/fields/RadioFieldRender.js +4 -0
  92. package/src/ui/components/form/fields/RangeFieldRender.js +4 -0
  93. package/src/ui/components/form/fields/SelectFieldRender.js +5 -0
  94. package/src/ui/components/form/fields/SliderFieldRender.js +3 -0
  95. package/src/ui/components/icon/tabler/TablerIconRender.js +0 -1
  96. package/src/ui/components/list/item/ListItemRender.js +4 -0
  97. package/src/ui/components/menu/MenuItemRender.js +8 -0
  98. package/src/ui/components/menu/MenuLinkRender.js +11 -0
  99. package/src/ui/components/menu/MenuRender.js +5 -0
  100. package/src/ui/components/menu/helpers.js +2 -1
  101. package/src/ui/components/modal/ModalRender.js +8 -2
  102. package/src/ui/components/progress/ProgressRender.js +9 -0
  103. package/src/ui/components/skeleton/SkeletonRender.js +2 -0
  104. package/src/ui/components/spinner/SpinnerRender.js +3 -0
  105. package/src/ui/components/splitter/SplitterGutterRender.js +4 -0
  106. package/src/ui/components/splitter/SplitterPanelRender.js +4 -0
  107. package/src/ui/components/splitter/SplitterRender.js +2 -0
  108. package/src/ui/components/stepper/StepperRender.js +2 -1
  109. package/src/ui/components/stepper/StepperStepRender.js +8 -1
  110. package/src/ui/components/switch/SwitchRender.js +3 -0
  111. package/src/ui/components/table/data-table/DataTableRender.js +4 -0
  112. package/src/ui/components/table/simple-table/SimpleTableRender.js +2 -0
  113. package/src/ui/components/toast/ToastRender.js +4 -0
  114. package/src/ui/utils/aria.js +19 -0
  115. package/tests/integration/ui/attributes-wrapper.test.js +177 -0
  116. package/tests/integration/ui/for-each-array.test.js +167 -0
  117. package/tests/integration/ui/lifecycle.test.js +146 -0
  118. package/tests/integration/ui/show-if.test.js +168 -0
  119. package/tests/unit/core/observable-array.test.js +404 -0
  120. package/tests/unit/core/observable-item.test.js +428 -0
  121. package/tests/unit/core/observable-object.test.js +239 -0
  122. package/tests/unit/core/observable-resource.test.js +323 -0
  123. package/tests/unit/core/store.test.js +347 -0
  124. package/tests/unit/router/route-matching.test.js +169 -0
  125. package/tests/unit/router/router-guards.test.js +189 -0
  126. package/tests/unit/utils/cache.test.js +120 -0
  127. package/tests/unit/utils/filters.test.js +394 -0
  128. package/types/elements.d.ts +5 -0
  129. package/types/native-fetch.d.ts +1 -1
  130. package/types/observable-resource.d.ts +2 -2
  131. package/types/observable.d.ts +137 -21
  132. package/types/service.d.ts +2 -1
  133. package/utils.js +7 -4
  134. package/vitest.config.js +15 -0
@@ -1,4 +1,3 @@
1
- import Validator from '../utils/validator';
2
1
  import AttributesWrapper, { bindClassAttribute, bindStyleAttribute } from './AttributesWrapper';
3
2
  import PluginsManager from '../utils/plugins-manager';
4
3
 
@@ -8,7 +7,7 @@ export const ElementCreator = {
8
7
  createTextNode() {
9
8
  if(!$textNodeCache) {
10
9
  $textNodeCache = document.createTextNode('');
11
- ElementCreator.createTextNode = () => $textNodeCache.cloneNode();
10
+ ElementCreator.createTextNode = $textNodeCache.cloneNode.bind($textNodeCache);
12
11
  }
13
12
  return $textNodeCache.cloneNode();
14
13
  },
@@ -19,10 +18,19 @@ export const ElementCreator = {
19
18
  * @returns {Text}
20
19
  */
21
20
  createObservableNode: (parent, observable) => {
21
+ const text = ElementCreator.createObservableNodeWithoutParent(observable);
22
+ parent && parent.appendChild(text);
23
+ return text;
24
+ },
25
+ /**
26
+ *
27
+ * @param {ObservableItem} observable
28
+ * @returns {Text}
29
+ */
30
+ createObservableNodeWithoutParent: (observable) => {
22
31
  const text = ElementCreator.createTextNode();
23
32
  observable.subscribe(value => text.nodeValue = value);
24
33
  text.nodeValue = observable.val();
25
- parent && parent.appendChild(text);
26
34
  return text;
27
35
  },
28
36
  /**
@@ -49,6 +57,11 @@ export const ElementCreator = {
49
57
  parent && parent.appendChild(text);
50
58
  return text;
51
59
  },
60
+ createStaticTextNodeWithoutParent: (value) => {
61
+ const text = ElementCreator.createTextNode();
62
+ text.nodeValue = value;
63
+ return text;
64
+ },
52
65
  /**
53
66
  *
54
67
  * @param {string} name
@@ -72,27 +85,37 @@ export const ElementCreator = {
72
85
  * @param {HTMLElement|DocumentFragment} parent
73
86
  */
74
87
  processChildren: (children, parent) => {
75
- if(children === null) return;
76
88
  if(process.env.NODE_ENV === 'development') {
77
89
  PluginsManager.emit('BeforeProcessChildren', parent);
78
90
  }
79
- const child = ElementCreator.getChild(children);
80
- if(child) {
81
- parent.appendChild(child);
91
+ if(Array.isArray(children)) {
92
+ for(let i = 0, length = children.length; i < length; i++) {
93
+ const child = ElementCreator.getChild(children[i]);
94
+ if(child === null) {
95
+ continue;
96
+ }
97
+ parent.appendChild(child);
98
+ }
99
+ return;
82
100
  }
101
+ const child = ElementCreator.getChild(children);
102
+ parent.appendChild(child);
83
103
  if(process.env.NODE_ENV === 'development') {
84
104
  PluginsManager.emit('AfterProcessChildren', parent);
85
105
  }
86
106
  },
87
107
  async safeRemove(element) {
88
108
  await element.remove();
89
-
90
109
  },
91
110
  getChild: (child) => {
92
- if (child == null) return null;
111
+ if (child == null) {
112
+ return null;
113
+ }
93
114
 
94
115
  child = child.toNdElement();
95
- if (child instanceof Node) return child;
116
+ if (child && (child instanceof Node)) {
117
+ return child;
118
+ }
96
119
 
97
120
  while (child != null && !(child instanceof Node)) {
98
121
  child = child.toNdElement?.();
@@ -1,6 +1,5 @@
1
1
  import Anchor from '../elements/anchor/anchor';
2
2
  import {ElementCreator} from './ElementCreator';
3
- import {normalizeComponentArgs} from '../utils/args-types';
4
3
  import './NdPrototype';
5
4
 
6
5
  import '../../core/utils/prototypes.js';
@@ -19,7 +18,7 @@ import '../wrappers/prototypes/attributes-extensions';
19
18
  * @returns {Text} Text node, reactive if value is an ObservableItem
20
19
  */
21
20
  export const createTextNode = (value) => {
22
- if(value) {
21
+ if(value != null) {
23
22
  return value.toNdElement();
24
23
  }
25
24
  return ElementCreator.createTextNode();
@@ -36,10 +35,11 @@ export const createTextNode = (value) => {
36
35
  * @returns {HTMLElement} The configured element
37
36
  */
38
37
  export const createVoidHtmlElement = (element, attributes) => {
39
- ElementCreator.processAttributes(element, attributes);
38
+ attributes && ElementCreator.processAttributes(element, attributes);
40
39
  return element;
41
40
  };
42
41
 
42
+
43
43
  const OBJECT_PROTOTYPE = Object.prototype;
44
44
  /**
45
45
  * Applies attributes and children to an existing HTMLElement.
@@ -53,13 +53,18 @@ const OBJECT_PROTOTYPE = Object.prototype;
53
53
  */
54
54
  export const createHtmlElement = (element, _attributes, _children = null) => {
55
55
  let attributes = _attributes, children = _children;
56
- if((!_attributes || !_children) && (typeof _attributes !== 'object' || Array.isArray(_attributes) || _attributes === null || Object.getPrototypeOf(_attributes) !== OBJECT_PROTOTYPE || _attributes.$hydrate)) { // IF it's not a JSON
56
+ if(_attributes?.__$isValidNdChild) { // If attributes is a ValidChild
57
57
  attributes = _children;
58
58
  children = _attributes;
59
59
  }
60
+ element = element.cloneNode();
60
61
 
61
- ElementCreator.processAttributes(element, attributes);
62
- ElementCreator.processChildren(children, element);
62
+ if(attributes != null) {
63
+ ElementCreator.processAttributes(element, attributes);
64
+ }
65
+ if(children != null) {
66
+ ElementCreator.processChildren(children, element);
67
+ }
63
68
  return element;
64
69
  };
65
70
 
@@ -70,6 +75,7 @@ export const createHtmlElement = (element, _attributes, _children = null) => {
70
75
  *
71
76
  * @param {string} name - HTML tag name (e.g. 'div', 'button', 'input'). Pass empty string to create a Fragment.
72
77
  * @param {((element: HTMLElement) => HTMLElement)|null} [customWrapper=null] - Optional function to augment the element before returning
78
+ * @param {boolean} [isVoid=false] - If true, the element is a void element (no children allowed, e.g. input, img)
73
79
  * @returns {(attr?: Object, children?: ValidChild) => HTMLElement} Element factory function
74
80
  * @example
75
81
  * const Div = HtmlElementWrapper('div');
@@ -84,14 +90,12 @@ export const createHtmlElement = (element, _attributes, _children = null) => {
84
90
  export default function HtmlElementWrapper(name, customWrapper = null, isVoid = false) {
85
91
  const elementCreator = isVoid ? createVoidHtmlElement : createHtmlElement;
86
92
  if(name) {
87
- if(customWrapper) {
93
+ if(customWrapper == null) {
88
94
  let node = null;
89
95
  let createElement = (attr, children) => {
90
96
  node = document.createElement(name);
91
- createElement = (attr, children) => {
92
- return elementCreator(customWrapper(node.cloneNode()), attr, children);
93
- };
94
- return elementCreator(customWrapper(node.cloneNode()), attr, children);;
97
+ createElement = elementCreator.bind(null, node);
98
+ return elementCreator(node.cloneNode(), attr, children);
95
99
  };
96
100
 
97
101
  return (attr, children) => createElement(attr, children);
@@ -101,9 +105,9 @@ export default function HtmlElementWrapper(name, customWrapper = null, isVoid =
101
105
  let createElement = (attr, children) => {
102
106
  node = document.createElement(name);
103
107
  createElement = (attr, children) => {
104
- return elementCreator(node.cloneNode(), attr, children);
108
+ return elementCreator(customWrapper(node.cloneNode()), attr, children);
105
109
  };
106
- return elementCreator(node.cloneNode(), attr, children);
110
+ return elementCreator(customWrapper(node.cloneNode()), attr, children);;
107
111
  };
108
112
 
109
113
  return (attr, children) => createElement(attr, children);
@@ -187,16 +187,32 @@ NDElement.prototype.destroyOnUnmount = function() {
187
187
  * @returns {this}
188
188
  */
189
189
  NDElement.prototype.destroy = function() {
190
- this.$element?.querySelectorAll('[data--nd-before-unmount]').forEach(child => {
190
+ if(!this.$element) {
191
+ return this;
192
+ }
193
+ const observer = $lifeCycleObservers.get(this.$element);
194
+ if(observer) {
195
+ observer.disconnect();
196
+ }
197
+
198
+ const treewalk = document.createTreeWalker(this.$element, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
199
+ const nodes = [];
200
+ while(treewalk.nextNode()) {
201
+ nodes.push(treewalk.currentNode);
202
+ }
203
+
204
+ for(let i = 0, length = nodes.length; i < length; i++) {
205
+ const child = nodes[i];
191
206
  child.remove();
192
- child.__$controller?.abort();
193
- child.__$controller = null;
207
+ const childObserver = $lifeCycleObservers.get(child);
208
+ if(childObserver) {
209
+ childObserver.disconnect();
210
+ }
194
211
  $lifeCycleObservers.delete(child);
195
- });
212
+ }
196
213
 
197
- this.$element.__$controller?.abort();
198
- this.$element.__$controller = null;
199
214
  $lifeCycleObservers.delete(this.$element);
215
+ this.$element.remove();
200
216
  this.$element = null;
201
217
  };
202
218
 
@@ -418,7 +434,6 @@ NDElement.prototype.style = function(style) {
418
434
  return this;
419
435
  };
420
436
 
421
-
422
437
  /**
423
438
  * Extends the NDElement prototype with new methods available to all NDElement instances.
424
439
  * Use this to add global methods to all NDElements.
@@ -618,7 +633,7 @@ NDElement.prototype.contentEditable = function($obs, {format = 'html'} = {}) {
618
633
 
619
634
  this.$element.addEventListener('input', () => {
620
635
  $obs?.set(getValue());
621
- }, { signal: this.$getSignal() });
636
+ });
622
637
 
623
638
  return this;
624
639
  };
@@ -20,64 +20,74 @@ Object.defineProperty(NDElement.prototype, 'nd', {
20
20
  });
21
21
 
22
22
 
23
-
24
23
  // ----------------------------------------------------------------
25
24
  // Events helpers
26
25
  // ----------------------------------------------------------------
27
26
  EVENTS.forEach(eventSourceName => {
28
27
  const eventName = eventSourceName.toLowerCase();
29
- NDElement.prototype['on'+eventSourceName] = function(callback = null, options = {}) {
30
- this.$element.addEventListener(eventName, callback, {
31
- signal: this.$getSignal(),
32
- ...options,
33
- });
28
+ const inlineHandler = 'on'+eventName;
29
+ const fnName = 'on'+eventSourceName;
30
+ NDElement.prototype[fnName] = function(callback = null, options = null) {
31
+ if(!this.$element[inlineHandler] && !options) {
32
+ this.$element[inlineHandler] = callback;
33
+ return this;
34
+ }
35
+ this.$element.addEventListener(eventName, callback, options);
34
36
  return this;
35
37
  };
38
+ if(!HTMLElement.prototype[fnName]) {
39
+ HTMLElement.prototype[fnName] = function(callback, options) {
40
+ if(!this[inlineHandler] && !options) {
41
+ this[inlineHandler] = callback;
42
+ return this;
43
+ }
44
+ this.addEventListener(eventName, callback, options);
45
+ return this;
46
+ }
47
+ }
36
48
  });
37
49
 
38
50
  EVENTS_WITH_STOP.forEach(eventSourceName => {
39
51
  const eventName = eventSourceName.toLowerCase();
40
- NDElement.prototype['onStop'+eventSourceName] = function(callback = null, options = {}) {
41
- _stop(this.$element, eventName, callback, {
42
- signal: this.$getSignal(),
43
- ...options,
44
- });
52
+ const stopFnName = 'onStop'+eventSourceName;
53
+ const preventStopFnName = 'onPreventStop'+eventSourceName;
54
+
55
+ NDElement.prototype[stopFnName] = function(callback = null, options = null) {
56
+ _stop(this.$element, eventName, callback, options);
45
57
  return this;
46
58
  };
47
- NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null, options = {}) {
48
- _preventStop(this.$element, eventName, callback, {
49
- signal: this.$getSignal(),
50
- ...options,
51
- });
59
+ NDElement.prototype[preventStopFnName] = function(callback = null, options = null) {
60
+ _preventStop(this.$element, eventName, callback, options);
52
61
  return this;
53
62
  };
63
+ if(HTMLElement.prototype[stopFnName]) {
64
+ HTMLElement.prototype[stopFnName] = function(callback = null, options = null) {
65
+ _stop(this, eventName, callback, options);
66
+ return this;
67
+ };
68
+ }
69
+ if(!HTMLElement.prototype[preventStopFnName]) {
70
+ HTMLElement.prototype[preventStopFnName] = function(callback = null, options = null) {
71
+ _preventStop(this, eventName, callback, options);
72
+ return this;
73
+ };
74
+ }
54
75
  });
55
76
 
56
77
  EVENTS_WITH_PREVENT.forEach(eventSourceName => {
57
78
  const eventName = eventSourceName.toLowerCase();
58
- NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null, options = {}) {
59
- _prevent(this.$element, eventName, callback, {
60
- signal: this.$getSignal(),
61
- ...options,
62
- });
79
+ const preventFnName = 'onPrevent'+eventSourceName;
80
+ NDElement.prototype[preventFnName] = function(callback = null, options = null) {
81
+ _prevent(this.$element, eventName, callback, options);
63
82
  return this;
64
83
  };
65
- });
66
-
67
- /**
68
- * Retrieves or creates an AbortController signal tied to this element's lifecycle.
69
- * The signal is automatically aborted when the element is removed via .nd.remove().
70
- * Used internally by all event listeners (onClick, onInput, etc.) to auto-cleanup on unmount.
71
- *
72
- * @internal
73
- * @returns {AbortSignal} The signal for this element's AbortController
74
- */
75
- NDElement.prototype.$getSignal = function() {
76
- if(!this.$element.__$controller) {
77
- this.$element.__$controller = new AbortController();
84
+ if(HTMLElement.prototype[preventFnName]) {
85
+ HTMLElement.prototype[preventFnName] = function(callback = null, options = null) {
86
+ _prevent(this, eventName, callback, options);
87
+ return this;
88
+ };
78
89
  }
79
- return this.$element.__$controller.signal;
80
- };
90
+ });
81
91
 
82
92
 
83
93
  /**
@@ -91,7 +101,6 @@ NDElement.prototype.$getSignal = function() {
91
101
  */
92
102
  NDElement.prototype.on = function(name, callback, options) {
93
103
  this.$element.addEventListener(name.toLowerCase(), callback, {
94
- signal: this.$getSignal(),
95
104
  ...options,
96
105
  });
97
106
  return this;
@@ -119,7 +128,6 @@ NDElement.prototype.off = function(name, callback) {
119
128
  */
120
129
  NDElement.prototype.once = function(name, callback) {
121
130
  this.$element.addEventListener(name.toLowerCase(), callback, {
122
- signal: this.$getSignal(),
123
131
  once: true,
124
132
  });
125
133
  return this;
@@ -151,8 +159,13 @@ const _prevent = function(element, eventName, callback, options) {
151
159
  event.preventDefault();
152
160
  callback && callback.call(element, event);
153
161
  };
162
+
163
+ const inlineHandler = 'on' + eventName;
164
+ if(!element[inlineHandler] && !options) {
165
+ element[inlineHandler] = handler;
166
+ return;
167
+ }
154
168
  element.addEventListener(eventName, handler, options);
155
- return this;
156
169
  };
157
170
 
158
171
  const _stop = function(element, eventName, callback, options) {
@@ -160,6 +173,13 @@ const _stop = function(element, eventName, callback, options) {
160
173
  event.stopPropagation();
161
174
  callback && callback.call(element, event);
162
175
  };
176
+
177
+ const inlineHandler = 'on' + eventName;
178
+ if(!element[inlineHandler] && !options) {
179
+ element[inlineHandler] = handler;
180
+ return;
181
+ }
182
+
163
183
  element.addEventListener(eventName, handler, options);
164
184
  return this;
165
185
  };
@@ -170,6 +190,11 @@ const _preventStop = function(element, eventName, callback, options) {
170
190
  event.preventDefault();
171
191
  callback && callback.call(element, event);
172
192
  };
193
+ const inlineHandler = 'on' + eventName;
194
+ if(!element[inlineHandler] && !options) {
195
+ element[inlineHandler] = handler;
196
+ return;
197
+ }
173
198
  element.addEventListener(eventName, handler, options);
174
199
  return this;
175
200
  };
@@ -3,19 +3,19 @@ export const BOOLEAN_ATTRIBUTES = new Set([
3
3
  'checked',
4
4
  'selected',
5
5
  'disabled',
6
- 'readonly',
6
+ 'readonly', 'readOnly',
7
7
  'required',
8
- 'autofocus',
8
+ 'autofocus', 'autoFocus',
9
9
  'multiple',
10
- 'autocomplete',
10
+ 'autocomplete', 'autoComplete',
11
11
  'hidden',
12
- 'contenteditable',
13
- 'spellcheck',
12
+ 'contenteditable', 'contentEditable',
13
+ 'spellcheck', 'spellCheck',
14
14
  'translate',
15
15
  'draggable',
16
16
  'async',
17
17
  'defer',
18
- 'autoplay',
18
+ 'autoplay', 'autoPlay',
19
19
  'controls',
20
20
  'loop',
21
21
  'muted',
@@ -23,13 +23,13 @@ export const BOOLEAN_ATTRIBUTES = new Set([
23
23
  'reversed',
24
24
  'open',
25
25
  'default',
26
- 'formnovalidate',
27
- 'novalidate',
26
+ 'formnovalidate', 'formNoValidate',
27
+ 'novalidate', 'noValidate',
28
28
  'scoped',
29
- 'itemscope',
30
- 'allowfullscreen',
31
- 'allowpaymentrequest',
32
- 'playsinline',
29
+ 'itemscope', 'itemScope',
30
+ 'allowfullscreen', 'allowFullscreen',
31
+ 'allowpaymentrequest', 'allowPaymentRequest',
32
+ 'playsinline', 'playsInline',
33
33
  ]);
34
34
 
35
35
  export const BOOL_ATTRIBUTES_NAME = {