@dynamix-layout/core 0.0.2-beta.0

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.
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @file Element.ts
3
+ * @description Interface to create concrete class.
4
+ */
5
+ /**
6
+ * @interface INode
7
+ * @description Interface for Node.
8
+ * @property {Type} type : Type of Node (Row, Column, Tabset, Tab).
9
+ * @property {number} weight : Weight of Node.
10
+ * @property {[number,number]} dimension : Dimension of Node.
11
+ * @property {[number,number]} coordinate : Coordinate of Node.
12
+ * @property {Node | null} parent : Parent Node ( Node | null ).
13
+ * @property {Node[]} children : Children Node ( Node[] ).
14
+ * @property {Bond | null} prev : Previous Bond ( Bond | null ).
15
+ * @property {Bond | null} next : Next Bond ( Bond | null ).
16
+ *
17
+ */
18
+ export interface INode<T, K> {
19
+ type: TypeValue;
20
+ weight: number;
21
+ dimension: [number, number];
22
+ coordinate: [number, number];
23
+ parent: T | null;
24
+ children: T[];
25
+ prev: K | null;
26
+ next: K | null;
27
+ }
28
+ /**
29
+ * @interface IBond
30
+ * @description Interface for Bond.
31
+ * @property {Type} type : Type of Bond (Row, Column, Tabset, Tab).
32
+ * @property {Node} prev : Previous Node ( Node | null ).
33
+ * @property {Node} next : Next Node ( Node | null ).
34
+ * @property {[number,number]} dimension : Dimension of Bond.
35
+ * @property {[number,number]} coordinate : Coordinate of Bond.
36
+ *
37
+ */
38
+ export interface IBond<T> {
39
+ type: TypeValue;
40
+ prev: T;
41
+ next: T;
42
+ dimension: [number, number];
43
+ coordinate: [number, number];
44
+ }
45
+ /**
46
+ * @interface ILayout
47
+ * @description Interface for Layout.
48
+ * @property {Node} root : Root Node.
49
+ * @property {Node[]} tabs : Tabs Node.
50
+ * @property {Bond[]} bond : Bond between two components.
51
+ *
52
+ */
53
+ export interface ILayout<T, K> {
54
+ _root: T;
55
+ _tabs: T[];
56
+ _bond: K[];
57
+ }
58
+ /**
59
+ * @enum Type
60
+ * @description Enum for Type.
61
+ * @property {Row} Row : Row Type.
62
+ * @property {Column} Column : Column Type.
63
+ * @property {Tabset} Tabset : Tabset Type.
64
+ * @property {Tab} Tab : Tab Type.
65
+ */
66
+ export declare const Type: {
67
+ Row: number;
68
+ Column: number;
69
+ Tabset: number;
70
+ Tab: number;
71
+ };
72
+ /**
73
+ * @enum TypeValue : Value of Type.
74
+ */
75
+ export type TypeValue = number;
76
+ /**
77
+ * @enum Area
78
+ * @description Enum for Area.
79
+ * @property {Left} Left : Left Area.
80
+ * @property {Right} Right : Right Area.
81
+ * @property {Top} Top : Top Area.
82
+ * @property {Bottom} Bottom : Bottom Area.
83
+ * @property {Cover} Cover : Cover Area.
84
+ */
85
+ export declare const Area: {
86
+ Left: "left";
87
+ Right: "right";
88
+ Top: "top";
89
+ Bottom: "bottom";
90
+ Cover: "cover";
91
+ };
92
+ export type Left = "left";
93
+ export type Right = "right";
94
+ export type Top = "top";
95
+ export type Bottom = "bottom";
96
+ export type Cover = "cover";
97
+ export type AreaValue = typeof Area[keyof typeof Area];
98
+ export type LayoutTree = {
99
+ type: TypeValue;
100
+ weight: number;
101
+ children: LayoutTree[];
102
+ name: string;
103
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Methods
3
+ */
4
+ export interface IMethods {
5
+ }
@@ -0,0 +1,2 @@
1
+ export * from './Element';
2
+ export * from './Method';
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@dynamix-layout/core",
3
+ "version": "0.0.2-beta.0",
4
+ "description": "Dynamix Layout/Core is a JavaScript package for creating dynamic layouts with ease.",
5
+ "main": "dist/core.js",
6
+ "module": "dist/core.mjs",
7
+ "browser": "dist/core.iife.js",
8
+ "types": "dist/types/index.d.ts",
9
+ "typings": "dist/types/index.d.ts",
10
+ "funding": {
11
+ "type": "patreon",
12
+ "url": "https://www.patreon.com/Akash960"
13
+ },
14
+ "files": [
15
+ "src",
16
+ "dist",
17
+ "LICENSE",
18
+ "CHANGELOG.md",
19
+ "README.md"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/akash-aman/dynamix-layout.git"
24
+ },
25
+ "keywords": [
26
+ "dynamix-layout",
27
+ "ui",
28
+ "ux"
29
+ ],
30
+ "author": "Akash Aman",
31
+ "license": "MIT",
32
+ "devDependencies": {
33
+ "@changesets/cli": "^2.26.2",
34
+ "typescript": "^5.2.2",
35
+ "vite": "^4.4.9"
36
+ },
37
+ "dependencies": {
38
+ "@rollup/plugin-typescript": "^11.1.3",
39
+ "tslib": "^2.6.2"
40
+ },
41
+ "scripts": {
42
+ "build": "vite build",
43
+ "dev": "vite"
44
+ }
45
+ }
@@ -0,0 +1,291 @@
1
+ import { ILayout, Type, LayoutTree, AreaValue } from "../types";
2
+ import { Node, Bond, Helper } from "../lib";
3
+
4
+
5
+ export type LayoutOptions = {
6
+ layout?: LayoutTree,
7
+ range?: number,
8
+ dimension?: [number, number],
9
+ tabs?: string[],
10
+ }
11
+
12
+ export type Settings = {
13
+ layout: LayoutTree,
14
+ range: number,
15
+ dimension: [number, number],
16
+ coordinate: [number, number],
17
+ tabs: string[],
18
+ }
19
+
20
+ export default class Layout implements ILayout<Node, Bond> {
21
+ _root: Node;
22
+ _tabs: Node[];
23
+ _bond: Bond[];
24
+ _settings: Settings;
25
+ constructor(
26
+ options: LayoutOptions = {}
27
+ ) {
28
+
29
+ let setting = Object.assign({
30
+ layout: null,
31
+ range: 1,
32
+ dimension: [0, 0],
33
+ coordinate: [0, 0],
34
+ tabs: Array.from({ length: options.range ?? 1 }, (_, i) => `tab-${i + 1}`),
35
+ }, options);
36
+
37
+ this._tabs = [];
38
+ this._bond = [];
39
+ this._settings = setting;
40
+ this._root = new Node(Type.Row, 100, null);
41
+
42
+ this._root.coordinate = this._settings.coordinate;
43
+ this._root.dimension = this._settings.dimension;
44
+ this.createTree();
45
+ }
46
+
47
+ public shiftTree = (srcId: string, desId: string, area: AreaValue) => {
48
+
49
+ let des: any;
50
+ let src: any;
51
+
52
+ this._tabs.forEach((tab: Node) => {
53
+ if (tab.name == desId) des = tab;
54
+ if (tab.name == srcId) src = tab;
55
+ tab.children.forEach((child: Node) => {
56
+ if (child.name == desId) des = child;
57
+ if (child.name == srcId) src = child;
58
+ });
59
+ });
60
+
61
+ if (src === undefined || src === null) return;
62
+ if (des === undefined || des === null) return;
63
+
64
+ if (src.parent === null) return;
65
+
66
+ const length = src.parent.children.length;
67
+
68
+ if (des.type == Type.Tabset && src.type == Type.Tab) {
69
+ Helper.detach(src, length > 1);
70
+ Helper.attach(des, src, area);
71
+
72
+ } else if (des.type == Type.Tabset && src.type == Type.Tabset) {
73
+ Helper.detach(src, length > 2);
74
+ Helper.attach(des, src, area);
75
+ }
76
+
77
+ return this.calculate(this._root, 0);
78
+ }
79
+
80
+ private createTree = () => {
81
+ const { layout } = this._settings;
82
+
83
+ if (!layout) {
84
+ Helper.createBinaryTree(this._root, this._settings);
85
+ console.log("create tree",JSON.stringify(this.jsonify()));
86
+
87
+ return this.updateTree();
88
+ }
89
+
90
+ const queue: LayoutTree[] = [layout];
91
+ const _queue: Node[] = [this._root];
92
+
93
+ const levels: LayoutTree[][] = [];
94
+ let toggle = 1;
95
+
96
+ while (queue.length) {
97
+ const level: LayoutTree[] = [];
98
+ const range = queue.length;
99
+
100
+ for (let i = 0; i < range; i++) {
101
+
102
+ const parent = queue.shift();
103
+ const _parent = _queue.shift();
104
+
105
+ if (parent) {
106
+ level.push(parent);
107
+ parent.children.forEach((child: LayoutTree, index: number) => {
108
+ queue.push(child);
109
+ _queue.push(
110
+ new Node(child.type, child.weight, _parent ?? null)
111
+ );
112
+
113
+ _parent?.children.push(_queue[_queue.length - 1]);
114
+
115
+ if (index == 0) return;
116
+
117
+ new Bond(
118
+ child.type,
119
+ _queue[_queue.length - 2],
120
+ _queue[_queue.length - 1],
121
+ );
122
+ });
123
+ }
124
+ }
125
+
126
+ levels.push(level);
127
+ toggle = 1 - toggle;
128
+ }
129
+
130
+ this.updateTree();
131
+ return this;
132
+ }
133
+
134
+ public updateTree = (width?: number, height?: number, hook?: Function) => {
135
+
136
+ if (width && height) {
137
+ this._root.dimension = [width, height];
138
+ }
139
+
140
+ const queue: Node[] = [this._root];
141
+
142
+ const levels: any[][] = [];
143
+ let toggle = 1;
144
+
145
+ this._bond = [];
146
+ this._tabs = [];
147
+
148
+ while (queue.length) {
149
+ const level: any[] = [];
150
+ const range = queue.length;
151
+
152
+ for (let i = 0; i < range; i++) {
153
+
154
+ const parent = queue.shift() as Node;
155
+
156
+ const size = Helper.getSize(parent);
157
+ const weight = Helper.getTotalWeight(parent);
158
+
159
+ let percent = 0;
160
+ let sum = 0;
161
+ let prev = parent.children[0];
162
+ const dimension = parent.dimension
163
+ const coordinate = parent.coordinate
164
+
165
+ if (parent) {
166
+ level.push(parent.coordinate);
167
+ if (parent.type == Type.Tabset) {
168
+ this._tabs.push(parent);
169
+ }
170
+
171
+ parent.children.forEach((child: Node, index: number) => {
172
+ queue.push(child);
173
+ child.dimension = [...dimension];
174
+ child.coordinate = [...coordinate];
175
+
176
+ child.weight = (child.weight / weight) * 100;
177
+ if (index === parent.children.length - 1) {
178
+ child.dimension[parent.type] = size - sum;
179
+ child.weight = 100 - percent;
180
+ } else {
181
+ child.weight = (child.weight / weight) * 100;
182
+ const dmn = size * (child.weight / 100);
183
+ child.dimension[parent.type] = dmn;
184
+ percent += child.weight;
185
+ sum += child.dimension[parent.type];
186
+ }
187
+
188
+ child.dimension[parent.type] = child.dimension[parent.type];
189
+
190
+ if (!child.prev) return;
191
+ child.coordinate[parent.type] =
192
+ prev.coordinate[parent.type] +
193
+ prev.dimension[parent.type] + 8;
194
+
195
+ child.prev.dimension = [...dimension];
196
+ child.prev.coordinate = [...coordinate];
197
+ child.prev.dimension[parent.type] = 8;
198
+
199
+ child.prev.coordinate[parent.type] =
200
+ prev.coordinate[parent.type] +
201
+ prev.dimension[parent.type];
202
+
203
+ child.prev.type = 1 - parent.type;
204
+ prev = child;
205
+ this._bond.push(child.prev);
206
+ });
207
+ }
208
+ }
209
+
210
+ levels.push(level);
211
+ toggle = 1 - toggle;
212
+ }
213
+
214
+ if (hook) hook();
215
+
216
+ return this.getElements();
217
+
218
+ }
219
+
220
+ calculate(node: Node, level = 0) {
221
+
222
+ if (level == 0) {
223
+ this._bond = [];
224
+ this._tabs = [];
225
+ }
226
+
227
+ const reducedSize = Helper.getSize(node);
228
+ const totalWeight = Helper.getTotalWeight(node);
229
+
230
+ let prev = node.children[0];
231
+ let sum = 0;
232
+ let prcnt = 0;
233
+
234
+ if (node.type == Type.Tabset) {
235
+ this._tabs.push(node);
236
+ }
237
+
238
+ node.children.forEach((child, index) => {
239
+
240
+ child.dimension = [...node.dimension];
241
+ child.coordinate = [...node.coordinate];
242
+
243
+ if (index === node.children.length - 1) {
244
+ child.dimension[node.type] = reducedSize - sum;
245
+ child.weight = 100 - prcnt;
246
+ } else {
247
+ child.weight = (child.weight / totalWeight) * 100;
248
+ child.dimension[node.type] = reducedSize * (child.weight / 100);
249
+ prcnt += child.weight;
250
+ sum += child.dimension[node.type];
251
+ }
252
+
253
+ if (index === 0) return;
254
+
255
+ child.coordinate[node.type] = prev.coordinate[node.type] + prev.dimension[node.type] + 8;
256
+
257
+ if (child.prev) {
258
+
259
+ child.prev.dimension = [...node.dimension];
260
+ child.prev.coordinate = [...node.coordinate];
261
+ child.prev.dimension[node.type] = 8;
262
+ child.prev.coordinate[node.type] = prev.coordinate[node.type] + prev.dimension[node.type];
263
+
264
+ this._bond.push(child.prev);
265
+ }
266
+
267
+ prev = child;
268
+ });
269
+
270
+ if (node.type == Type.Tabset) {
271
+ this._tabs.push(node);
272
+ }
273
+ node.children.forEach((child) => {
274
+ if (child.children.length) {
275
+ this.calculate(child, level + 1);
276
+ }
277
+ });
278
+
279
+ }
280
+
281
+ public getElements = () => {
282
+ return {
283
+ tabs: this._tabs.map((tab: Node) => Helper.json(tab)),
284
+ bonds: this._bond.map((bond: Bond) => Helper.json(bond))
285
+ };
286
+ }
287
+
288
+ public jsonify = () => {
289
+ return Helper.json(this._root)
290
+ }
291
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ import Layout from './app'
2
+
3
+ export default Layout
@@ -0,0 +1,17 @@
1
+ import { Type } from '../types';
2
+
3
+ export const AreaType = {
4
+ top: Type.Row,
5
+ left: Type.Column,
6
+ right: Type.Column,
7
+ bottom: Type.Row,
8
+ cover: Type.Tab
9
+ }
10
+
11
+ export const AreaIndex = {
12
+ top: 0,
13
+ left: 0,
14
+ right: 1,
15
+ bottom: 1,
16
+ cover : 0
17
+ }
@@ -0,0 +1,66 @@
1
+ import {
2
+ INode,
3
+ IBond,
4
+ TypeValue,
5
+ } from '../types';
6
+
7
+ export class Node implements INode<Node,Bond> {
8
+ type: TypeValue;
9
+ name: string | null;
10
+ weight: number;
11
+
12
+ parent: Node | null;
13
+ children: Node[];
14
+
15
+ dimension: [number,number];
16
+ coordinate: [number,number];
17
+
18
+ prev: Bond | null;
19
+ next: Bond | null;
20
+ constructor(
21
+ type: TypeValue,
22
+
23
+ weight: number,
24
+ parent: Node | null
25
+ ) {
26
+ this.type = type;
27
+ this.name = null;
28
+ this.parent = parent;
29
+ this.weight = weight;
30
+
31
+ this.children = [];
32
+ this.dimension = [0,0];
33
+ this.coordinate = [0,0];
34
+ this.prev = null;
35
+ this.next = null;
36
+ }
37
+ }
38
+
39
+ export class Bond implements IBond<Node> {
40
+ type: TypeValue;
41
+ name: string | null;
42
+
43
+ prev: Node;
44
+ next: Node;
45
+
46
+ dimension: [number,number];
47
+ coordinate: [number,number];
48
+
49
+ constructor(
50
+ type: TypeValue,
51
+
52
+ prev: Node,
53
+ next: Node,
54
+ ) {
55
+ this.type = type;
56
+ this.prev = prev;
57
+ this.next = next;
58
+ this.name = `${prev.name}-${next.name}`;
59
+ this.dimension = [0,0];
60
+ this.coordinate = [0,0];
61
+
62
+ prev.next = this;
63
+ next.prev = this;
64
+ }
65
+ }
66
+