verstak 0.23.107 → 0.23.109

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
@@ -5,23 +5,44 @@
5
5
 
6
6
  # **Verstak** - Experimental Front-End Library
7
7
 
8
- Verstak is an experimental JavaScript library that provides
9
- chain-based an table-based layouts with
10
- [transactional reactive](https://blog.nezaboodka.com/post/2019/593-modern-database-should-natively-support-transactionally-reactive-programming)
11
- facilities for building front-end applications.
12
-
13
- Transactional reactivity means that state changes are being made in an
14
- isolated data snapshot and then, once atomically applied, are
15
- **consistently propagated** to corresponding visual components for
16
- (re)rendering. All that is done in automatic, seamless, and fine-grained
17
- way, because reactronic **takes full care of tracking dependencies**
18
- between visual components (observers) and state objects (observables).
19
-
20
- Based on Reactronic: https://github.com/nezaboodka/reactronic/blob/master/README.md#readme
21
-
22
- Example of the application built with Verstak: https://nevod.io
23
-
24
- Source code of the example: https://gitlab.com/nezaboodka/nevod.web.public/-/blob/master/README.md
8
+ Verstak is a experimental library for rapid development of user
9
+ interfaces. It provides **automatic refresh** of visual elements
10
+ upon change of underlying data in a program.
11
+
12
+ Refresh on the screen is **fine-grained**, meaning that only
13
+ those visual elements are refreshed, which really depend on
14
+ actual data changed. It is achieved by automatic tracking of
15
+ all dependencies between visual elements and data they use
16
+ during run time. Such an approach is usually called reactive
17
+ programming. It frees a programmer from writing boilerplate
18
+ code for "pushing" changed data to visual elements.
19
+
20
+ Changing of compound data and refreshing of visual elements
21
+ on the screen is performed consistently, in other words in
22
+ "all-or-nothing" way. It means that in case of changing
23
+ multiple variables in a program actual visual refresh
24
+ happens only in case of successful change of all the variables.
25
+ Partial changes are "not visible" to visual elements even
26
+ in case of exception or cancellation of changes. Such a
27
+ change of compound data in "all-or-nothing" way is called
28
+ a transaction.
29
+
30
+ Verstak supports asynchronous programming out of the box
31
+ at all the layers, including transactions and visual elements
32
+ rendering.
33
+
34
+ Altogether it is called reactive transactional programming.
35
+ Transactional reactivity means that state changes are being
36
+ made in an isolated data snapshot and then, once atomically
37
+ applied, are **consistently propagated** to corresponding
38
+ visual components for (re)rendering. All that is done in
39
+ automatic, seamless, and fine-grained way, because Verstak
40
+ **takes full care of tracking dependencies** between visual
41
+ components (observers) and state objects (observables).
42
+
43
+ Example application: https://nevod.io ([source code](https://gitlab.com/nezaboodka/nevod.web.public/-/blob/master/README.md)).
44
+
45
+ Verstak is based on [Reactronic](https://github.com/nezaboodka/reactronic/blob/master/README.md#readme).
25
46
 
26
47
  # Contribution
27
48
 
@@ -0,0 +1,134 @@
1
+ import { CollectionReader, Item, MemberOptions } from "reactronic";
2
+ export type Callback<T = unknown> = (native: T) => void;
3
+ export type Delegate<T = unknown, M = unknown, C = unknown, R = void> = (block: Block<T, M, C, R>, base: () => R) => R;
4
+ export type AsyncDelegate<T = unknown, M = unknown> = (block: Block<T, M, Promise<void>>) => Promise<void>;
5
+ export type SimpleDelegate<T = unknown> = (block: Block<T, any, any, any>) => void;
6
+ export declare enum BlockKind {
7
+ Band = 0,
8
+ Table = 1,
9
+ Note = 2,
10
+ Group = 3,
11
+ Row = 4,
12
+ Cursor = 5,
13
+ Native = 6
14
+ }
15
+ export interface Block<T = unknown, M = unknown, C = unknown, R = void> {
16
+ readonly descriptor: BlockDescriptor<T, M, C, R>;
17
+ readonly native: T;
18
+ readonly isBand: boolean;
19
+ readonly isTable: boolean;
20
+ model: M;
21
+ controller: C;
22
+ kind: BlockKind;
23
+ area: BlockArea;
24
+ widthGrowth: number;
25
+ minWidth: string;
26
+ maxWidth: string;
27
+ heightGrowth: number;
28
+ minHeight: string;
29
+ maxHeight: string;
30
+ contentAlignment: Align;
31
+ blockAlignment: Align;
32
+ contentWrapping: boolean;
33
+ overlayVisible: boolean | undefined;
34
+ childrenShuffling: boolean;
35
+ renderingPriority?: Priority;
36
+ isSequential: boolean;
37
+ readonly isInitialRendering: boolean;
38
+ useStyle(styleName: string, enabled?: boolean): void;
39
+ configureReactronic(options: Partial<MemberOptions>): MemberOptions;
40
+ }
41
+ export interface BlockDescriptor<T = unknown, M = unknown, C = unknown, R = void> {
42
+ readonly key: string;
43
+ readonly driver: Driver<T>;
44
+ readonly builder: Readonly<BlockBuilder<T, M, C, R>>;
45
+ readonly level: number;
46
+ readonly owner: Block;
47
+ readonly host: Block;
48
+ readonly children: CollectionReader<Block>;
49
+ readonly item: Item<Block> | undefined;
50
+ readonly stamp: number;
51
+ readonly outer: Block;
52
+ readonly context: BlockCtx | undefined;
53
+ }
54
+ export interface BlockBuilder<T = unknown, M = unknown, C = unknown, R = void> {
55
+ base?: BlockBuilder<T, M, C, R>;
56
+ key?: string;
57
+ mode?: Mode;
58
+ triggers?: unknown;
59
+ claim?: Delegate<T, M, C, R>;
60
+ create?: Delegate<T, M, C, R>;
61
+ initialize?: Delegate<T, M, C, R>;
62
+ render?: Delegate<T, M, C, R>;
63
+ finalize?: Delegate<T, M, C, R>;
64
+ }
65
+ export interface BlockCtx<T extends Object = Object> {
66
+ value: T;
67
+ }
68
+ export interface Driver<T, C = unknown> {
69
+ readonly name: string;
70
+ readonly isRow: boolean;
71
+ readonly preset?: SimpleDelegate<T>;
72
+ claim(block: Block<T, unknown, C>): void;
73
+ create(block: Block<T, unknown, C>, b: {
74
+ native?: T;
75
+ controller?: C;
76
+ }): void;
77
+ initialize(block: Block<T, unknown, C>): void;
78
+ mount(block: Block<T, unknown, C>): void;
79
+ render(block: Block<T, unknown, C>): void | Promise<void>;
80
+ finalize(block: Block<T, unknown, C>, isLeader: boolean): boolean;
81
+ applyKind(block: Block<T, any, C, any>, value: BlockKind): void;
82
+ applyCoords(block: Block<T, any, C, any>, value: BlockCoords | undefined): void;
83
+ applyWidthGrowth(block: Block<T, any, C, any>, value: number): void;
84
+ applyMinWidth(block: Block<T, any, C, any>, value: string): void;
85
+ applyMaxWidth(block: Block<T, any, C, any>, value: string): void;
86
+ applyHeightGrowth(block: Block<T, any, C, any>, value: number): void;
87
+ applyMinHeight(block: Block<T, any, C, any>, value: string): void;
88
+ applyMaxHeight(block: Block<T, any, C, any>, value: string): void;
89
+ applyContentAlignment(block: Block<T, any, C, any>, value: Align): void;
90
+ applyBlockAlignment(block: Block<T, any, C, any>, value: Align): void;
91
+ applyContentWrapping(block: Block<T, any, C, any>, value: boolean): void;
92
+ applyOverlayVisible(block: Block<T, any, C, any>, value: boolean | undefined): void;
93
+ applyStyle(block: Block<T, any, C, any>, secondary: boolean, styleName: string, enabled?: boolean): void;
94
+ }
95
+ export interface BlockCoords {
96
+ x1: number;
97
+ y1: number;
98
+ x2: number;
99
+ y2: number;
100
+ }
101
+ export declare const enum Priority {
102
+ Realtime = 0,
103
+ Normal = 1,
104
+ Background = 2
105
+ }
106
+ export declare enum Mode {
107
+ Default = 0,
108
+ PinpointRefresh = 1,
109
+ ManualMounting = 2
110
+ }
111
+ export declare enum Align {
112
+ Stretch = 0,
113
+ Left = 1,
114
+ CenterX = 2,
115
+ Right = 3,
116
+ Top = 4,
117
+ CenterY = 8,
118
+ Bottom = 12,
119
+ Default = 16,
120
+ Center = 10
121
+ }
122
+ export interface ElasticSize {
123
+ cells?: number;
124
+ min?: string;
125
+ max?: string;
126
+ growth?: number;
127
+ }
128
+ export interface TrackSize extends ElasticSize {
129
+ track?: string | number;
130
+ }
131
+ export type BlockArea = undefined | string | {
132
+ cellsOverWidth?: number;
133
+ cellsOverHeight?: number;
134
+ };
@@ -0,0 +1,34 @@
1
+ export var BlockKind;
2
+ (function (BlockKind) {
3
+ BlockKind[BlockKind["Band"] = 0] = "Band";
4
+ BlockKind[BlockKind["Table"] = 1] = "Table";
5
+ BlockKind[BlockKind["Note"] = 2] = "Note";
6
+ BlockKind[BlockKind["Group"] = 3] = "Group";
7
+ BlockKind[BlockKind["Row"] = 4] = "Row";
8
+ BlockKind[BlockKind["Cursor"] = 5] = "Cursor";
9
+ BlockKind[BlockKind["Native"] = 6] = "Native";
10
+ })(BlockKind || (BlockKind = {}));
11
+ export var Priority;
12
+ (function (Priority) {
13
+ Priority[Priority["Realtime"] = 0] = "Realtime";
14
+ Priority[Priority["Normal"] = 1] = "Normal";
15
+ Priority[Priority["Background"] = 2] = "Background";
16
+ })(Priority || (Priority = {}));
17
+ export var Mode;
18
+ (function (Mode) {
19
+ Mode[Mode["Default"] = 0] = "Default";
20
+ Mode[Mode["PinpointRefresh"] = 1] = "PinpointRefresh";
21
+ Mode[Mode["ManualMounting"] = 2] = "ManualMounting";
22
+ })(Mode || (Mode = {}));
23
+ export var Align;
24
+ (function (Align) {
25
+ Align[Align["Stretch"] = 0] = "Stretch";
26
+ Align[Align["Left"] = 1] = "Left";
27
+ Align[Align["CenterX"] = 2] = "CenterX";
28
+ Align[Align["Right"] = 3] = "Right";
29
+ Align[Align["Top"] = 4] = "Top";
30
+ Align[Align["CenterY"] = 8] = "CenterY";
31
+ Align[Align["Bottom"] = 12] = "Bottom";
32
+ Align[Align["Default"] = 16] = "Default";
33
+ Align[Align["Center"] = 10] = "Center";
34
+ })(Align || (Align = {}));
@@ -1,2 +1,8 @@
1
+ import { BlockCoords } from "./Interfaces";
2
+ export declare function parseBlockCoords(text: string, result: BlockCoords): BlockCoords;
3
+ export declare function emitBlockCoords(value: BlockCoords): string;
4
+ export declare function emitLetters(n: number): string;
5
+ export declare function emitCellPosition(x: number, y: number): string;
6
+ export declare function equalBlockCoords(a: BlockCoords, b: BlockCoords): boolean;
1
7
  export declare function objectHasMember<T>(obj: any, member: string): obj is T;
2
8
  export declare function getCallerInfo(prefix: string): string;
@@ -1,3 +1,179 @@
1
+ export function parseBlockCoords(text, result) {
2
+ let i = 0;
3
+ let value = 0;
4
+ let sign = 1;
5
+ let component = 0;
6
+ while (i < text.length) {
7
+ const charCode = text.charCodeAt(i);
8
+ if (isCapitalLetter(charCode)) {
9
+ if (component % 2 === 0)
10
+ value = value * 26 + charCode - 64;
11
+ else
12
+ console.error(`Digit is expected, but letter ('${text[i]}') was read`);
13
+ }
14
+ else if (isLowercaseLetter(charCode)) {
15
+ if (component % 2 === 0) {
16
+ value = value * 26 + charCode - 96;
17
+ }
18
+ else {
19
+ console.error(`Digit is expected, but letter ('${text[i]}') was read`);
20
+ }
21
+ }
22
+ else if (isDigit(charCode)) {
23
+ if (component % 2 === 0) {
24
+ if (value !== 0) {
25
+ if (component === 0)
26
+ result.x1 = value * sign;
27
+ else
28
+ result.x2 = value * sign;
29
+ value = 0;
30
+ }
31
+ component++;
32
+ }
33
+ value = value * 10 + charCode - 48;
34
+ }
35
+ else if (charCode === 40) {
36
+ if (component === 0)
37
+ result.x1 = value * sign;
38
+ else if (component === 2)
39
+ result.x2 = value * sign;
40
+ if (sign > 0) {
41
+ sign = -1;
42
+ component &= ~1;
43
+ value = 0;
44
+ }
45
+ else {
46
+ console.error("Sign must not be negative");
47
+ }
48
+ }
49
+ else if (charCode === 41) {
50
+ if (sign > 0) {
51
+ console.error("Sign must be negative");
52
+ }
53
+ switch (component) {
54
+ case 0:
55
+ result.x1 = value * sign;
56
+ break;
57
+ case 1:
58
+ result.y1 = value * sign;
59
+ break;
60
+ case 2:
61
+ result.x2 = value * sign;
62
+ break;
63
+ case 3:
64
+ result.y2 = value * sign;
65
+ break;
66
+ }
67
+ sign = 1;
68
+ value = 0;
69
+ component++;
70
+ }
71
+ else if (charCode === 58) {
72
+ if (sign < 0)
73
+ console.error(`area '${text}': e1`);
74
+ if (component === 1)
75
+ result.y1 = value * sign;
76
+ else if (component !== 2)
77
+ console.error(`area '${text}': [e2] component = ${component}`);
78
+ component = 2;
79
+ value = 0;
80
+ }
81
+ else if (isWhitespace(charCode)) {
82
+ }
83
+ else {
84
+ console.error(`Unknown symbol '${text[i]}' in '${text}'`);
85
+ }
86
+ i++;
87
+ }
88
+ if (value !== 0) {
89
+ switch (component) {
90
+ case 0: {
91
+ result.x1 = value * sign;
92
+ if (sign < 0 && result.y1 === 0)
93
+ result.y1 = sign;
94
+ break;
95
+ }
96
+ case 1: {
97
+ if (sign < 0 && result.x1 === 0)
98
+ result.x1 = sign;
99
+ result.y1 = value * sign;
100
+ break;
101
+ }
102
+ case 2: {
103
+ result.x2 = value * sign;
104
+ if (sign < 0 && result.y2 === 0)
105
+ result.y2 = sign;
106
+ break;
107
+ }
108
+ case 3: {
109
+ if (sign < 0 && result.x2 === 0)
110
+ result.x2 = sign;
111
+ result.y2 = value * sign;
112
+ break;
113
+ }
114
+ }
115
+ }
116
+ else if (sign < 0) {
117
+ if (component === 0) {
118
+ if (result.x1 === 0)
119
+ result.x1 = sign;
120
+ if (result.y1 === 0)
121
+ result.y1 = sign;
122
+ }
123
+ else {
124
+ if (result.x2 === 0)
125
+ result.x2 = sign;
126
+ if (result.y2 === 0)
127
+ result.y2 = sign;
128
+ }
129
+ }
130
+ return result;
131
+ }
132
+ export function emitBlockCoords(value) {
133
+ const p1 = emitCellPosition(value.x1, value.y1);
134
+ const p2 = emitCellPosition(value.x2, value.y2);
135
+ return `${p1}${p2 !== "" ? `:${p2}` : ""}`;
136
+ }
137
+ export function emitLetters(n) {
138
+ if (n < 0)
139
+ throw new Error(`emitLetters: argument (${n}) should not be negative or zero`);
140
+ let result = "";
141
+ while (n >= 0) {
142
+ const r = n % 26;
143
+ n = Math.floor(n / 26) - 1;
144
+ result = String.fromCharCode(65 + r) + result;
145
+ }
146
+ return result;
147
+ }
148
+ export function emitCellPosition(x, y) {
149
+ let result = "";
150
+ if (x > 0 && y > 0)
151
+ result = `${emitLetters(x - 1)}${y}`;
152
+ else if (x > 0 && y < 0)
153
+ result = `${emitLetters(x - 1)}(${-y})`;
154
+ else if (x < 0 && y > 0)
155
+ result = `(${emitLetters(-x - 1)})${y}`;
156
+ else if (x < 0 && y < 0)
157
+ result = `(${emitLetters(-x - 1)}${-y})`;
158
+ else
159
+ result = "";
160
+ return result;
161
+ }
162
+ export function equalBlockCoords(a, b) {
163
+ return a.x1 === b.x1 && a.y1 === b.y1 && a.x2 === b.x2 && a.y1 === b.y2;
164
+ }
165
+ function isWhitespace(char) {
166
+ return char === 32 || (char >= 9 && char <= 13) || char === 133 || char === 160;
167
+ }
168
+ function isDigit(input, index) {
169
+ return 48 <= input && input <= 57;
170
+ }
171
+ function isCapitalLetter(ch) {
172
+ return 65 <= ch && ch <= 90;
173
+ }
174
+ function isLowercaseLetter(ch) {
175
+ return 97 <= ch && ch <= 122;
176
+ }
1
177
  export function objectHasMember(obj, member) {
2
178
  return obj === Object(obj) && !Array.isArray(obj) && member in obj;
3
179
  }
@@ -0,0 +1,69 @@
1
+ import { LoggingOptions } from "reactronic";
2
+ import { BlockCoords, BlockKind, Priority, Align, BlockBuilder, Block, Driver, SimpleDelegate } from "./Interfaces";
3
+ export declare class Verstak {
4
+ static readonly shortFrameDuration = 16;
5
+ static readonly longFrameDuration = 300;
6
+ static currentRenderingPriority: Priority;
7
+ static frameDuration: number;
8
+ static claim<T = undefined, M = unknown, C = unknown, R = void>(driver: Driver<T>, builder?: BlockBuilder<T, M, C, R>, base?: BlockBuilder<T, M, C, R>): Block<T, M, C, R>;
9
+ static get block(): Block;
10
+ static renderNestedTreesThenDo(action: (error: unknown) => void): void;
11
+ static getDefaultLoggingOptions(): LoggingOptions | undefined;
12
+ static setDefaultLoggingOptions(logging?: LoggingOptions): void;
13
+ }
14
+ export declare class BaseDriver<T, C = unknown> implements Driver<T, C> {
15
+ readonly name: string;
16
+ readonly isRow: boolean;
17
+ readonly preset?: SimpleDelegate<T> | undefined;
18
+ static readonly fragment: BaseDriver<any, unknown>;
19
+ constructor(name: string, isRow: boolean, preset?: SimpleDelegate<T> | undefined);
20
+ claim(block: Block<T, unknown, C>): void;
21
+ create(block: Block<T, unknown, C>, b: {
22
+ native?: T;
23
+ controller?: C;
24
+ }): void;
25
+ initialize(block: Block<T, unknown, C>): void;
26
+ mount(block: Block<T, unknown, C>): void;
27
+ render(block: Block<T, unknown, C>): void | Promise<void>;
28
+ finalize(block: Block<T, unknown, C>, isLeader: boolean): boolean;
29
+ applyKind(block: Block<T, any, C, any>, value: BlockKind): void;
30
+ applyCoords(block: Block<T, any, C, any>, value: BlockCoords | undefined): void;
31
+ applyWidthGrowth(block: Block<T, any, C, any>, value: number): void;
32
+ applyMinWidth(block: Block<T, any, C, any>, value: string): void;
33
+ applyMaxWidth(block: Block<T, any, C, any>, value: string): void;
34
+ applyHeightGrowth(block: Block<T, any, C, any>, value: number): void;
35
+ applyMinHeight(block: Block<T, any, C, any>, value: string): void;
36
+ applyMaxHeight(block: Block<T, any, C, any>, value: string): void;
37
+ applyContentAlignment(block: Block<T, any, C, any>, value: Align): void;
38
+ applyBlockAlignment(block: Block<T, any, C, any>, value: Align): void;
39
+ applyContentWrapping(block: Block<T, any, C, any>, value: boolean): void;
40
+ applyOverlayVisible(block: Block<T, any, C, any>, value: boolean | undefined): void;
41
+ applyStyle(block: Block<T, any, C, any>, secondary: boolean, styleName: string, enabled?: boolean): void;
42
+ }
43
+ export declare class StaticDriver<T> extends BaseDriver<T> {
44
+ readonly element: T;
45
+ constructor(element: T, name: string, isRow: boolean, preset?: SimpleDelegate<T>);
46
+ create(block: Block<T, unknown, unknown, void>, b: {
47
+ native?: T;
48
+ controller?: unknown;
49
+ }): void;
50
+ }
51
+ export declare class CursorCommand {
52
+ absolute?: string;
53
+ columnShift?: number;
54
+ rowShift?: number;
55
+ }
56
+ export declare class CursorCommandDriver extends BaseDriver<CursorCommand, void> {
57
+ constructor();
58
+ create(block: Block<CursorCommand, unknown, void, void>, b: {
59
+ native?: CursorCommand;
60
+ controller?: void;
61
+ }): void;
62
+ }
63
+ export declare class ContextVariable<T extends Object = Object> {
64
+ readonly defaultValue: T | undefined;
65
+ constructor(defaultValue?: T);
66
+ set value(value: T);
67
+ get value(): T;
68
+ get valueOrUndefined(): T | undefined;
69
+ }