native-document 1.0.40 → 1.0.42

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.
@@ -9,7 +9,7 @@ import {ElementCreator} from "../../wrappers/ElementCreator";
9
9
  *
10
10
  * @param {ObservableItem|ObservableChecker} condition
11
11
  * @param {*} child
12
- * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} comment
12
+ * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
13
13
  * @returns {DocumentFragment}
14
14
  */
15
15
  export const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
@@ -25,7 +25,7 @@ export const ShowIf = function(condition, child, { comment = null, shouldKeepInC
25
25
  }
26
26
  childElement = ElementCreator.getChild(child);
27
27
  if(Validator.isFragment(childElement)) {
28
- childElement = Array.from(childElement.children);
28
+ childElement = Array.from(childElement.childNodes);
29
29
  }
30
30
  return childElement;
31
31
  };
@@ -50,15 +50,14 @@ export const ShowIf = function(condition, child, { comment = null, shouldKeepInC
50
50
  * Hide the element if the condition is true
51
51
  * @param {ObservableItem|ObservableChecker} condition
52
52
  * @param child
53
- * @param comment
53
+ * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
54
54
  * @returns {DocumentFragment}
55
55
  */
56
- export const HideIf = function(condition, child, comment) {
57
-
56
+ export const HideIf = function(condition, child, configs) {
58
57
  const hideCondition = Observable(!condition.val());
59
58
  condition.subscribe(value => hideCondition.set(!value));
60
59
 
61
- return ShowIf(hideCondition, child, comment);
60
+ return ShowIf(hideCondition, child, configs);
62
61
  }
63
62
 
64
63
  /**
@@ -66,9 +65,9 @@ export const HideIf = function(condition, child, comment) {
66
65
  *
67
66
  * @param {ObservableItem|ObservableChecker} condition
68
67
  * @param {*} child
69
- * @param {string|null} comment
68
+ * @param {{comment?: string|null, shouldKeepInCache?: Boolean}} configs
70
69
  * @returns {DocumentFragment}
71
70
  */
72
- export const HideIfNot = function(condition, child, comment) {
73
- return ShowIf(condition, child, comment);
71
+ export const HideIfNot = function(condition, child, configs) {
72
+ return ShowIf(condition, child, configs);
74
73
  }
@@ -18,7 +18,7 @@ export const Match = function($condition, values, shouldKeepInCache = true) {
18
18
  throw new NativeDocumentError("Toggle : condition must be an Observable");
19
19
  }
20
20
 
21
- const anchor = new Anchor();
21
+ const anchor = new Anchor('Match');
22
22
  const cache = new Map();
23
23
 
24
24
  const getItem = function(key) {
@@ -63,7 +63,6 @@ export const Match = function($condition, values, shouldKeepInCache = true) {
63
63
  * @returns {DocumentFragment}
64
64
  */
65
65
  export const Switch = function ($condition, onTrue, onFalse) {
66
-
67
66
  if(!Validator.isObservable($condition)) {
68
67
  throw new NativeDocumentError("Toggle : condition must be an Observable");
69
68
  }
@@ -16,11 +16,13 @@ export const Img = function(src, attributes) {
16
16
  * @returns {Image}
17
17
  */
18
18
  export const AsyncImg = function(src, defaultImage, attributes, callback) {
19
- const image = Img(defaultImage || src, attributes);
19
+ const defaultSrc = Validator.isObservable(src) ? src.val() : src;
20
+ const image = Img(defaultImage || defaultSrc, attributes);
20
21
  const img = new Image();
22
+
21
23
  img.onload = () => {
22
24
  Validator.isFunction(callback) && callback(null, image);
23
- image.src = src;
25
+ image.src = Validator.isObservable(src) ? src.val() : src;
24
26
  };
25
27
  img.onerror = () => {
26
28
  Validator.isFunction(callback) && callback(new NativeDocumentError('Image not found'));
@@ -30,7 +32,7 @@ export const AsyncImg = function(src, defaultImage, attributes, callback) {
30
32
  img.src = newSrc;
31
33
  });
32
34
  }
33
- img.src = src;
35
+ img.src = defaultSrc;
34
36
  return image;
35
37
  };
36
38
 
@@ -13,7 +13,7 @@ export const RouteParamPatterns = {
13
13
  */
14
14
  export function Route($path, $component, $options = {}) {
15
15
 
16
- $path = '/'+trim($path, '/');
16
+ $path = '/'+trim($path, '/').replace(/\/+/, '/');
17
17
 
18
18
  let $pattern = null;
19
19
  let $name = $options.name || null;
@@ -21,6 +21,7 @@ export function Route($path, $component, $options = {}) {
21
21
  const $middlewares = $options.middlewares || [];
22
22
  const $shouldRebuild = $options.shouldRebuild || false;
23
23
  const $paramsValidators = $options.with || {};
24
+ const $layout = $options.layout || null;
24
25
 
25
26
  const $params = {};
26
27
  const $paramsNames = [];
@@ -65,6 +66,7 @@ export function Route($path, $component, $options = {}) {
65
66
  this.middlewares = () => $middlewares;
66
67
  this.shouldRebuild = () => $shouldRebuild;
67
68
  this.path = () => $path;
69
+ this.layout = () => $layout;
68
70
 
69
71
  /**
70
72
  *
@@ -48,5 +48,13 @@ export const RouteGroupHelper = {
48
48
  });
49
49
  name && fullName.push(name);
50
50
  return fullName.join('.');
51
+ },
52
+ layout: ($groupTree) => {
53
+ for(let i = $groupTree.length - 1; i >= 0; i--) {
54
+ if($groupTree[i]?.options?.layout) {
55
+ return $groupTree[i].options.layout;
56
+ }
57
+ }
58
+ return null;
51
59
  }
52
60
  };
@@ -54,7 +54,7 @@ export default function Router($options = {}) {
54
54
  *
55
55
  * @param {string} path
56
56
  * @param {Function} component
57
- * @param {{name:?string, middlewares:Function[], shouldRebuild:Boolean, with: Object }} options
57
+ * @param {{name:?string, middlewares:Function[], shouldRebuild:Boolean, with: Object, layout: Function }} options
58
58
  * @returns {this}
59
59
  */
60
60
  this.add = function(path, component, options) {
@@ -62,6 +62,7 @@ export default function Router($options = {}) {
62
62
  ...options,
63
63
  middlewares: RouteGroupHelper.fullMiddlewares($groupTree, options?.middlewares || []),
64
64
  name: options?.name ? RouteGroupHelper.fullName($groupTree, options.name) : null,
65
+ layout: options?.layout || RouteGroupHelper.layout($groupTree)
65
66
  });
66
67
  $routes.push(route);
67
68
  if(route.name()) {
@@ -7,8 +7,13 @@ export function RouterComponent(router, container) {
7
7
 
8
8
  const $cache = new Map();
9
9
 
10
- const updateContainer = function(node) {
10
+ const updateContainer = function(node, route) {
11
11
  container.innerHTML = '';
12
+ const layout = route.layout();
13
+ if(layout) {
14
+ container.appendChild(layout(node));
15
+ return;
16
+ }
12
17
  container.appendChild(node);
13
18
  };
14
19
 
@@ -19,13 +24,13 @@ export function RouterComponent(router, container) {
19
24
  const { route, params, query, path } = state;
20
25
  if($cache.has(path)) {
21
26
  const cacheNode = $cache.get(path);
22
- updateContainer(cacheNode);
27
+ updateContainer(cacheNode, route);
23
28
  return;
24
29
  }
25
30
  const Component = route.component();
26
31
  const node = Component({ params, query });
27
32
  $cache.set(path, node);
28
- updateContainer(node);
33
+ updateContainer(node, route);
29
34
  };
30
35
 
31
36
  router.subscribe(handleCurrentRouterState);
@@ -0,0 +1,79 @@
1
+ export default function NativeFetch($baseUrl) {
2
+
3
+ const $interceptors = {
4
+ request: [],
5
+ response: []
6
+ };
7
+
8
+ this.interceptors = {
9
+ response: (callback) => {
10
+ $interceptors.response.push(callback);
11
+ },
12
+ request: (callback) => {
13
+ $interceptors.request.push(callback);
14
+ }
15
+ };
16
+
17
+ this.fetch = async function(method, endpoint, params = {}, options = {}) {
18
+ if(!endpoint.startsWith('http')) {
19
+ endpoint = ($baseUrl.endsWith('/') ? $baseUrl : $baseUrl+'/') + endpoint;
20
+ }
21
+ let configs = {
22
+ method,
23
+ headers: {
24
+ ...(options.headers || {})
25
+ },
26
+ };
27
+ if(params) {
28
+ if(params instanceof FormData) {
29
+ configs.body = params;
30
+ }
31
+ else {
32
+ configs.headers['Content-Type'] = 'application/json';
33
+ if(method !== 'GET') {
34
+ configs.body = JSON.stringify(params);
35
+ } else {
36
+ configs.params = params;
37
+ }
38
+ }
39
+ }
40
+
41
+ for(const interceptor of $interceptors.request) {
42
+ configs = (await interceptor(configs, endpoint)) || configs;
43
+ }
44
+
45
+ let response = await fetch(endpoint, configs);
46
+
47
+ for(const interceptor of $interceptors.response) {
48
+ response = (await interceptor(response, endpoint)) || response;
49
+ }
50
+
51
+ const contentType = response.headers.get('content-type') || '';
52
+ const data = contentType.includes('application/json')
53
+ ? await response.json()
54
+ : await response.text();
55
+
56
+ if(!response.ok) {
57
+ const error = new Error(data?.message || response.statusText);
58
+ error.status = response.status;
59
+ error.data = data;
60
+ throw error;
61
+ }
62
+
63
+ return data;
64
+ };
65
+
66
+
67
+ this.post = function (endpoint, params = {}, options = {}) {
68
+ return this.fetch('POST', endpoint, params, options);
69
+ };
70
+ this.put = function (endpoint, params = {}, options = {}) {
71
+ return this.fetch('PUT', endpoint, params, options);
72
+ };
73
+ this.delete = function (endpoint, params = {}, options = {}) {
74
+ return this.fetch('DELETE', endpoint, params, options);
75
+ };
76
+ this.get = function (endpoint, params = {}, options = {}) {
77
+ return this.fetch('GET', endpoint, params, options);
78
+ };
79
+ };
@@ -19,6 +19,9 @@ const Validator = {
19
19
  isProxy(value) {
20
20
  return value?.__isProxy__
21
21
  },
22
+ isAnchor(value) {
23
+ return value?.__Anchor__
24
+ },
22
25
  isObservableChecker(value) {
23
26
  return value?.__$isObservableChecker || value instanceof ObservableChecker;
24
27
  },
@@ -50,7 +53,8 @@ const Validator = {
50
53
  return value && (
51
54
  value.nodeType === COMMON_NODE_TYPES.ELEMENT ||
52
55
  value.nodeType === COMMON_NODE_TYPES.TEXT ||
53
- value.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT
56
+ value.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT ||
57
+ value.nodeType === COMMON_NODE_TYPES.COMMENT
54
58
  );
55
59
  },
56
60
  isFragment(value) {
@@ -10,8 +10,6 @@ export function NDElement(element) {
10
10
  }
11
11
  NDElement.prototype.__$isNDElement = true;
12
12
 
13
-
14
-
15
13
  NDElement.prototype.valueOf = function() {
16
14
  return this.$element;
17
15
  };
@@ -0,0 +1,48 @@
1
+ import Anchor from "../elements/anchor";
2
+
3
+
4
+ export function SingletonView($viewCreator) {
5
+ let $cacheNode = null;
6
+ let $components = null;
7
+
8
+ this.render = (data) => {
9
+ if(!$cacheNode) {
10
+ $cacheNode = $viewCreator(this);
11
+ }
12
+ if(!$components) {
13
+ return $cacheNode;
14
+ }
15
+ for(const index in $components) {
16
+ const updater = $components[index];
17
+ updater(...data);
18
+ }
19
+ return $cacheNode;
20
+ };
21
+
22
+ this.createSection = (name, fn) => {
23
+ $components = $components || {};
24
+ const anchor = new Anchor('Component '+name);
25
+
26
+ $components[name] = function(...args) {
27
+ anchor.removeChildren();
28
+ if(!fn) {
29
+ anchor.append(args);
30
+ return;
31
+ }
32
+ anchor.appendChild(fn(...args));
33
+ };
34
+ return anchor;
35
+ };
36
+ }
37
+
38
+
39
+ export function useSingleton(fn) {
40
+ let $cache = null;
41
+
42
+ return function(...args) {
43
+ if(!$cache) {
44
+ $cache = new SingletonView(fn);
45
+ }
46
+ return $cache.render(args);
47
+ };
48
+ }
@@ -1,5 +1,6 @@
1
1
  import {ElementCreator} from "./ElementCreator";
2
2
  import {createTextNode} from "./HtmlElementWrapper";
3
+ import Anchor from "../elements/anchor";
3
4
 
4
5
  const cloneBindingsDataCache = new WeakMap();
5
6
 
@@ -142,6 +143,7 @@ export function TemplateCloner($fn) {
142
143
  this.attach = (fn) => {
143
144
  return createBinding(fn, 'attach');
144
145
  };
146
+
145
147
  }
146
148
 
147
149
  export function useCache(fn) {
@@ -18,6 +18,7 @@ export type ValidChild =
18
18
  | ValidChild[]
19
19
  | ((...args: any[]) => ValidChild);
20
20
 
21
+
21
22
  export type Attributes = Record<string, any> & {
22
23
  class?: string | Record<string, boolean | ObservableItem<boolean>>;
23
24
  style?: string | Record<string, string | ObservableItem<string>>;
@@ -122,5 +123,20 @@ export declare const TBodyCell: ElementFunction;
122
123
  export declare const Fragment: ElementFunction;
123
124
  export declare const NativeDocumentFragment: typeof Anchor;
124
125
 
126
+
127
+ export declare type AnchorDocumentFragment = DocumentFragment & {
128
+ detach: () => void;
129
+ restore: () => void;
130
+ clear: () => void;
131
+ remove: () => void;
132
+ removeChildren: () => void;
133
+ insertBefore: (child: ValidChild, before: HTMLElement|Comment) => void;
134
+ replaceContent: (child: ValidChild) => void;
135
+ appendElement: (child: ValidChild, before: HTMLElement) => void;
136
+ getByIndex: (index: number) => HTMLElement;
137
+ endElement: () => Comment;
138
+ startElement: () => Comment;
139
+ };
140
+
125
141
  // Anchor
126
- export declare function Anchor(name?: string, isUniqueChild?: boolean): DocumentFragment;
142
+ export declare function Anchor(name?: string, isUniqueChild?: boolean): AnchorDocumentFragment;
@@ -50,11 +50,14 @@ export interface ObservableArray<T> extends ObservableItem<T[]> {
50
50
  sort(compareFn?: (a: T, b: T) => number): T[];
51
51
  splice(start: number, deleteCount?: number, ...items: T[]): T[];
52
52
 
53
+ isEmpty(): boolean;
53
54
  clear(): boolean;
54
55
  merge(values: T[]): void;
56
+ removeItem(item: T): T[];
55
57
  remove(index: number): T[];
56
58
  swap(indexA: number, indexB: number): boolean;
57
59
  length(): number;
60
+ count(condition: (item:T, index?:number) => boolean): number;
58
61
  populateAndRender(iteration: number, callback: (index: number) => T): void;
59
62
 
60
63
  map<U>(callback: (value: T, index: number, array: T[]) => U): U[];
package/types/router.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  // Router system type definitions
2
- import { ValidChild, NDElement } from './elements';
2
+ import { ValidChild } from './elements';
3
+ import { NDElement } from './nd-element';
3
4
 
4
5
  export interface RouteParams {
5
6
  [key: string]: string;
@@ -42,7 +43,7 @@ export interface Router {
42
43
  with?: Record<string, string>;
43
44
  }): this;
44
45
 
45
- group(suffix: string, options: { middlewares?: Function[]; name?: string }, callback: () => void): this;
46
+ group(suffix: string, options: { middlewares?: Function[]; name?: string, layout?: Function }, callback: () => void): this;
46
47
 
47
48
  generateUrl(name: string, params?: RouteParams, query?: QueryParams): string;
48
49
  resolve(target: string | { name: string; params?: RouteParams; query?: QueryParams }): {
@@ -0,0 +1,19 @@
1
+ import { AnchorDocumentFragment } from "./elements";
2
+
3
+ export type ViewCreator = (instance: SingletonView) => Node;
4
+
5
+ export type SectionFunction = (...args: any[]) => Node | Node[];
6
+
7
+ export type ComponentUpdater = (...args: any[]) => void;
8
+
9
+ export type ComponentsMap = Record<string, ComponentUpdater>;
10
+
11
+ export declare class SingletonView {
12
+ constructor(viewCreator: ViewCreator);
13
+
14
+ render(data: any[]): Node;
15
+
16
+ createSection(name: string, fn?: SectionFunction): AnchorDocumentFragment;
17
+ }
18
+
19
+ export declare function useSingleton(fn: ViewCreator): (...args: any[]) => Node;
package/utils.d.ts ADDED
File without changes
package/utils.js ADDED
@@ -0,0 +1,6 @@
1
+ import NativeFetch from "./src/utils/fetch/NativeFetch";
2
+
3
+
4
+ export {
5
+ NativeFetch
6
+ };