native-document 1.0.247 → 1.0.249

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.247",
3
+ "version": "1.0.249",
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",
@@ -45,6 +45,7 @@ export default function FieldCollection(name, props = {}) {
45
45
  layout: null,
46
46
  transition: null,
47
47
  label: null,
48
+ filter: null,
48
49
  props,
49
50
  };
50
51
 
@@ -79,7 +80,7 @@ FieldCollection.use = function(template) {
79
80
  };
80
81
 
81
82
  /**
82
- * @param {(fields: FieldCollection, index: number) => NdChild} fieldBuilder
83
+ * @param {(index: number) => Record<string, NdChild>} fieldBuilder
83
84
  * @returns {this}
84
85
  */
85
86
  FieldCollection.prototype.fields = function(fieldBuilder) {
@@ -148,32 +149,49 @@ FieldCollection.prototype.transition = function(transitionName) {
148
149
  FieldCollection.prototype.model = function(observable) {
149
150
  if(Validator.isObservable(observable)) {
150
151
  this.$description.value = observable;
151
- this.$description.value.interceptMutations((items) =>
152
- items.map(item => Validator.isObservable(item) ? item : $.object(item)),
153
- );
152
+ this.$description.value.interceptMutations((items) => {
153
+ return items.map(item => Validator.isObservable(item) ? item : $.object(item));
154
+ });
154
155
  return this;
155
156
  }
156
157
  this.$description.value.set(observable);
157
158
  return this;
158
159
  };
159
160
 
161
+
160
162
  /**
163
+ * @param {*} data
161
164
  * @returns {this}
162
165
  */
163
- FieldCollection.prototype.add = function() {
166
+ FieldCollection.prototype.add = function(data) {
164
167
  if(!this.$description.fieldBuilder) {
165
168
  throw new NativeDocumentError('FieldCollection: fields() must be defined before add()');
166
169
  }
167
- const raw = this.$description.defaultItem
168
- ? this.$description.defaultItem()
169
- : {};
170
- const item = Validator.isObservable(raw) ? raw : $.object(raw);
170
+ const item = this.$dataSet(data);
171
+ if(!item) {
172
+ return;
173
+ }
171
174
 
172
175
  this.$description.value.push(item);
173
176
  this.emit('add', item);
174
177
  return this;
175
178
  };
176
179
 
180
+ FieldCollection.prototype.$dataSet = function(data) {
181
+ const dataBuilder = this.$description.defaultItem;
182
+
183
+ let raw = {};
184
+ if(dataBuilder) {
185
+ const dataSet =this.$description.defaultItem(data);
186
+ if(!dataSet) {
187
+ return null;
188
+ }
189
+ raw = dataSet;
190
+ }
191
+
192
+ return Validator.isObservable(raw) ? raw : $.object(raw);
193
+ };
194
+
177
195
  /**
178
196
  * @param {*} item
179
197
  * @returns {this}
@@ -204,9 +222,25 @@ FieldCollection.prototype.reset = function() {
204
222
  * @returns {*[]}
205
223
  */
206
224
  FieldCollection.prototype.value = function() {
207
- return this.$description.value.map(item =>
225
+ const raw = this.$description.value.map(item =>
208
226
  Validator.isObservable(item) ? item.val() : item,
209
227
  );
228
+ const filter = this.$description.filter;
229
+ return filter ? raw.filter(filter) : raw;
230
+ };
231
+
232
+ /**
233
+ * Predicate applied on value() export to filter out unwanted items.
234
+ *
235
+ * @param {(item: *) => boolean} fn
236
+ * @returns {this}
237
+ */
238
+ FieldCollection.prototype.filter = function(fn) {
239
+ if (typeof fn !== 'function') {
240
+ throw new NativeDocumentError('FieldCollection.filter() expects a function');
241
+ }
242
+ this.$description.filter = fn;
243
+ return this;
210
244
  };
211
245
 
212
246
  /**
@@ -0,0 +1,60 @@
1
+ import { $ } from '../../../../core/data/Observable';
2
+ import Field from '../Field';
3
+
4
+
5
+ export default function AddressSearchField(name, props = {}) {
6
+ if(!(this instanceof AddressSearchField)) {
7
+ return new AddressSearchField(name, props);
8
+ }
9
+
10
+ Field.call(this, name, 'input', props);
11
+
12
+ Object.assign(this.$description, {
13
+ renderSuggestion: null
14
+ });
15
+
16
+ }
17
+
18
+ AddressSearchField.defaultTemplate = null;
19
+
20
+ AddressSearchField.prototype = Object.create(Field.prototype);
21
+ AddressSearchField.prototype.constructor = AddressSearchField;
22
+
23
+ /**
24
+ * Registers the render template for AddressSearchField.
25
+ * @param {(description: {
26
+ * value: Observable<string>,
27
+ * placeholder: string|null,
28
+ * debounceMs: number,
29
+ * disabled: Observable<boolean>|null,
30
+ * loading: Observable<boolean>|null,
31
+ * props: GlobalAttributes,
32
+ * }, instance: AddressSearchField) => NdChild} template
33
+ */
34
+ AddressSearchField.use = function(template) {
35
+ AddressSearchField.defaultTemplate = template;
36
+ };
37
+
38
+
39
+ /**
40
+ * @param {Observable} $loading
41
+ * @return {this}
42
+ */
43
+ AddressSearchField.prototype.loading = function($loading){
44
+ this.$description.loading = $loading;
45
+ return this;
46
+ };
47
+
48
+ /**
49
+ * @param {(sugesstion: *) => {}} callback
50
+ * @return {AddressSearchField}
51
+ */
52
+ AddressSearchField.prototype.onSuggestions = function(callback){
53
+ this.$description.callback = callback;
54
+ return this;
55
+ };
56
+
57
+ AddressSearchField.prototype.renderSuggestion = function(renderFn){
58
+ this.$description.renderSuggestion = renderFn;
59
+ return this;
60
+ };
@@ -63,4 +63,13 @@ SearchField.prototype.constructor = SearchField;
63
63
  SearchField.prototype.debounce = function(ms) {
64
64
  this.$description.debounce = ms;
65
65
  return this;
66
- };
66
+ };
67
+
68
+ /**
69
+ * @param {Observable} $loading
70
+ * @return {this}
71
+ */
72
+ SearchField.prototype.loading = function($loading){
73
+ this.$description.loading = $loading;
74
+ return this;
75
+ };
@@ -34,6 +34,7 @@ export interface FieldCollectionInterface extends Omit<BaseComponent, 'onChange'
34
34
  value(): unknown[];
35
35
  count(): number;
36
36
  isEmpty(): boolean;
37
+ filter(handler: (item: any) => boolean): this;
37
38
  onChange(handler: () => void): this;
38
39
  onAdd(handler: () => void): this;
39
40
  onRemove(handler: (item: unknown) => void): this;
@@ -40,7 +40,7 @@ export type SelectFieldDescription = {
40
40
  props: GlobalAttributes;
41
41
  };
42
42
 
43
- export interface SelectFieldInterface extends Omit<FieldInterface, 'render'> {
43
+ export interface SelectFieldInterface extends Omit<FieldInterface, 'render' | 'onChange'> {
44
44
  render(renderFn: (description: SelectFieldDescription, instance: SelectFieldInterface) => ValidChild): this;
45
45
  options(opts: SelectOption[]): this;
46
46
  option(value: unknown, label: ValidChild, props?: GlobalAttributes): this;
@@ -149,4 +149,5 @@ ListGroup.prototype.hideIfEmpty = function() {
149
149
  */
150
150
  ListGroup.prototype.showTitleWhen = function($observable) {
151
151
  this.$description.showTitleWhen = $observable;
152
+ return this;
152
153
  };
@@ -0,0 +1,15 @@
1
+ import BaseComponent from '../../BaseComponent';
2
+
3
+
4
+ export default function AddressMapPicker() {
5
+ if(!(this instanceof AddressMapPicker)) {
6
+ return new AddressMapPicker();
7
+ }
8
+
9
+ this.$description = {
10
+
11
+ };
12
+
13
+ };
14
+
15
+ BaseComponent.extends(AddressMapPicker);
@@ -466,6 +466,7 @@ ObservableArray.prototype.deepSubscribe = function(callback) {
466
466
  };
467
467
  };
468
468
 
469
+
469
470
  /**
470
471
  * Keeps this array in sync with another ObservableArray.
471
472
  * All mutations are mirrored to the target array in real time.
@@ -539,7 +540,7 @@ ObservableArray.prototype.fnClear = function () {
539
540
  return () => this.clear();
540
541
  };
541
542
 
542
- ObservableArray.prototype.val = function () {
543
+ ObservableArray.prototype.rawValue = function () {
543
544
  const result = [];
544
545
  for(const element of this.$currentValue) {
545
546
  result.push(element?.__$Observable ? element.val() : element);
@@ -88,7 +88,17 @@ ObservableItem.prototype.intercept = function(callback) {
88
88
  * @returns {ObservableItem} this
89
89
  */
90
90
  ObservableItem.prototype.interceptMutations = function(callback) {
91
- this.$mutationInterceptor = callback;
91
+ if (typeof callback !== 'function') {
92
+ throw new NativeDocumentError('interceptMutations expects a function');
93
+ }
94
+
95
+ const previousMutationInterceptor = this.$mutationInterceptor;
96
+ this.$mutationInterceptor = (data, ...args) => {
97
+ const prevResult = previousMutationInterceptor ? previousMutationInterceptor(data, ...args) : undefined;
98
+ const nextData = prevResult !== undefined ? prevResult : data;
99
+ const result = callback(nextData, ...args);
100
+ return result !== undefined ? result : nextData;
101
+ };
92
102
  return this;
93
103
  };
94
104
 
@@ -646,6 +656,28 @@ ObservableItem.prototype.clone = function() {
646
656
  return new ObservableItem(clonedValue);
647
657
  };
648
658
 
659
+ /**
660
+ * @param {ObservableItem} targetObservable
661
+ * @return {(function())|*}
662
+ */
663
+ ObservableItem.prototype.sync = function(targetObservable) {
664
+ if(this === targetObservable) {
665
+ return () => {};
666
+ }
667
+
668
+ const updateTargetObservable = (newValue) => targetObservable.set(newValue);
669
+ const updateCurrentObservable = (newValue) => this.set(newValue);
670
+
671
+ this.subscribe(updateTargetObservable);
672
+ targetObservable.subscribe(updateCurrentObservable);
673
+
674
+
675
+ return () => {
676
+ this.unsubscribe(updateTargetObservable);
677
+ targetObservable.unsubscribe(updateCurrentObservable);
678
+ };
679
+ };
680
+
649
681
 
650
682
  ObservableItem.prototype.fnSet = function(value) {
651
683
  return () => this.set(value);
@@ -16,10 +16,14 @@ import ObservableArray from './ObservableArray';
16
16
  * const user = Observable.object({ name: 'John', age: 25 });
17
17
  * user.name.$value = 'Jane'; // triggers reactivity on name only
18
18
  */
19
- export const ObservableObject = function(target, configs) {
19
+ export const ObservableObject = function(target, configs = { }) {
20
20
  ObservableItem.call(this, target);
21
21
  this.$observables = {};
22
- this.configs = configs;
22
+ this.configs = {
23
+ deep: true,
24
+ propagation: true,
25
+ ...configs,
26
+ };
23
27
 
24
28
  for(const key in target) {
25
29
  this.$addKey(key);
@@ -4,6 +4,8 @@ import { $ } from '../../../core/data/Observable';
4
4
  import {H2} from '../../../core/elements';
5
5
 
6
6
  import './field-collection.css';
7
+ import {buildRow} from '../table/data-table/tables';
8
+ import {items} from 'happy-dom/lib/PropertySymbol';
7
9
 
8
10
  export default function FieldCollectionRender($desc, instance) {
9
11
  const props = instance.getEditableProps();
@@ -116,7 +118,6 @@ export default function FieldCollectionRender($desc, instance) {
116
118
  return Div(instance.resolveProps(), layout({ button, rows, label }));
117
119
  }
118
120
 
119
-
120
121
  const defaultLayout = ({ label, button, rows }) => {
121
122
 
122
123
  return [
@@ -80,7 +80,7 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
80
80
  if($desc.showIf && $desc.showIf.val() === false) {
81
81
  return;
82
82
  }
83
- if(isSupportsPopover) {
83
+ if(isSupportsPopover && popover.isConnected) {
84
84
  popover.showPopover();
85
85
  }
86
86