arrmatura 6.3.1 → 6.3.2

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/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  ## Definitive
4
4
 
5
- `Arrmatura` is a programming framework strongly relied on declarative style and functional programming paradigm.
5
+ `Arrmatura` is a framework which inherits declarative approach and functional programming.
6
+
6
7
  It comprises of
7
8
 
8
- - declarative notation to define orbitrary components, its composition and data flow.
9
- - set of public and private types, which outlines an implementation approach.
10
- - a runtime engine, that enables launching applications of any kind.
11
- - `IPlatform` implementation for web to build/launch client applications.
12
- - Web UI kits with various components, services, forms, rich UI etc.
9
+ - extended HTML notation to define components, its composition, behaviour and data flow.
10
+ - type system and runtime enabling development of applications of any kind.
11
+ - `IPlatform` implementation for web client applications.
12
+ - Web UI kits with plenty of components, services, forms, editors etc.
13
13
 
14
14
  ## Key features and benefits of the platform
15
15
 
@@ -39,7 +39,3 @@ See [Hello, world](docs/HELLO.md) for starting example.
39
39
  - [Emoji List](https://emojis-list.web.app/)
40
40
  - [Countries List](https://countries-list.web.app/)
41
41
  - [Game Solver](https://dlitskevich.github.io/solver/) ([source](https://github.com/dlitskevich/solver/tree/master/app))
42
-
43
- ## Limitations and considerations
44
-
45
- TBD
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{CRootNode as m}from"./src/registry/root";export*from"./src/registry";import{CRootNode as c}from"./src/registry/root";export*from"./src/core/Component";var n=(o,t)=>{let r=new m(t).createArrmatron(o);return r.up({},!0),r};export{c as CRootNode,n as launch};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../index.ts"],
4
+ "sourcesContent": ["import { IArrmatron, IPlatform } from \"arrmatura/types\";\n\nimport { CRootNode } from \"./src/registry/root\";\n\nexport * from \"./src/registry\";\nexport { CRootNode } from \"./src/registry/root\";\nexport * from \"./src/core/Component\";\n\n/**\n * Launches the runtime with given top-level template on the specified platform.\n *\n * @param {IPlatform} platform - The platform on which to launch the template.\n * @param {string} template - The template to launch with.\n * @return {IArrmatron} The root context object.\n */\nexport const launch = (platform: IPlatform, template: string): IArrmatron => {\n const root = new CRootNode(template).createArrmatron(platform);\n\n root.up({}, true);\n\n return root;\n};\n"],
5
+ "mappings": "AAEA,OAAS,aAAAA,MAAiB,sBAE1B,WAAc,iBACd,OAAS,aAAAA,MAAiB,sBAC1B,WAAc,uBASP,IAAMC,EAAS,CAACC,EAAqBC,IAAiC,CAC3E,IAAMC,EAAO,IAAIJ,EAAUG,CAAQ,EAAE,gBAAgBD,CAAQ,EAE7D,OAAAE,EAAK,GAAG,CAAC,EAAG,EAAI,EAETA,CACT",
6
+ "names": ["CRootNode", "launch", "platform", "template", "root"]
7
+ }
package/docs/manual.md CHANGED
@@ -7,17 +7,17 @@
7
7
  ```html
8
8
 
9
9
  <component id="NavTreeItem">
10
- <a href="@id">
11
- <span>{@name | slice:0:50 | capitalize}</span>
12
- <span if="@label" class="label label-{@type}">{@label}</span>
10
+ <a href="id">
11
+ <span>{name | slice:0:50 | capitalize}</span>
12
+ <span If="label" class="label label-{type}">{label}</span>
13
13
  </a>
14
14
  </component>
15
15
 
16
16
  <component id="NavTree">
17
17
  <ul class="nav">
18
- <li class="nav-item {@item.class}" each="item of @data">
19
- <NavTreeItem {...@item}>
20
- <NavTree if="@item.subs" data="@item.subs" />
18
+ <li class="nav-item {item.class}" Each="item of data">
19
+ <NavTreeItem (...)="{item}">
20
+ <NavTree If="item.subs" data="{item.subs}" />
21
21
  </li>
22
22
  </ul>
23
23
  </component>
@@ -30,13 +30,13 @@
30
30
  With `if` attribute, an element(and its inner context) presents only if value of expression is truthy.
31
31
 
32
32
  ```html
33
- <div ... if="@enabled">...</div>
33
+ <div ... If="enabled">...</div>
34
34
  ```
35
35
 
36
36
  #### full `then-else` syntax
37
37
 
38
38
  ```html
39
- <Fragment if="@enabled">
39
+ <Fragment If="enabled">
40
40
  <Then><Case1 /></Then>
41
41
  <Else><Case2 /></Else>
42
42
  </Fragment>
@@ -48,8 +48,8 @@ With `if` attribute, an element(and its inner context) presents only if value of
48
48
 
49
49
  ```html
50
50
  <ul>
51
- <li each="item of @data">
52
- <a href="/item/{@item.id}">{@item.position}. {@item.name}</span>
51
+ <li Each="item of data">
52
+ <a href="/item/{item.id}">{item.position}. {item.name}</span>
53
53
  </li>
54
54
  </ul>
55
55
  ```
@@ -61,7 +61,7 @@ With `if` attribute, an element(and its inner context) presents only if value of
61
61
  `<Fragment>` is a transparent container and works just like a parens for multiple components.
62
62
 
63
63
  ```html
64
- <Fragment if="@enabled"> <innerContent1 />...<innerContentN /> </Fragment>
64
+ <Fragment If="enabled"> <innerContent1 />...<innerContentN /> </Fragment>
65
65
  ```
66
66
 
67
67
  ## Dynamic tags.
@@ -69,93 +69,108 @@ With `if` attribute, an element(and its inner context) presents only if value of
69
69
  Used to calculate tag dunamically at runtime.
70
70
 
71
71
  ```html
72
- <Dynamic as="{@type}Field" ...></Dynamic>
72
+ <Dynamic As="Field.{type}" ...></Dynamic>
73
73
  ```
74
74
 
75
- > use dot in type name to fallback to a basic implementation if a specific one not found `tag="Button.{@type}"`
76
-
77
- ### References.
78
-
79
- Add `ref` attribute to any component to get refer it in `arrows` expressions.
80
-
81
- ```html
82
- <UserService ref="user" />
83
- ...
84
- <UserAvatar data="<- user.profile" onSave="->user.update" />
85
- ```
75
+ > it will fallback to a `Field` if a specific type not found.
86
76
 
87
77
  ## Properties.
88
78
 
89
- Component properties can be assigned
79
+ Component state can be mutated different ways listed below.
80
+ State updates lead to redraw UI and notify subscribers(left arrows)
81
+ Updating data is compared with existing state values for 'sameness' (same set of same values).
90
82
 
91
83
  ### with scalar literals
92
84
 
93
- `prop1="magicNumber"` puts a `magicNumber` literal into `prop1` property.
85
+ `prop1="'somestring'"` puts a literal into `prop1` property.
94
86
 
95
87
  > - 'true', 'false' values are narrowed to boolean,
96
88
  > - numbers has been narrowed to number type.
97
89
 
98
90
  ### with resources values
99
91
 
100
- use `@@` prefix to refer any entity in the resource bundle.
92
+ `R`-prefix used to refer any value in the resource bundle.
101
93
 
102
- `prop="@@resId"` puts result of `platform.getResource(resId)` into `prop`.
94
+ `prop="R.resId"` assigns `resId` resource value to `prop`.
103
95
 
104
96
  ### with result of expression
105
97
 
106
- `prop="@prop2"` puts value of `prop2` owner property
98
+ `prop="{prop2}"` assigns value of `prop2` property of the current scope.
107
99
 
108
- `prop="@data.key"` puts value of `prop2.key` owner property in depth.
100
+ `prop="{data.key}"` assigns value of `data.key`.
109
101
 
110
- `prop="@prop2#not"` the `#not` postfix narrow to boolean and inverts the value of `prop2`
102
+ `prop="{!prop2}"` assigns inverted value of `prop2`
111
103
 
112
- `...="@data"` special `...` prop name spreads keys/values of `data` into properties of an entity.
104
+ `(...)="{data}"` special `(...)` notation used to spread keys/values of `data` into properties of a target entity.
113
105
 
114
106
  ### with result of chain of pipes
115
107
 
116
- `prop="@some | pipeFn1 : 'strLiteral1' : 1 : true | pipeFn2 : @property2 | pipeFn2 : @@resourceId"` applies chain of pipes in left-to-right order.
108
+ `prop="{some | pipeFn1 : 'strLiteral1' : 1 : true | pipeFn2 : property2 | pipeFn2 : R.resourceId}` applies chain of pipes.
117
109
 
118
110
  > - Pipe functions can be chained. Result of the previous one passed as a first argument to the next one.
119
111
  > - Optional colon-separated arguments can be passed to a pipe function as second, third arguments.
120
- > - Use shortcuts like `==, && , ??, ?, >, <, []` for `equals, and, or, then, less, greater, dot` functions respectively. Priority is still left-to-right here.
112
+ > - Use shortcuts like `==, && , ??, ?, >, <, []` for `equals, and, or, then, less, greater, dot` functions respectively.
113
+ > - There is no operation priority, they applied in left-to-right order.
121
114
 
122
115
  ### `data-*` attributes
123
116
 
124
117
  All `data-[key]` attributes will be collected into single `data` object property under its keys.
125
118
 
126
- ## Left arrow expression
119
+ ### References.
127
120
 
128
- `data="<-ref.prop"` makes a hot subscription to any property of orbitrary component in upper scopes.
121
+ Add `Ref` attribute to any component to get refer it in `arrows` expressions.
129
122
 
130
- > may use pipes to adapt received value `data="<-ref.prop | adjustFn"`.
123
+ ```html
124
+ <UserService Ref="user" /> <UserAvatar data="<- user.profile" onSave="-> user.update" />
125
+ ```
131
126
 
132
- ## Right arrow expression
127
+ ## Left arrow expression
133
128
 
134
- ```html
135
- <button ... action="-> ref.key1" data-key="val" data="@data" />
129
+ `data="<- ref.prop"` makes a hot subscription to any property of orbitrary component in the current or upper scopes.
136
130
 
137
- <button ... action="-> ref.key1 = @value|pipe" />
138
- ```
131
+ > use pipes to adapt received value `data="<- ref.prop | adjustFn"`.
132
+
133
+ ## Right arrow expression
139
134
 
140
135
  Right arrow creates a function, that
141
136
 
142
- - `action="-> ref.key1"` invokes `upperScopes[ref].onKey1(data)` action handler with an `data` object as parameter.
137
+ - `action="data-> ref.submit(data)"` invokes `scope.refs[ref].submit(data)` action with an `data` object as parameter.
138
+
139
+ - `action="-> ref.submit(prop1)"` invokes `scope.refs[ref].submit(data)` action with a value of property `prop1` as parameter.
143
140
 
144
- - `action="-> ref.!prop1"` updates container state for given key `upperScopes[ref].up({ prop1: data })`.
141
+ - `action="-> ref.prop1"` updates container state for given key `scope.refs[ref].up({ prop1: data })`.
145
142
 
146
- > `action="-> ref.key1 = * | prepare"` pipes will be applied on `data`-object before it passed to the action handler .
143
+ > `action="data-> ref.action(data | prepare)` pipes will be applied on `data`-object before it passed to the action.
147
144
 
148
- > `click="-> @opened"` if `ref` is omitted, then a target will be a scope component `scope.up({opened:data})`
145
+ > `click="-> opened"` if `ref` is omitted, then a target will be a scope component `scope.up({opened:data})`
149
146
 
150
- > `click="-> ..."` will spread data to state of a scope component `scope.up(data)`
147
+ > `click="-> *"` will spread data to state of a scope component `scope.up(data)`
151
148
 
152
149
  #### Right arrows with inline payload
153
150
 
154
151
  Often, it is shorter to pass payload inline instead of using `data` property.
155
152
 
156
- - `click="->" data="@data | assignKeyValue:key:@value"` updates a scope properties with `data` object.
157
- - `click="-> prop" data="@data"` updates a given scope property of owner with `data` object.
158
- - `click="-> prop=literalValue"` updates a given scope property of owner with literal.
153
+ - `click="data-> * = data | assignKeyValue:'key':value"` updates a scope properties with `data` object.
154
+ - `click="-> prop" data="data"` updates a given scope property of owner with `data` object.
155
+ - `click="-> prop='literalValue'"` updates a given scope property of owner with literal.
156
+
157
+ ## Connector
158
+
159
+ Special build-in `Connector` component serves for async data binding
160
+ It acts with timeout(0 by default) and debounces if any:
161
+
162
+ ```html
163
+ <!-- `data` works as a `trigger`, if none specified. -->
164
+ <Connector data="<- todo.shownItems|adjust" change="-> someData" />
165
+
166
+ <!-- `change` is invokes with `data` on `trigger` changed. -->
167
+ <Connector
168
+ data="someData"
169
+ trigger="<- todo.shownItemsCount"
170
+ timeout="100"
171
+ change="data-> discriminant=data|calculate"
172
+ />
173
+ ```
159
174
 
160
175
  ## Slots
161
176
 
@@ -193,12 +208,12 @@ Inner content could be multiple-part and thus, distributed separately inside com
193
208
  <div class="component template">
194
209
 
195
210
  <!-- <Extra1/> will be placed here-->
196
- <Slot key="key1">
211
+ <Slot Key="key1">
197
212
 
198
213
  <!-- special `slot(key)` conditional expression may be used to check if non-empty slot content passed. -->
199
- <div class="comp" if="slot(key2)">
214
+ <div class="comp" If="slot(key2)">
200
215
  <!-- <Extra2/> will be placed here -->
201
- <Slot key="key2">
216
+ <Slot Key="key2">
202
217
  </div>
203
218
 
204
219
  <!-- <DefaultContent/> will be placed here -->
@@ -206,24 +221,18 @@ Inner content could be multiple-part and thus, distributed separately inside com
206
221
  </div>
207
222
  ```
208
223
 
209
- ### DOM support.
210
-
211
- You can provide life-cycle hooks for DOM element:
212
-
213
- ```html
214
- <div attached="initBehavior" detached="finalizeBehavior"></div>
215
- ```
216
-
217
224
  # Custom components
218
225
 
219
226
  There is a [Component] class that could be used an base ancestor for custom components.
220
227
 
221
- It allows
228
+ While designing custom components you can
222
229
 
223
230
  - to define life-cycle hooks;
224
231
  - to add getters/setter for its properties;
225
- - to define action handlers;
226
- - to use context methods like `up()`, `emit()`, `defer()`.
232
+ - to define `__getProperty(propName)` to return value of any property by its name
233
+ - to define `__stateChanged(changes)` to intercept appluing state changes
234
+ - to define action handlers like `doSomethig(data: any): object`, which may return a delta object for updating a component state;
235
+ - to use context methods like `up(delta)`, `emit('ref-target', data)`, `defer(fn)`.
227
236
 
228
237
  ```typescript
229
238
  class MyService extends Component {
@@ -252,6 +261,15 @@ class MyService extends Component {
252
261
  this.cancel();
253
262
  }
254
263
 
264
+ // to intercept getting of any property
265
+ __getProperty(key: string) {
266
+ this.log('getProperty', key)
267
+ return this[key]
268
+
269
+ // to intercept state changes
270
+ __stateChanged(changes: Map) {
271
+ }
272
+
255
273
  // property getter
256
274
  getSrc(){
257
275
  return this.url.toString()
@@ -268,7 +286,7 @@ class MyService extends Component {
268
286
  }
269
287
 
270
288
  // action handler. To be invoked with '-> ref.someAction' notation
271
- onSomeAction(data, T:This) {
289
+ onSomeAction(data: any) {
272
290
  if (asyncMode) {
273
291
  return promise.then(() => delta)
274
292
  }
@@ -279,7 +297,7 @@ class MyService extends Component {
279
297
  // async evaluation for 'prop'. 'Promise' postfix is optional.
280
298
  propPromise: T.fetchProp(),
281
299
  // async spread
282
- '*': Promise.resolve({
300
+ '...': Promise.resolve({
283
301
  prop1: 'val1'
284
302
  prop2: 'val2'
285
303
  })
@@ -288,7 +306,7 @@ class MyService extends Component {
288
306
 
289
307
  toast (message) {
290
308
  // emit action event
291
- this.emit('toasters.send', { message });
309
+ this.emit('toasters.onSend(data)', { message });
292
310
  };
293
311
  }
294
312
  ```
package/index.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { IEntitron, IPlatform } from "arrmatura/types";
1
+ import { IArrmatron, IPlatform } from "arrmatura/types";
2
+
2
3
  import { CRootNode } from "./src/registry/root";
3
4
 
4
5
  export * from "./src/registry";
@@ -10,10 +11,10 @@ export * from "./src/core/Component";
10
11
  *
11
12
  * @param {IPlatform} platform - The platform on which to launch the template.
12
13
  * @param {string} template - The template to launch with.
13
- * @return {IEntitron} The root context object.
14
+ * @return {IArrmatron} The root context object.
14
15
  */
15
- export const launch = (platform: IPlatform, template: string): IEntitron => {
16
- const root = new CRootNode(template).createEntitron(platform);
16
+ export const launch = (platform: IPlatform, template: string): IArrmatron => {
17
+ const root = new CRootNode(template).createArrmatron(platform);
17
18
 
18
19
  root.up({}, true);
19
20
 
package/package.json CHANGED
@@ -1,21 +1,27 @@
1
1
  {
2
2
  "name": "arrmatura",
3
- "version": "6.3.1",
3
+ "version": "6.3.2",
4
4
  "description": "Arrmatura runtime engine",
5
5
  "author": "alitskevich@gmail.com",
6
6
  "license": "ISC",
7
7
  "type": "module",
8
- "main": "./index.ts",
8
+ "exports": {
9
+ "import": "./index.ts",
10
+ "require": "./dist/index.js"
11
+ },
9
12
  "files": [
10
13
  "src",
14
+ "dist",
15
+ "index.ts",
11
16
  "types.ts",
12
17
  "docs/**/*"
13
18
  ],
14
19
  "dependencies": {
15
- "arrmatura": "6.3.1",
16
- "ultimus": "2.1.8"
20
+ "arrmatura": "6.3.2",
21
+ "ultimus": "2.1.10"
17
22
  },
18
23
  "scripts": {
24
+ "esbuild": "esbuild index.ts --bundle --outdir=./dist --platform=browser --format=esm --sourcemap --target=esnext --external:* --minify",
19
25
  "pnpm:publish": "pnpm publish --no-git-checks"
20
26
  }
21
27
  }