arrmatura 4.3.2 → 5.0.1

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 (87) hide show
  1. package/README.md +22 -22
  2. package/commons/auth/UserService.ts +107 -0
  3. package/commons/auth/index.ts +4 -0
  4. package/commons/auth/user.xml +66 -0
  5. package/commons/components/buttons.xml +23 -0
  6. package/commons/components/index.ts +13 -0
  7. package/commons/components/inputs.xml +33 -0
  8. package/commons/components/layouts.xml +77 -0
  9. package/commons/components/media.xml +21 -0
  10. package/commons/components/modal.xml +37 -0
  11. package/commons/components/navigation.xml +59 -0
  12. package/commons/components/popups.xml +12 -0
  13. package/commons/components/searchbar.xml +40 -0
  14. package/commons/components/table.xml +120 -0
  15. package/commons/components/toasts.xml +13 -0
  16. package/commons/components/viewport.xml +48 -0
  17. package/commons/forms/FieldItem.xml +20 -0
  18. package/commons/forms/FormController.ts +73 -0
  19. package/commons/forms/Item.ts +68 -0
  20. package/commons/forms/ItemCollection.ts +152 -0
  21. package/commons/forms/ItemController.ts +62 -0
  22. package/commons/forms/MetadataService.ts +45 -0
  23. package/commons/forms/MultiEnumField.xml +44 -0
  24. package/commons/forms/MultivalueController.ts +49 -0
  25. package/commons/forms/SmartareaField.xml +51 -0
  26. package/commons/forms/SuggestionController.ts +80 -0
  27. package/commons/forms/SuggestionField.xml +28 -0
  28. package/commons/forms/fields.xml +138 -0
  29. package/commons/forms/form.xml +37 -0
  30. package/commons/forms/index.ts +29 -0
  31. package/commons/index.ts +6 -0
  32. package/commons/pipes/index.ts +21 -0
  33. package/commons/pipes/showCounts.ts +16 -0
  34. package/commons/services/ErrorHandlingService.ts +11 -0
  35. package/commons/services/FirebaseService.ts +185 -0
  36. package/commons/services/GSheetsService.ts +92 -0
  37. package/commons/services/HeartbeatService.ts +35 -0
  38. package/commons/services/Invoke.ts +13 -0
  39. package/commons/services/JsonpService.ts +18 -0
  40. package/commons/services/Loader.ts +17 -0
  41. package/commons/services/LocalStorage.ts +46 -0
  42. package/commons/services/NavigationService.ts +55 -0
  43. package/commons/services/Service.ts +68 -0
  44. package/commons/services/ServiceWorker.ts +111 -0
  45. package/commons/services/ToastService.ts +49 -0
  46. package/commons/services/index.ts +14 -0
  47. package/core/Arrmatura.ts +79 -0
  48. package/core/CNode.ts +112 -0
  49. package/core/Component.ts +431 -0
  50. package/core/Platform.ts +3 -0
  51. package/core/cnodes/composition.ts +100 -0
  52. package/core/cnodes/conditionals.ts +51 -0
  53. package/core/cnodes/elementary.ts +45 -0
  54. package/core/cnodes/iterations.ts +94 -0
  55. package/core/cnodes/routing.ts +25 -0
  56. package/core/compileNode.ts +39 -0
  57. package/core/expression.ts +73 -0
  58. package/core/index.ts +2 -0
  59. package/core/register.ts +43 -0
  60. package/core/utils.ts +25 -0
  61. package/docs/index.js +191 -4069
  62. package/lib/arrayGroupBy.ts +19 -0
  63. package/lib/arraySortBy.ts +49 -0
  64. package/lib/arrayToObject.ts +18 -0
  65. package/lib/codus.ts +25 -0
  66. package/lib/consts.ts +3 -0
  67. package/lib/createListeners.ts +12 -0
  68. package/lib/curry.ts +8 -0
  69. package/lib/dateFormat.ts +69 -0
  70. package/lib/dateOf.ts +31 -0
  71. package/lib/dateParseISO8601.ts +27 -0
  72. package/lib/fx.ts +62 -0
  73. package/lib/guid.ts +7 -0
  74. package/lib/index.ts +19 -0
  75. package/lib/l10n.ts +40 -0
  76. package/lib/nextId.ts +9 -0
  77. package/lib/noop.ts +8 -0
  78. package/lib/obj.ts +62 -0
  79. package/lib/predicat.ts +26 -0
  80. package/lib/resources.ru.ts +20 -0
  81. package/lib/resources.ts +20 -0
  82. package/lib/scalar.ts +25 -0
  83. package/lib/str.ts +76 -0
  84. package/lib/urls.ts +91 -0
  85. package/lib/xml.ts +117 -0
  86. package/package.json +19 -8
  87. package/docs/index.js.map +0 -1
