native-document 1.0.185 → 1.0.187

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.185",
3
+ "version": "1.0.187",
4
4
  "description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
5
5
  "author": "AfroCodeur <https://github.com/afrocodeur>",
6
6
  "license": "MIT",
package/router.js CHANGED
@@ -7,5 +7,5 @@ import { Link } from './src/router/link.js';
7
7
  export {
8
8
  RouteParamPatterns,
9
9
  Router,
10
- Link
11
- }
10
+ Link,
11
+ };
@@ -123,13 +123,18 @@ Avatar.prototype.alt = function(alt) {
123
123
 
124
124
  /**
125
125
  * Sets the name associated with the avatar
126
- * @param {string} name - The name
126
+ * @param {string|Observable} name - The name
127
127
  * @returns {Avatar}
128
128
  */
129
129
  Avatar.prototype.name = function(name) {
130
130
  this.$description.name = name;
131
131
  if(!this.$description.initials) {
132
- this.$description.initials = name.split(' ').map(n => n[0]).join('');
132
+ if(name.__$Observable) {
133
+ this.$description.initials = name.format((value) => value.split(' ').map(n => n[0]).join(''));
134
+ }
135
+ else {
136
+ this.$description.initials = name.split(' ').map(n => n[0]).join('');
137
+ }
133
138
  }
134
139
  return this;
135
140
  };
@@ -308,7 +308,7 @@ Dropdown.prototype.trigger = function(trigger, includeTriggerIntoGhost = true) {
308
308
  * @returns {this}
309
309
  */
310
310
  Dropdown.prototype.add = function(item, props = {}) {
311
- this.$description.items.push(normalizeDropdownItem(item, null, props));
311
+ this.$description.items.push(normalizeDropdownItem(item, props));
312
312
  return this;
313
313
  };
314
314
 
@@ -36,6 +36,7 @@ export default function DropdownItem(props = {}) {
36
36
  data: null,
37
37
  render: null,
38
38
  renderContent: null,
39
+ action: null,
39
40
  props,
40
41
  };
41
42
  this.aria = { 'role': 'option', 'tabindex': '-1' };
@@ -115,6 +116,14 @@ DropdownItem.prototype.content = function(content) {
115
116
  this.$description.content = content;
116
117
  return this;
117
118
  };
119
+ /**
120
+ * @param {Function} action
121
+ * @returns {this}
122
+ */
123
+ DropdownItem.prototype.action = function(action) {
124
+ this.$description.action = action;
125
+ return this;
126
+ };
118
127
 
119
128
  /**
120
129
  * @param {*} data
@@ -18,6 +18,12 @@ export const normalizeDropdownItem = (raw, mapper = null, props = {}) => {
18
18
  return raw;
19
19
  }
20
20
 
21
+ if(typeof raw === 'function') {
22
+ const item = new DropdownItem({});
23
+ raw(item);
24
+ return item;
25
+ }
26
+
21
27
  let config;
22
28
 
23
29
  if(typeof mapper === 'function') {
@@ -25,6 +25,7 @@ export interface DropdownItemInterface extends BaseComponent {
25
25
  content(content: ValidChild): this;
26
26
  data(data: unknown): this;
27
27
  getData(): unknown;
28
+ action(action: Function): this;
28
29
  shortcut(shortcut: ValidChild): this;
29
30
  render(template: (description: DropdownItemDescription, instance: DropdownItemInterface) => ValidChild): this;
30
31
  renderContent(callback: (item: DropdownItemInterface) => ValidChild): this;
@@ -174,7 +174,12 @@ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations)
174
174
  ObservableItem.prototype.$runAssocTrigger = function() {
175
175
  this.$firstListener = null;
176
176
  if(this.$watchers?.size && this.$listeners?.length) {
177
- this.$trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
177
+ if(this.$listeners.length === 1) {
178
+ this.$firstListener = this.$listeners[0];
179
+ this.$trigger = this.triggerWatchersAndFirstListener;
180
+ } else {
181
+ this.$trigger = this.triggerAll;
182
+ }
178
183
  return;
179
184
  }
180
185
  if(this.$listeners?.length) {
@@ -171,10 +171,10 @@ const AttributesWrapper = (element, attributes = {}) => {
171
171
  element.setAttribute(attributeName, value);
172
172
  continue;
173
173
  }
174
- if(value.$hydrate) {
175
- value.$hydrate(element, attributeName, 'attribute');
176
- continue;
177
- }
174
+ // if(value.$hydrate) {
175
+ // value.$hydrate(element, attributeName, 'attribute');
176
+ // continue;
177
+ // }
178
178
  // const attributeName = originalAttributeName.toLowerCase();
179
179
  if(value.__$Observable) {
180
180
  if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
@@ -199,9 +199,9 @@ const AttributesWrapper = (element, attributes = {}) => {
199
199
  continue;
200
200
  }
201
201
 
202
- // if(value.__$isTemplateBinding) {
203
- // // value.$hydrate(element, attributeName, 'attribute');
204
- // }
202
+ if(value.__$isTemplateBinding) {
203
+ value.$hydrate(element, attributeName, 'attribute');
204
+ }
205
205
 
206
206
  element.setAttribute(attributeName, value);
207
207
  }
@@ -1,7 +1,6 @@
1
1
  import {ElementCreator} from '../ElementCreator';
2
2
  import {createTextNode} from '../HtmlElementWrapper';
3
3
  import {NDElement} from '../NDElement';
4
- import {call} from '@babel/traverse/lib/path/context';
5
4
 
6
5
  /**
7
6
  * Stores deferred attribute, class, style, and event bindings for a cloneable element.
@@ -66,18 +65,15 @@ const getPropertyValue = (callbackOrProperty, data) => {
66
65
  };
67
66
 
68
67
 
69
- const $nodeClonedCallbackData = new WeakMap();
70
-
71
- const $nodeClonerCallbackCaller = (callback, event) => {
72
- const data = $nodeClonedCallbackData.get(event.target);
73
- callback.apply(event.target, [...data, event]);
68
+ const $nodeClonerCallbackCaller = function(callback, event) {
69
+ const data = event.currentTarget.$ndScopeData;
70
+ callback.apply(event.currentTarget, [...data, event]);
74
71
  };
75
72
 
76
73
  NodeCloner.prototype.resolveMethods = function() {
77
74
  for(const methodName in this.$ndMethods) {
78
75
  const callback = this.$ndMethods[methodName];
79
- const uniqueCallback = $nodeClonerCallbackCaller.bind(null, callback);
80
- this.$uniqueCallbacks.set(methodName, uniqueCallback);
76
+ this.$ndMethods[methodName] = $nodeClonerCallbackCaller.bind($nodeClonerCallbackCaller, callback);
81
77
  }
82
78
  };
83
79
  /**
@@ -86,95 +82,108 @@ NodeCloner.prototype.resolveMethods = function() {
86
82
  *
87
83
  * @internal
88
84
  */
89
- NodeCloner.prototype.resolve = function() {
90
- if(this.$content) {
91
- return;
92
- }
93
- this.resolveMethods();
94
- const steps = [];
95
- if(this.$ndMethods) {
96
- const methods = Object.keys(this.$ndMethods);
97
- if(methods.length === 1) {
98
- const methodName = methods[0];
99
- steps.push((clonedNode) => {
100
- const uniqueCallback = this.$uniqueCallbacks.get(methodName);
101
- clonedNode.nd[methodName](uniqueCallback);
102
- });
85
+ NodeCloner.prototype.$cleanResolve = function() {
86
+ const fns = [];
87
+ const fnsParamNames = [];
88
+ const fnsParams = [];
89
+
90
+ const $element = this.$element;
91
+
92
+ if(this.$ndMethods !== null) {
93
+ const methodNames = Object.keys(this.$ndMethods);
94
+ if(methodNames.length === 1) {
95
+ const methodName = methodNames[0];
96
+ const callback = this.$ndMethods[methodName];
97
+ if($element[methodName]) {
98
+ fns.push(`clonedNode.${methodName}(callback)`);
99
+ } else {
100
+ fns.push(`clonedNode.nd.${methodName}(callback)`);
101
+ }
102
+ fnsParamNames.push('callback');
103
+ fnsParams.push(callback);
103
104
  } else {
104
- steps.push((clonedNode) => {
105
- const nd = clonedNode.nd;
106
- for(const methodName in this.$ndMethods) {
107
- const uniqueCallback = this.$uniqueCallbacks.get(methodName);
108
105
 
109
- // callback.length === 0 ? callback : this.$ndMethods[methodName].bind(clonedNode, ...data)
110
- nd[methodName](uniqueCallback);
106
+ for(const methodName in this.$ndMethods) {
107
+ const callbackName = methodName+'Callback';
108
+ const callback = this.$ndMethods[methodName];
109
+ if($element[methodName]) {
110
+ fns.push(`clonedNode.${methodName}(${callbackName})`);
111
+ } else {
112
+ fns.push(`clonedNode.nd.${methodName}(${callbackName})`);
111
113
  }
112
- });
114
+ fnsParamNames.push(callbackName);
115
+ fnsParams.push(callback);
116
+ }
113
117
  }
114
118
  }
115
- if(this.$classes) {
119
+ if(this.$classes !== null) {
116
120
  const cache = {};
117
121
  const keys = Object.keys(this.$classes);
118
122
 
119
123
  if(keys.length === 1) {
120
124
  const key = keys[0];
121
125
  const callback = this.$classes[key];
122
- steps.push((clonedNode, data) => {
123
- cache[key] = getPropertyValue(callback, data);
124
- ElementCreator.processClassAttribute(clonedNode, cache);
125
- });
126
+ fns.push(`ElementCreator.processClassAttribute(clonedNode, { ${key}: getPropertyValue(getPropertyValueCallback, data) })`);
127
+ fnsParamNames.push('getPropertyValueCallback');
128
+ fnsParams.push(callback);
126
129
  } else {
127
- steps.push((clonedNode, data) => {
128
- ElementCreator.processClassAttribute(clonedNode, buildProperties(cache, this.$classes, data));
129
- });
130
+ fns.push(`const classesCache = {}`);
131
+ fns.push(`ElementCreator.processClassAttribute(clonedNode, buildProperties(classesCache, $classes, data))`);
132
+ fnsParamNames.push('$classes');
133
+ fnsParams.push(this.$classes);
130
134
  }
131
135
  }
132
- if(this.$styles) {
136
+ if(this.$styles !== null) {
133
137
  const cache = {};
134
138
  const keys = Object.keys(this.$styles);
135
139
 
136
140
  if(keys.length === 1) {
137
141
  const key = keys[0];
138
142
  const callback = this.$styles[key];
139
- steps.push((clonedNode, data) => {
140
- cache[key] = getPropertyValue(callback, data);
141
- ElementCreator.processStyleAttribute(clonedNode, cache);
142
- });
143
+ fns.push(`ElementCreator.processStyleAttribute(clonedNode, { ${key}: getPropertyValue(getStyleValueCallback, data) } )`);
144
+ fnsParamNames.push('getStyleValueCallback');
145
+ fnsParams.push(callback);
143
146
  } else {
144
- steps.push((clonedNode, data) => {
145
- ElementCreator.processStyleAttribute(clonedNode, buildProperties(cache, this.$styles, data));
146
- });
147
+ fns.push(`const stylesCache = {}`);
148
+ fns.push(`ElementCreator.processStyleAttribute(clonedNode, buildProperties(stylesCache, $styles, data))`);
149
+ fnsParamNames.push('$styles');
150
+ fnsParams.push(this.$styles);
147
151
  }
148
152
  }
149
- if(this.$attrs) {
153
+ if(this.$attrs !== null) {
150
154
  const cache = {};
151
155
  const keys = Object.keys(this.$attrs);
152
156
 
153
157
  if(keys.length === 1) {
154
158
  const key = keys[0];
155
159
  const callback = this.$attrs[key];
156
- steps.push((clonedNode, data) => {
157
- cache[key] = getPropertyValue(callback, data);
158
- ElementCreator.processAttributes(clonedNode, cache);
159
- });
160
+ fns.push(`ElementCreator.processAttributes(clonedNode, { ${key}: getPropertyValue(getAttrValueCallback, data) } )`);
161
+ fnsParamNames.push('getAttrValueCallback');
162
+ fnsParams.push(callback);
160
163
  } else {
161
- steps.push((clonedNode, data) => {
162
- ElementCreator.processAttributes(clonedNode, buildProperties(cache, this.$attrs, data));
163
- });
164
+ fns.push(`const attrsCache = {}`);
165
+ fns.push(`ElementCreator.processAttributes(clonedNode, buildProperties(attrsCache, this.$attrs, data))`);
166
+ fnsParamNames.push('$attrs');
167
+ fnsParams.push(this.$attrs);
164
168
  }
165
169
  }
166
170
 
167
- const stepsCount = steps.length;
168
- const $element = this.$element;
171
+ fnsParamNames.push('ElementCreator', 'buildProperties', 'getPropertyValue', '$element', 'data');
172
+ fnsParams.push(ElementCreator, buildProperties, getPropertyValue, $element);
173
+ fns.unshift('const clonedNode = $element.cloneNode(false)', 'clonedNode.$ndScopeData = data');
174
+ fns.push('return clonedNode');
169
175
 
170
- this.cloneNode = (data) => {
171
- const clonedNode = $element.cloneNode(false);
172
- $nodeClonedCallbackData.set(clonedNode, data);
173
- for(let i = 0; i < stepsCount; i++) {
174
- steps[i](clonedNode, data);
175
- }
176
- return clonedNode;
177
- };
176
+ this.cloneNode = (new Function(fnsParamNames, fns.join(';'))).bind(null, ...fnsParams);
177
+ };
178
+
179
+ NodeCloner.prototype.resolve = function() {
180
+ if(this.$content) {
181
+ return;
182
+ }
183
+ this.resolveMethods();
184
+ this.$cleanResolve();
185
+ this.resolve = this.$cleanResolve();
186
+ return this;
178
187
  };
179
188
 
180
189
  /**
@@ -1,5 +1,6 @@
1
1
  import {Div, Label, Input, Span, ShowIf, ForEachArray} from '../../../../../elements';
2
2
  import {buildInputWithSlots} from '../helpers';
3
+ import {Observable} from '../../../../core/data/Observable';
3
4
 
4
5
  import './field.css';
5
6
 
@@ -106,13 +107,14 @@ const setupEvents = (input, $desc, instance) => {
106
107
  };
107
108
 
108
109
  const buildErrors = ($desc) => {
109
- return ShowIf($desc.showErrors, () => {
110
- return ShowIf($desc.hasErrors,
111
- () => Div({class: 'field-errors', ...($desc.elementsProps.error || {})},
112
- ForEachArray($desc.errors, (error) =>
113
- Span({class: 'field-error'}, (typeof error === 'string' ? error.toNdChildren() : error)),
114
- ),
110
+ const $shouldShowErrors = Observable.computed((showErrors, hasErrors) => {
111
+ return showErrors && hasErrors;
112
+ }, [$desc.showErrors, $desc.hasErrors]);
113
+ return ShowIf($shouldShowErrors,
114
+ () => Div({class: 'field-errors', ...($desc.elementsProps.error || {})},
115
+ ForEachArray($desc.errors, (error) =>
116
+ Span({class: 'field-error'}, (typeof error === 'string' ? error.toNdChildren() : error)),
115
117
  ),
116
- );
117
- });
118
+ ),
119
+ );
118
120
  };
@@ -61,6 +61,7 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
61
61
 
62
62
 
63
63
  let position;
64
+ const isSupportsPopover = supportsPopover();
64
65
  const updatePosition = (state) => {
65
66
  if(!state) {
66
67
  return;
@@ -79,7 +80,7 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
79
80
  if($desc.showIf && $desc.showIf.val() === false) {
80
81
  return;
81
82
  }
82
- if(supportsPopover()) {
83
+ if(isSupportsPopover) {
83
84
  popover.showPopover();
84
85
  }
85
86