cradova 2.2.3 → 2.3.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.
package/README.md CHANGED
@@ -49,15 +49,16 @@ Cradova follows the [VJS specification](https://github.com/fridaycandour/cradova
49
49
 
50
50
  Cradova is aimed to be fast and simple with and fewer abstractions and yet easily composable.
51
51
 
52
- Cradova does't rely on visual DOM or diff algorithms to manage the DOM, instead, State management is done more elegantly with a simple predictive model, manually and easily with all the speed.
52
+ Cradova is not built on visual DOM or diff algorithms.
53
+ Instead, State management is done more elegantly with a simple predictive model, simple and easy with all the speed.
53
54
 
54
- ### is this a big benefit?
55
+ ## Is this a big benefit?
55
56
 
56
- Undoubtedly, this provides a significant advantage. You can experience it firsthand and decide for yourself.
57
+ Undoubtedly, this provides a significant advantage. You can experience it firsthand and decide.
57
58
 
58
59
  Cradova has already been utilized in multiple production projects, and we will continuously update this page to showcase our advancements as we keep improving.
59
60
 
60
- [current version changes](https://github.com/fridaycandour/cradova/blob/main/CHANGELOG.md#v220)
61
+ [current version changes](https://github.com/fridaycandour/cradova/blob/main/CHANGELOG.md#v230)
61
62
 
62
63
  ## Installation
63
64
 
@@ -83,12 +84,10 @@ npm i cradova
83
84
 
84
85
  Many aspects of Cradova are not reflected in the following example. More functionality will be entailed in future docs.
85
86
 
86
- Here's an example of create a basic component in Cradova:
87
+ ## A basic component in Cradova:
87
88
 
88
89
  ```js
89
- // cradova v2.0.0 comes with all html tags prebuilt and fully typed
90
- // this gives your app more performance gain.
91
- import _, { h1 } from "cradova";
90
+ import { div, h1 } from "cradova";
92
91
 
93
92
  function Hello(name) {
94
93
  return h1("Hello " + name, {
@@ -99,88 +98,21 @@ function Hello(name) {
99
98
  });
100
99
  }
101
100
 
102
- // document fragment empty cradova call _()
103
-
104
- const html = _(Hello("peter"), Hello("joe"));
101
+ const html = div(Hello("peter"), Hello("joe"));
105
102
 
106
103
  document.body.append(html);
107
104
  ```
108
105
 
109
- ```js
110
- // regular example
111
- import _ from "cradova";
112
-
113
- function Hello(name) {
114
- return _("h1", "Hello " + name);
115
- }
116
-
117
- const html = _(Hello("peter"), Hello("joe"));
118
-
119
- document.body.append(html);
120
- ```
106
+ ## working with state:
121
107
 
122
- ## Using Screen
108
+ this a collection of basic examples
109
+ you can choose any that best suite what problem you want to solve
123
110
 
124
111
  ```js
125
- import _, { Screen, Router } from "cradova";
126
-
127
- function HelloMessage(name) {
128
- // an effect run once after screen renders
129
- this.effect(() => {
130
- const name = new Promise((res) => {
131
- res("friday");
132
- });
133
- this.updateState(await name)
134
- });
135
- // effects can be used to make api calls needed for the page
136
- return _("div", "Hello " + name);
137
- }
138
-
139
-
140
- /*
141
-
142
- when using router and screens
143
-
144
- cradova will create a div with data-cra-id=cradova-app-wrapper
145
-
146
- if it already exist cradova will use it instead
112
+ import _, { button, createSignal, Ref, reference, h1, br, div } from "cradova";
147
113
 
148
- so if you want to use your own mount point then create a div with data-cra-id="cradova-app-wrapper"
149
-
150
- */
151
-
152
- const home = new Screen({
153
- name: "hello page", // page title
154
- template: HelloMessage,
155
- ...
156
- });
157
-
158
- Router.route("/", home);
159
-
160
- // navigates to that page
161
- // Router.navigate("/home", data, force);
162
- // get the page ready in the background
163
- // Router.packageScreen("/home");
164
- // get route params for this page
165
- // Router.getParams();
166
-
167
- ```
168
-
169
- ## State management
170
-
171
- ```js
172
-
173
-
174
- // element can have this.updateState when the shouldUpdate props is true
175
-
176
- // Ref components
177
-
178
- // state can be managed from a store when using createSignal or simpleStores
179
- // this method is not yet documented
180
-
181
- import _, { Ref } from "cradova";
182
-
183
- // simple count
114
+ // setting shouldUpdate to true
115
+ // gives you this.updateState binding
184
116
 
185
117
  function counter() {
186
118
  let num = 0;
@@ -193,32 +125,42 @@ function counter() {
193
125
  });
194
126
  }
195
127
 
128
+ // Another example with data- attribute
129
+
196
130
  function dataCounter() {
197
131
  return _("h1| 0", {
198
132
  shouldUpdate: true,
199
133
  "data-num": "0",
200
134
  onclick() {
201
- const num = Number(this.getAttribute("data-num")) + 1;
202
- this.updateState({ text: num, $num: num });
135
+ const num = this.getAttribute("data-num") * 1 + 1;
136
+ this.updateState({ text: num, "data-num": num });
203
137
  },
204
138
  });
205
139
  }
206
140
 
207
- function HelloMessage(name = "no name") {
208
- return _("div.foo#bar", {
141
+ // hello message
142
+
143
+ function HelloMessage() {
144
+ return div({
209
145
  shouldUpdate: true,
210
- text: "hello " + name,
146
+ text: "Click to get a greeting",
211
147
  onclick() {
212
148
  const name = prompt("what are your names");
213
- this.updateState({ text: "hello " + name });
149
+ this.updateState({
150
+ text: name ? "hello " + name : "Click to get a greeting",
151
+ });
214
152
  },
215
153
  });
216
154
  }
217
155
 
218
- const nameRef = new Ref(function ( name ) {
156
+ // using cradova Ref
157
+
158
+ const nameRef = new Ref(function (name) {
219
159
  const self = this;
220
160
  return _("div.foo#bar", {
221
- text: "hello" + (name || "no name"),
161
+ text: name
162
+ ? "hello " + (name || " user 2")
163
+ : "Click to get a second greeting",
222
164
  onclick() {
223
165
  const name = prompt();
224
166
  self.updateState(name);
@@ -226,62 +168,267 @@ const nameRef = new Ref(function ( name ) {
226
168
  });
227
169
  });
228
170
 
229
- /*
230
- cradova Ref are component objects
231
- with methods for rendering, pre-rendering, and updating a it dom elements.
171
+ // reference (not state)
172
+
173
+ function typingExample() {
174
+ const re = new reference();
175
+ return _(
176
+ "div",
177
+ input({
178
+ oninput() {
179
+ re.text.innerText = this.value;
180
+ },
181
+ placeholder: "typing simulation",
182
+ }),
183
+ p(" no thing typed yet!", { reference: re.bindAs("text") })
184
+ );
185
+ }
232
186
 
233
- Ref also has the feature to stash input values need by the components
187
+ function App() {
188
+ return div(counter, dataCounter, HelloMessage, br, nameRef);
189
+ }
190
+
191
+ // add your app to the DOM
234
192
 
235
- */
193
+ document.body.append(App());
194
+ ```
236
195
 
196
+ ## Simple Todo list
197
+
198
+ Let's see a simple TodoList example
199
+
200
+ ```js
201
+ import _, {
202
+ button,
203
+ createSignal,
204
+ css,
205
+ div,
206
+ input,
207
+ main,
208
+ p,
209
+ Ref,
210
+ reference,
211
+ } from "cradova";
212
+
213
+ function TodoList() {
214
+ // can be used to hold multiple references
215
+ const referenceSet = new reference();
216
+
217
+ // creating a store
218
+ const todoStore = new createSignal([
219
+ "take bath",
220
+ "code code code",
221
+ "take a break",
222
+ ]);
223
+
224
+ // create actions
225
+ todoStore.createAction("add-todo", function (todo) {
226
+ this.set([...this.value, todo]);
227
+ });
228
+
229
+ todoStore.createAction("remove-todo", function (todo) {
230
+ const ind = this.value.indexOf(todo);
231
+ this.value.splice(ind, 1);
232
+ this.set(this.value);
233
+ });
237
234
 
238
- function Home() {
239
- return _("div.foo#bar",
240
- counter,
241
- dataCounter,
242
- HelloMessage,
243
- nameRef.render( "no name" )
235
+ // bind Ref to Signal
236
+ todoStore.bindRef(todoList);
237
+
238
+ // markup
239
+ return main(
240
+ _`|Todo List`,
241
+ div(
242
+ input({
243
+ placeholder: "type in todo",
244
+ reference: referenceSet.bindAs("todoInput"),
245
+ }),
246
+ button("Add todo", {
247
+ onclick() {
248
+ todoStore.fireAction("add-todo", referenceSet.todoInput.value);
249
+ referenceSet.todoInput.value = "";
250
+ },
251
+ })
252
+ ),
253
+ todoList.render
244
254
  );
245
255
  }
246
256
 
257
+ const todoList = new Ref(function () {
258
+ const self = this;
259
+ return div(
260
+ self.Signal.value.map((item) =>
261
+ p(item, {
262
+ title: "click to remove",
263
+ onclick() {
264
+ self.Signal.fireAction("remove-todo", item);
265
+ },
266
+ })
267
+ )
268
+ );
269
+ });
270
+
271
+ document.body.appendChild(TodoList());
272
+
273
+ css`
274
+ body {
275
+ box-sizing: border-box;
276
+ display: flex;
277
+ }
278
+ main {
279
+ margin: auto;
280
+ }
281
+ main > p {
282
+ font-size: 2rem;
283
+ }
284
+ `;
285
+ ```
286
+
287
+ ## working with screen and Router:
288
+
289
+ unlike just appending stuff to the DOM,
290
+ a better to build apps is to use a routing system.
291
+
292
+ Cradova Router is a module that allows you do the following:
293
+
294
+ Create specified routes in you application
295
+ help you orchestrate navigation
296
+ render a screen on a route
297
+ pre-render a screen in the background if you want to.
298
+ listen to Navigation changes
299
+ create error boundary at screen level.
300
+ persist rendered screens by default
301
+ allow parallel screen rendering for every unique route scheme
302
+
303
+ let's try an example.
304
+
305
+ ```js
306
+ import _, { Screen, Router } from "cradova";
307
+
308
+ // Ref can be used as screens
309
+
310
+ const template = new Ref(function (name) {
311
+ // an effect run once after screen renders
312
+ const self = this;
313
+ self.effect(() => {
314
+ const name = new Promise((res) => {
315
+ res("john doe");
316
+ });
317
+ setTimeout(async () => {
318
+ self.updateState(await name);
319
+ }, 1000);
320
+ });
321
+ // effects can be used to make api calls needed for the page
322
+ return _("div", name ? ">>>>>>>> Hello " + name : " loading...");
323
+ });
324
+
247
325
  const home = new Screen({
248
326
  name: "home page", // page title
249
- template: Home,
250
- ...
327
+ template,
328
+ });
329
+
330
+ // in your routes.ts file
331
+ Router.BrowserRoutes({
332
+ "/home": home,
333
+ "/lazy-loaded-home": async () => await import("./home"),
334
+ });
335
+ // creates these routes
336
+
337
+ Router.packageScreen("/home", data);
338
+ // get the page ready in the background
339
+
340
+ Router.navigate("/home", data);
341
+ // navigates to that page
342
+
343
+ Router.getParams();
344
+ // get route params for this current page
345
+
346
+ Router.onPageEvent((lastRoute, newRoute) => {
347
+ console.log(lastRoute, newRoute);
251
348
  });
349
+ // listen for navigation changes
350
+ ```
351
+
352
+ ### More info
353
+
354
+ ---
355
+
356
+ More info on cradova Router
357
+
358
+ ---
359
+
360
+ Every cradova app mounts on a div with attribute data-wrapper="app"
361
+
362
+ if it already exist cradova will use it instead.
363
+
364
+ cradova will create a div with data-wrapper="app" if it doesn't exists already.
365
+
366
+ so if you want to use your own mount point then create a div with data-wrapper="app".
367
+
368
+ ---
252
369
 
253
- /*
370
+ More info on cradova screens
254
371
 
255
- Nice things about cradova screens
372
+ ---
256
373
 
257
374
  screens are rendered once by default to hack
258
375
  responsiveness making your app work fast as user navigates.
259
376
 
260
377
  this behavior can be override
261
378
  by passing
262
- prerender: false
379
+ persist: false
263
380
  in the constructor
264
381
 
265
-
266
382
  Cradova screens has
267
383
  onActivate() and
268
- onDeactivate() methods
384
+ onDeactivate() methods which is also available in the
385
+ component function on the this variable bound to it.
269
386
 
270
- these allow you manage rendering
271
- circle for each in your app
387
+ this allow you manage rendering
388
+ circle for each screen in your app
272
389
 
273
- */
390
+ ---
274
391
 
275
- Router.route("/", home);
276
- ```
392
+ More info on cradova Ref
393
+
394
+ ---
395
+
396
+ Refs are dynamic components, they have simple abstractions like:
397
+
398
+ - Effects
399
+ - stash
400
+ - preRender
401
+ - updateState
402
+
403
+ these behaviors allow you manage rendering
404
+ circle for refs in your app
405
+
406
+ ---
407
+
408
+ More info on cradova createSignal
409
+
410
+ ---
411
+
412
+ Cradova Signals allows you to create powerful data stores.
413
+
414
+ with ability to:
415
+
416
+ - create store
417
+ - create actions and fire them
418
+ - bind a Ref
419
+ - listen to changes
420
+ - persist changes to localStorage
421
+ - update a cradova Ref and bindings automatically
422
+
423
+ With these simple and easy abstractions, you can use datastores with powerful convenience.
277
424
 
278
425
  ## Documentation
279
426
 
280
- At the moment, we're in the process of creating documentation for Cradova, and we have limited resources. If you're interested in lending a hand, we invite you to join our community, gain firsthand experience, and contribute to the advancement of Cradova.
427
+ At the moment, we're in the process of creating a documentation website for Cradova, and we have limited resources. If you're interested in lending a hand, we invite you to join our community, gain firsthand experience, and contribute to the advancement of Cradova.
281
428
 
282
429
  ## Getting Help
283
430
 
284
- To get further insights and help on Cradova, visit our new [Telegram Community Chat](https://t.me/cradovaframework).
431
+ To get further insights and help on Cradova, visit our [Discord](https://discord.gg/b7fvMg38) and [Telegram](https://t.me/cradovaframework) Community Chats.
285
432
 
286
433
  ## Contributing
287
434
 
package/dist/index.d.ts CHANGED
@@ -11,9 +11,9 @@ declare module "cradova" {
11
11
  beforeMount?: () => void;
12
12
  afterMount?: () => void;
13
13
  text?: string;
14
+ reference?: any;
14
15
  stateID?: string;
15
16
  shouldUpdate?: boolean;
16
- assert?: any;
17
17
  }
18
18
  )[]
19
19
  ) => T;
@@ -80,10 +80,6 @@ declare module "cradova" {
80
80
  persist?: boolean;
81
81
  };
82
82
 
83
- export const makeElement: (
84
- element: Record<string, any>,
85
- ...ElementChildrenAndPropertyList: ElementType<HTMLElement>[]
86
- ) => Record<string, any>;
87
83
  export const a: ElementType<HTMLAnchorElement>;
88
84
  export const abbr: ElementType<HTMLElement>;
89
85
  export const address: ElementType<HTMLElement>;
@@ -150,7 +146,6 @@ declare module "cradova" {
150
146
  export const meta: ElementType<HTMLMetaElement>;
151
147
  export const meter: ElementType<HTMLMeterElement>;
152
148
  export const nav: ElementType<HTMLElement>;
153
- export const noscript: ElementType<HTMLElement>;
154
149
  export const object: ElementType<HTMLObjectElement>;
155
150
  export const ol: ElementType<HTMLOListElement>;
156
151
  export const optgroup: ElementType<HTMLOptGroupElement>;
@@ -222,32 +217,16 @@ declare module "cradova" {
222
217
  ): Promise<unknown>;
223
218
 
224
219
  /**
225
- * Cradova afterMount event
220
+ * Cradova event
226
221
  */
227
- export let cradovaAftermountEvent: CustomEvent<unknown>;
228
- /**
229
- Write CSS styles in Javascript
230
- @example
231
-
232
- css("#container",
233
- {
234
- height: "100%",
235
- height: "100%",
236
- background-color: "#ff9800"
237
- })
238
-
239
- css(".btn:hover",
240
- {
241
- height: "100%",
242
- height: "100%",
243
- background-color: "#ff9800"
244
- })
245
-
246
- */
247
- export function css(
248
- identifier: string,
249
- properties?: Record<string, string>
250
- ): void;
222
+ export class cradovaEvent {
223
+ private listeners;
224
+ addEventListener(eventName: string, callback: any): void;
225
+ removeEventListener(eventName: string, callback: any): void;
226
+ dispatchEvent(eventName: string, eventArgs?: any): void;
227
+ }
228
+ export const CradovaEvent: cradovaEvent;
229
+ export function css(identifier: string | TemplateStringsArray): void;
251
230
  /**
252
231
  *
253
232
  * @param {expression} condition
@@ -271,13 +250,14 @@ css(".btn:hover",
271
250
  type RefProps<D> = D | any;
272
251
  export class Ref<D> {
273
252
  private component;
274
- private stateID;
275
253
  private effects;
276
254
  private effectuate;
277
255
  private rendered;
278
256
  private published;
279
257
  private hasFirstStateUpdateRun;
280
258
  private preRendered;
259
+ private reference;
260
+ Signal: createSignal<any> | undefined;
281
261
  stash: D | undefined;
282
262
  constructor(component: (data?: RefProps<D>) => any);
283
263
  preRender(data?: RefProps<D>): void;
@@ -290,7 +270,8 @@ css(".btn:hover",
290
270
  * @returns () => HTMLElement
291
271
  */
292
272
  render(data?: D, stash?: boolean): HTMLElement;
293
- instance(): any;
273
+ instance(): Record<string, any>;
274
+ _setExtra(Extra: createSignal<any>): void;
294
275
  /**
295
276
  * Cradova Ref
296
277
  * ---
@@ -324,6 +305,12 @@ css(".btn:hover",
324
305
  constructor(cb: () => Promise<any>);
325
306
  load(): Promise<void>;
326
307
  }
308
+ export class reference {
309
+ [x: string]: Record<string, any>;
310
+ bindAs(name: string): any;
311
+ _appendDom(name: string, Element: any): void;
312
+ _appendDomForce(name: string, Element: any): void;
313
+ }
327
314
 
328
315
  /**
329
316
  * Cradova Signal
@@ -391,11 +378,11 @@ css(".btn:hover",
391
378
  * @param key - string key of the action
392
379
  * @param data - data for the action
393
380
  */
394
- fireAction(key: string, data?: Type): void;
381
+ fireAction(key: string, data?: unknown): void;
395
382
  /**
396
383
  * Cradova
397
384
  * ---
398
- * is used to bind store data to an element
385
+ * is used to bind store data to any element
399
386
  *
400
387
  * @param prop
401
388
  * @returns something
@@ -412,7 +399,7 @@ css(".btn:hover",
412
399
  */
413
400
  bindRef(
414
401
  ref: any,
415
- binding: {
402
+ binding?: {
416
403
  event?: string;
417
404
  signalProperty: string;
418
405
  _element_property: string;
@@ -458,13 +445,75 @@ css(".btn:hover",
458
445
  state?: stateType
459
446
  ): any;
460
447
 
461
- /**
462
- * Cradova Router
448
+ /** cradova router
463
449
  * ---
464
- * Facilitates navigation within the application and initializes
465
- * page views based on the matched routes.
450
+ * Registers a route.
451
+ *
452
+ * @param {string} path Route path.
453
+ * @param {any} screen the cradova document tree for the route.
466
454
  */
467
- export const Router: Record<string, any>;
455
+ class RouterClass {
456
+ /** cradova router
457
+ * ---
458
+ * Registers a route.
459
+ *
460
+ * accepts an object containing
461
+ *
462
+ * @param {string} path Route path.
463
+ * @param {any} screen the cradova screen.
464
+ */
465
+ BrowserRoutes(obj: Record<string, any>): void;
466
+ /**
467
+ * Cradova Router
468
+ * ------
469
+ *
470
+ * Navigates to a designated screen in your app
471
+ *
472
+ * @param href string
473
+ * @param data object
474
+ * @param force boolean
475
+ */
476
+ navigate(
477
+ href: string,
478
+ data?: Record<string, any> | null,
479
+ force?: boolean
480
+ ): void;
481
+ /** cradova router
482
+ * ---
483
+ * Listen for navigation events
484
+ *
485
+ * @param callback () => void
486
+ */
487
+ onPageEvent(callback: () => void): void;
488
+ /** cradova router
489
+ * ---
490
+ * get a screen ready before time.
491
+ *
492
+ * @param {string} path Route path.
493
+ * @param {any} data data for the screen.
494
+ */
495
+ packageScreen(path: string, data?: any): Promise<void>;
496
+ /**
497
+ * Cradova Router
498
+ * ------
499
+ *
500
+ * return last set router params
501
+ *
502
+ * .
503
+ */
504
+ getParams: () => any;
505
+ /**
506
+ * Cradova
507
+ * ---
508
+ * Error Handler for your app
509
+ *
510
+ * @param callback
511
+ * @param path? page path
512
+ */
513
+ addErrorHandler(callback: () => void): void;
514
+ _mount(): void;
515
+ }
516
+ export const Router: RouterClass;
468
517
 
469
518
  /**
470
519
  * Cradova Screen