@@ -0,0 +1,45 @@
1
+ import { Platform } from '../Platform';
2
+ import { CNode } from '../CNode';
3
+ import { compileNodes } from '../compileNode';
4
+ import { Component } from '../Component';
5
+
6
+ export class ElementComponent extends Component<CElementNode> {
7
+ get displayName(): string {
8
+ return this.node.tag;
9
+ }
10
+
11
+ createImplementation(initials: Hash): IComponentImplementation {
12
+ return Platform.instance.createElement(this.node.tag, initials, this);
13
+ }
14
+ }
15
+
16
+ export class TextElementComponent extends Component<CTextElementNode> {
17
+ createImplementation(initials: Hash) {
18
+ return Platform.instance.createTextElement(initials, this);
19
+ }
20
+ }
21
+
22
+ export class CElementNode extends CNode<ElementComponent> {
23
+ constructor(x: XmlNode) {
24
+ super();
25
+ this.tag = x.tag;
26
+ this.content = compileNodes(x.nodes);
27
+ this.compileAttributes(x.attrs);
28
+ }
29
+
30
+ get ComponentConstructor() {
31
+ return ElementComponent;
32
+ }
33
+ }
34
+
35
+ export class CTextElementNode extends CNode<TextElementComponent> {
36
+ constructor(x: XmlNode) {
37
+ super();
38
+ this.tag = x.tag;
39
+ this.compileAttributes(x.attrs);
40
+ }
41
+
42
+ get ComponentConstructor() {
43
+ return TextElementComponent;
44
+ }
45
+ }
@@ -0,0 +1,94 @@
1
+ import { CNode } from '../CNode';
2
+ import { compileNodes } from '../compileNode';
3
+ import { Component } from '../Component';
4
+
5
+ class ForComponent extends Component<CForNode> {
6
+ pkHash: Hash<Datum> = {};
7
+
8
+ get displayName(): string {
9
+ return '🔹';
10
+ }
11
+
12
+ get content() {
13
+ const {
14
+ state: { each },
15
+ } = this;
16
+ const itemNode = this.node.itemNode;
17
+ const nodes: ComponentContent = new Map();
18
+ this.pkHash = {};
19
+ if (each?.length) {
20
+ if (!each.forEach) {
21
+ throw new Error('[ui:for] Items has no forEach() ' + each);
22
+ }
23
+ each.forEach((datum: Datum) => {
24
+ const id = datum.id;
25
+ if (id == null) {
26
+ console.error('ERROR: empty item id: ', datum);
27
+ return;
28
+ }
29
+ const pk = String(id);
30
+ if (this.pkHash[pk]) {
31
+ console.error('ERROR: duplicate item id: ' + pk, datum);
32
+ return;
33
+ }
34
+ this.pkHash[pk] = datum;
35
+ const inode = itemNode.cloneWithDatum(datum).addPropertyResolver(() => this.pkHash[pk], itemNode.itemName);
36
+ nodes.set(inode.uid, inode);
37
+ });
38
+ }
39
+ return nodes;
40
+ }
41
+ }
42
+
43
+ export class CForNode extends CNode<ForComponent> {
44
+ itemNode: CItemNode;
45
+ constructor(x: XmlNode, [itemName, prep, expr = prep]: string[]) {
46
+ super();
47
+ this.itemNode = new CItemNode(itemName, compileNodes([x]));
48
+ this.compileAttribute('each', '{:<'.includes(expr[0]) ? expr : `{${expr}}`);
49
+ }
50
+
51
+ get ComponentConstructor() {
52
+ return ForComponent;
53
+ }
54
+ }
55
+
56
+ class ItemComponent extends Component<CItemNode> {
57
+ get displayName(): string {
58
+ return '🔹';
59
+ }
60
+ get recontentScope(): Component {
61
+ return this;
62
+ }
63
+
64
+ emit(key: string, data: Delta): void {
65
+ return this.scope.emit(key, data);
66
+ }
67
+
68
+ get(propId: string) {
69
+ const iName: string = this.node.itemName;
70
+ const value = propId.startsWith(iName + '.') || propId === iName ? super.get(propId) : this.scope.get(propId);
71
+ // this.log(propId, value);
72
+ return value;
73
+ }
74
+ }
75
+
76
+ export class CItemNode extends CNode<ItemComponent> {
77
+ itemName: string;
78
+ constructor(itemName: string, content?: ComponentContent) {
79
+ super();
80
+ this.itemName = itemName;
81
+ this.content = content;
82
+ }
83
+
84
+ cloneWithDatum(datum: Datum) {
85
+ const uid = this.uid + '#' + datum.id;
86
+ return Object.assign(new CItemNode(this.itemName, this.content), {
87
+ uid,
88
+ });
89
+ }
90
+
91
+ get ComponentConstructor() {
92
+ return ItemComponent;
93
+ }
94
+ }
@@ -0,0 +1,25 @@
1
+ import { CNode } from '../CNode';
2
+ import { compileNode } from '../compileNode';
3
+ import { Component } from '../Component';
4
+
5
+ export class DynamicTagComponent extends Component<CDynamicTagNode> {
6
+ get content(): ComponentContent | undefined {
7
+ const { tag } = this.state;
8
+ const uid = this.node.uid + ':' + tag;
9
+ return new Map([[uid, Object.assign(compileNode(Object.assign(this.node.xml, { tag })), { uid })]]);
10
+ }
11
+ }
12
+
13
+ export class CDynamicTagNode extends CNode<DynamicTagComponent> {
14
+ xml: XmlNode & { tag: string };
15
+
16
+ constructor(xml: XmlNode, expr: string) {
17
+ super();
18
+ this.compileAttribute('tag', expr);
19
+ this.xml = xml;
20
+ }
21
+
22
+ get ComponentConstructor() {
23
+ return DynamicTagComponent;
24
+ }
25
+ }
@@ -0,0 +1,39 @@
1
+ import { CCompositeNode, CFragmentNode, CSlotNode } from './cnodes/composition';
2
+ import { CDynamicTagNode } from './cnodes/routing';
3
+ import { CElementNode, CTextElementNode } from './cnodes/elementary';
4
+ import { CForNode } from './cnodes/iterations';
5
+ import { CIfNode } from './cnodes/conditionals';
6
+
7
+ export const compileNode = (x: XmlNode): INode => {
8
+ const { tag, attrs } = x;
9
+ const each = attrs?.['ui:for'];
10
+ if (each) {
11
+ delete attrs['ui:for'];
12
+ return new CForNode(x, String(each).trim().split(' '));
13
+ }
14
+ const when = attrs?.['ui:if'];
15
+ if (when) {
16
+ delete attrs['ui:if'];
17
+ return new CIfNode(x, String(when));
18
+ }
19
+ if (tag === 'ui:tag') {
20
+ const expr = attrs?.['tag'] || tag;
21
+ delete attrs?.['tag'];
22
+ return new CDynamicTagNode(x, String(expr));
23
+ }
24
+ if (tag === 'ui:slot') {
25
+ return new CSlotNode(x);
26
+ }
27
+ if (tag === 'ui:fragment') {
28
+ return new CFragmentNode(x);
29
+ }
30
+ if (tag === '#text') {
31
+ return new CTextElementNode(x);
32
+ }
33
+ if (tag[0].match(/[A-Z]/)) return new CCompositeNode(x);
34
+
35
+ return new CElementNode(x);
36
+ };
37
+
38
+ export const compileNodes = (x?: XmlNode[] | null): ComponentContent =>
39
+ new Map<Uid, INode>(x?.map(compileNode).map((c) => [c.uid, c]) || []);
@@ -0,0 +1,73 @@
1
+ import { scalarParse } from 'scalar';
2
+
3
+ const RE_SINGLE_PLACEHOLDER = /^\{([^}]+)\}$/;
4
+
5
+ const RE_PLACEHOLDER = /\{([^}]+)\}/g;
6
+
7
+ const withNoPipes = (_: unknown, v: unknown) => v;
8
+
9
+ const splitExpression = (v: Expression) => {
10
+ return v.split('|').map((s) => s.trim());
11
+ };
12
+
13
+ export function withPipes(pipes: string[]) {
14
+ return !pipes.length
15
+ ? withNoPipes
16
+ : (c: IComponent, initialValue: unknown) => pipes.reduce((r, pk) => c.applyPipe(pk, r), initialValue);
17
+ }
18
+
19
+ export function compilePipeExpression(v: Expression) {
20
+ const [key, ...pipes] = splitExpression(v);
21
+ return { key, pipec: withPipes(pipes) };
22
+ }
23
+
24
+ function stringInterpolation(v: string, fnx: Array<(c: IComponent) => unknown> = []) {
25
+ const pattern = v.trim().replace(RE_PLACEHOLDER, (_: string, expr: string) => {
26
+ fnx.push(placeholder(expr));
27
+ return '{{' + (fnx.length - 1) + '}}';
28
+ });
29
+ return !fnx.length
30
+ ? (_: IComponent) => pattern
31
+ : (c: IComponent) =>
32
+ pattern
33
+ .replace(/\{\{(\d+)\}\}/g, (_: string, idx: string) => {
34
+ const r = fnx[Number(idx)](c);
35
+ return !r && r !== 0 ? '' : String(r);
36
+ })
37
+ .replace(/\s+/g, ' ');
38
+ }
39
+
40
+ function resourceExpression(expr: string) {
41
+ const { key, pipec } = compilePipeExpression(expr);
42
+ const intrpltn = stringInterpolation(key);
43
+ return !pipec.length ? (c: IComponent) => c.res(intrpltn(c)) : (c: IComponent) => pipec(c, c.res(intrpltn(c)));
44
+ }
45
+
46
+ function placeholder(expr: string) {
47
+ const { key, pipec } = compilePipeExpression(expr);
48
+ const fn =
49
+ key[0] === ':'
50
+ ? (
51
+ (k) => (c: IComponent) =>
52
+ c.res(k)
53
+ )(key.slice(1))
54
+ : (c: IComponent) => c.getFromScope(key);
55
+ return !pipec.length ? fn : (c: IComponent) => pipec(c, fn(c));
56
+ }
57
+
58
+ export function compileExpression(v: unknown) {
59
+ if (typeof v !== 'string') {
60
+ return () => v;
61
+ }
62
+ if (v[0] === ':') {
63
+ return resourceExpression(v.slice(1).trim());
64
+ }
65
+ if (!v.includes('{')) {
66
+ const vv = scalarParse(v);
67
+ return () => vv;
68
+ }
69
+ if (v.match(RE_SINGLE_PLACEHOLDER)) {
70
+ return placeholder(v.slice(1, -1).trim());
71
+ }
72
+ return stringInterpolation(v);
73
+ }
package/core/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './Arrmatura';
2
+ export * from './Platform';
@@ -0,0 +1,43 @@
1
+ import { compileNodes } from './compileNode';
2
+ import { xmlParse } from 'xml';
3
+ import { fnName } from './utils';
4
+
5
+ export class ComponentDefinition {
6
+ tag: string;
7
+ template?: string;
8
+ Ctor: any;
9
+ $templateContent?: ComponentContent;
10
+
11
+ constructor({ tag, template, Ctor }: ComponentDefinitionInfo) {
12
+ this.tag = tag;
13
+ this.template = template;
14
+ this.Ctor = Ctor || function () {};
15
+ }
16
+
17
+ get content() {
18
+ return this.$templateContent || (this.$templateContent = compileNodes(xmlParse(this.template)));
19
+ }
20
+ }
21
+
22
+ export const REGISTRY = new Map<string, ComponentDefinition>();
23
+
24
+ const notFound = (tag: string): ComponentDefinition =>
25
+ new ComponentDefinition({ tag, template: '<b>??' + tag + '??</b>' });
26
+
27
+ const setInfo = (ctr: ComponentDefinitionInfo) => REGISTRY.set(ctr.tag, new ComponentDefinition(ctr));
28
+
29
+ const registerType = (ctr: string | ComponentDefinitionInfo | Constructor) => {
30
+ if (typeof ctr === 'string') {
31
+ ctr.replace(/<component\s+id="(.+)">([\s\S]*?)<\/component>/gm, (_, tag, template) => {
32
+ setInfo({ tag, template: template.trim() });
33
+ return '';
34
+ });
35
+ } else {
36
+ setInfo(typeof ctr === 'function' ? { Ctor: ctr, tag: ctr.name || fnName(ctr) } : ctr);
37
+ }
38
+ };
39
+
40
+ export const registerTypes = (types?: Array<string | ComponentDefinitionInfo | Constructor>) =>
41
+ types?.forEach(registerType);
42
+
43
+ export const getByTag = (tag: string) => REGISTRY.get(tag) || notFound(tag);
package/core/utils.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { nextId } from 'nextId';
2
+ import { identity } from 'noop';
3
+ import { attributesToString } from 'xml';
4
+
5
+ export const applyValue = (value: any, fn = identity) => (value?.then ? value.then(fn) : fn(value));
6
+
7
+ export const fnName = (ctor: object) => (/^function\s+([\w$]+)\s*\(/.exec(ctor.toString()) || [])[1] || nextId('C');
8
+
9
+ export const methodName = (x: unknown, pre = '') => {
10
+ const s = `${x || ''}`;
11
+ return pre + s[0].toUpperCase() + s.slice(1);
12
+ };
13
+
14
+ export const stringifyState = (attrs?: object | Hash) => {
15
+ if (!attrs) {
16
+ return '';
17
+ }
18
+ const r: string[] = [];
19
+ Object.entries(attrs).forEach(([k, v]) => {
20
+ if (v) {
21
+ r.push(' ' + k + '="' + attributesToString(v) + '"');
22
+ }
23
+ });
24
+ return r.length ? r.join('') : '';
25
+ };