From b60251539347fcf2aa1fe9cc5edd01360440ebfd Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Mon, 13 Sep 2021 11:05:54 -0400 Subject: [PATCH 01/12] Master repo version update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 82d16113..8ce3b3e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pulse-framework", - "version": "3.0.0", + "version": "4.0.0", "description": "Global state and logic framework for reactive JavaScript & TypeScript applications.", "license": "MIT", "author": { From d18c1e4b17cd0780bf0760f7ff21dfadbc66ae30 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Mon, 13 Sep 2021 11:06:08 -0400 Subject: [PATCH 02/12] fix for typo in state page --- docs/v4/docs/state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/v4/docs/state.md b/docs/v4/docs/state.md index 97c53013..1d18398f 100644 --- a/docs/v4/docs/state.md +++ b/docs/v4/docs/state.md @@ -272,7 +272,7 @@ Reset state to initial value MY_STATE.reset(); ``` ::: warning -.reset() will not work if you do not provide a default value. if you wish to be able to reset string states, yous should initialize them like so: +.reset() will not work if you do not provide a default value. if you wish to be able to reset string states, you should initialize them like so: ```ts const MY_STATE = state(''); // and not state() ``` From 9927d59bf26e9a0cb56ae4152f73a7f04744bc9c Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Mon, 13 Sep 2021 11:21:38 -0400 Subject: [PATCH 03/12] Improved table styling --- docs/.vuepress/styles/index.styl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl index 9cb7a2cd..18bf24ca 100644 --- a/docs/.vuepress/styles/index.styl +++ b/docs/.vuepress/styles/index.styl @@ -8,8 +8,15 @@ $pulseYellow = #FFD696; $pulseWhite = #F7F8F8; $pulseLightBlue = #B6DCFF; -table code - line-height: 2em !important; +table + tr, td, th + border-color: $pulseGrey; + tr:nth-child(2n) + background-color: $pulseCodeBackground; + + code + line-height: 2em !important; + pre.vue-container border-left-width: .5rem; From f91837d4767d0296f44ae98e16a18d4989a1a185 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 08:57:42 -0400 Subject: [PATCH 04/12] Fix for `Cannot read property 'onCoreReady' of undefined` --- packages/pulse-core/lib/instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pulse-core/lib/instance.ts b/packages/pulse-core/lib/instance.ts index 5a0b8e23..ac450824 100644 --- a/packages/pulse-core/lib/instance.ts +++ b/packages/pulse-core/lib/instance.ts @@ -86,7 +86,7 @@ export function route(config?: RouteConfig) { }; } -export const core = instance.core; +export const setCore = (core?: CoreType): CoreType => instance.core(core); export const nextPulse = instance.nextPulse; export const track = instance.track; export const batch = instance.batch; From 70b5ca3213adb2054129a9d83b86b9725238146e Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 10:46:04 -0400 Subject: [PATCH 05/12] Docs work --- docs/v4/docs/core.md | 124 ++++++++--------------------------------- docs/v4/docs/events.md | 29 +++------- 2 files changed, 33 insertions(+), 120 deletions(-) diff --git a/docs/v4/docs/core.md b/docs/v4/docs/core.md index b4bf8037..6df834f1 100644 --- a/docs/v4/docs/core.md +++ b/docs/v4/docs/core.md @@ -23,89 +23,36 @@ core.authentication.state.TOKEN.value; ## Definition ```ts -export const App = new Pulse(); +import { setCore } from '@pulsejs/core' const core = { accounts, authentication }; -export default App.Core(core); +setCore(core); // register your core and initialize computed states -export type ICore = typeof core; +export default core; ``` Imports for `accounts` and `authentication` were ommited for this example. -The Pulse instance is created first as `App`, followed by an object that forms the root of the core object, in this case we're passing in two arbitrary Controllers. - -Now we register the core with `App.Core()` which snapshots the core object. It can now be accessed anywhere with the very same function, without any parameters. (See [Usage]()) - -> _In practice the initilization of App should be in a seperate file (eg: `app.ts`) as it must occur before the imports that require the `App` instance and TSLint doesn't like code above imports._ +An object forms the root of the core object, in this case we're passing in two arbitrary Controllers. -See [Creating your core]() for the more detailed structure. - -::: tip Why export the type? -We're unable to directly import the core into controllers, as it would create cyclic dependencies which can cause horrible compile issues, especially at scale. This is why we use `App.Core()` to get the core inside controllers, but it still wouldn't be type safe. - -However, TypeScript types are immune to this paradox and can time travel. :crystal_ball: Once you declare them, they are able to be refrenced in code before and after declaration. This means we can import just the type of the finalized core into our individual controllers. - -Now when making changes to one Controller you'll see full intelisense in the other—regardless of the order the controllers are initialized. -::: - -## Usage - -The core can be accessed from both outside and within itself, which means the syntax is slightly different for each. To demonstrate, we'll import and access a Controller named `accounts`. - -> From **within** the core (this could be any file within) - -```ts -import { App } from './app'; // instance -import { ICore } from './core'; // type from the future - -const core = App.Core(); -``` - -This method ensures this Controller can access other Controllers, even ones that might not be initialized yet. We import our time-traveling type `ICore` and assign it to the Core functions' generic. - -> From **outside** the core - -```js -import core from './core'; - -core.accounts; -``` - -It's safe to use the default import here as we know everything has been initialized, this would be the easiest way to access the core in your UI components. +Now we register the core with `setCore()` which snapshots the core object. ### Caveats -#### 1) Destructuing imports - -In an ideal world we'd be able to do this: - -```ts -const { accounts } = App.Core(); -``` - -This would not work because at import-level accounts has not been defined yet, as assembly of the core happens last. - -However if you import **without** destructuing, the constant you assign will be a direct reference to the core object within the App instance. So at runtime it will work. - -```ts -const core = App.Core(); -``` - -#### 2) Using the core to supply initial state +#### 1) Using the core to supply initial state A way to remember this rule, is to only use `core.` notation inside functions that are not **immediately called**. Such as Computed functions and actions. -```js -const core = App.Core(); +```ts +import core from './../core' const state = { - noworks: App.State(core.accounts.state.HELLO.value), // compile error - works: App.Computed(() => { + noworks: state(core.accounts.state.HELLO.value), // compile error + works: state(() => { return core.accounts.state.HELLO.value // no compile error }), }, @@ -123,24 +70,11 @@ Create a folder in your application named **_core_**. In some cases you might want to create your core in a seperate repo or monorepo if you wish to use the same core in multiple projects. ::: -### New File: `app.ts` - -This is where you create an instance of Pulse. -```ts -import React from 'react'; -import Pulse from 'pulse-framework'; - -export const App = new Pulse({ - framework: React -}); -``` - -By this point your core should look something like this: +At this point, your core should look something like this: ::: vue -├── **core** +├── **/core** │ ├── **index.ts** -│ ├── `app.ts` ::: > Leave index.ts empty for now. @@ -152,15 +86,10 @@ Create a folder for your conrollers. Pulse advocates splitting up your core into > See [Controller]() documentation for more detail ```ts -import { App } from './app'; // instance -import { ICore } from './core'; // type from the future +import core from './core'; // type from the future -const core = App.Core(); // grab sister controller - -export const accounts = App.Controller({ - state: { - IS_NEW_ACCOUNT: App.State().type(Boolean) - } +export const accounts = { + IS_NEW_ACCOUNT: state().type(Boolean), actions: { logout() { App.reset(core.authentication.state) @@ -172,24 +101,20 @@ export const accounts = App.Controller({ ### New File: `core.ts` ```ts -import { App } from './app'; - import accounts from './controllers/accounts'; import authentication from './controllers/authentication'; -export const core = App.Core({ +export const core = setCore({ accounts, authentication }); -export type ICore = typeof core; +export default core; ``` Everything comes together in `core.ts`, it handles importing the Pulse instance, followed by your controllers. -`App.Core()` declares the final core structure and saves it to the instance so that subsequent calls. - -Finally the core is registered and exported and `ICore` is exported as a type declaration. +`setCore()` declares the final core structure and saves it to the instance so that subsequent calls. ### Export everything `index.ts` @@ -203,23 +128,22 @@ export default core; Pulse is flexible, so you are free to do you own thing, but you must ensure that at the very least instance creation comes first, core construction comes last. ::: vue -**core** +**/core** ├── .**index.ts** -├── .**app.ts** _Create Pulse instance_ -│ ├── `controllers` +│ ├── `/controllers` │ │ └── **accounts** │ │ │ ├── **index.ts** _Create and export controller_ │ │ │ ├── **state.ts** _Define all State, Computed State & a Collection_ │ │ │ ├── **actions.ts** _All account actions as exported function_ │ │ │ ├── **interfaces.ts** _Typescript interfaces for accounts_ │ │ │ ├── **routes.ts** _api/socket endpoints for accounts_ -│ ├── `api` +│ ├── `/api` │ │ └── **index.ts** │ │ └── **rest.service.ts** _For rest api users_ │ │ └── **socket.service.ts** _For websocket users_ -│ ├── `utils` +│ ├── `/utils` │ │ └── **index.ts** -│ ├── `data` _(Optional)_ +│ ├── `/data` _(Optional)_ │ │ ├── **lists.json** -└── .**core.ts** _Construct the core_ +└── **core.ts** _Construct the core_ ::: diff --git a/docs/v4/docs/events.md b/docs/v4/docs/events.md index a0e90eed..4667ca23 100644 --- a/docs/v4/docs/events.md +++ b/docs/v4/docs/events.md @@ -11,15 +11,14 @@ Events are handy for emitting UI updates and passing data with them. Both core f A prime example for when to use events would be showing an alert dropdown inside your app. Your core can emit the event and a top-level component can listen and render alert dropdown with a message. ```ts -const App = new Pulse(); - -const ALERT = App.Event(); +import { event } from '@pulsejs/core' +const ALERT = event(); ``` ::: tip TypeScript: Payload Type Events support an optional generic parameter for the payload type, providing typesafety and VScode intellisense when using your Event. ```ts -const ALERT = App.Event<{ message: string }>(); +const ALERT = event<{ message: string }>(); ``` ::: @@ -29,7 +28,7 @@ const ALERT = App.Event<{ message: string }>(); Events can optionally receive a configuration object as the first and only parameter. ```ts -const ALERT = App.Event({ enabled: false }); +const ALERT = event({ enabled: false }); ``` **All config parameters** _(optional)_ @@ -67,7 +66,7 @@ cleanup(); This syntax is bulky considering you must invoke the cleanup function on component unmount, so with React the `useEvent()` hook will cleanup for you! ```ts import React from 'react'; -import { useEvent } from '@pulse/react'; +import { useEvent } from '@pulsejs/react'; export function MyComponent() { useEvent(ALERT, payload => { @@ -78,16 +77,6 @@ export function MyComponent() { ``` Eventually we will implement similar support for Vue components. -## Event Groups -In some cases you might want a cleaner way to define a group of Events at the same time. They are not related to each other in any way other than defining them with a cleaner syntax. Event Groups also assign the `name` property automatically. - -```ts -const events = App.EventGroup(Event => ({ - JUST_AN_EVENT: Event(), - ALERT: Event<{ message: string }>({ throttle: 100 }) -})); -``` - ## useEvent() This is a React hook for functional components that allows you to use an Event with automatic cleanup @@ -96,19 +85,19 @@ import React from 'react'; export function MyComponent(props) { - useEvent(events.ALERT, () => { + useEvent(ALERT, () => { // do something }) return
} ``` -In this example `events` is referencing the EventGroup created above, however usually this would be located inside your [Core](/v3/docs/core.html). +In this example `events` is referencing the EventGroup created above, however usually this would be located inside your [Core](/v4/docs/core.html). This is a really handy syntax for using Events and we'd recommend all React users. ## Importing Events -It's best practice to export your Events in your [Core](/v3/docs/core.html) object, so they can easily be used within your components. +It's best practice to export your Events in your [Core](/v4/docs/core.html) object, so they can easily be used within your components. -You might want to make your events global to your core, such as `core.events`, or maybe you'll put them in your [Controllers](/v3/docs/controllers.html) ``core.accounts.events.MY_EVENT``. It's up to you! +You might want to make your events global to your core, such as `core.events`, or maybe you'll put them in your [Controllers](/v4/docs/controllers.html) ``core.accounts.events.MY_EVENT``. It's up to you! From 7f9ebb606def432570ab0fdb4c9cf1642689f94a Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 10:46:25 -0400 Subject: [PATCH 06/12] New exported members structure --- packages/pulse-core/lib/index.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/pulse-core/lib/index.ts b/packages/pulse-core/lib/index.ts index c069e9c1..81f2b3a8 100644 --- a/packages/pulse-core/lib/index.ts +++ b/packages/pulse-core/lib/index.ts @@ -1,3 +1,17 @@ -export * from './internal'; +// Types +export { SetFunc } from './state'; +export { IJob } from './runtime'; +export { FuncType } from './action'; +export { SubscriptionContainer } from './sub'; +export { APIConfig, PulseResponse } from './api'; +export { PrimaryKey, GroupName, GroupAddOptions } from './collection/group'; +export { StorageConfig } from './storage'; +export { EventPayload, EventConfig, EventsObjFunc, EventCallbackFunc } from './event'; +export { GroupObj, DefaultDataItem, SelectorObj, Config } from './collection/collection'; + +// Instance +export * from './instance'; + import { Pulse } from './pulse'; + export default Pulse; From 525cfdd4ea859d8efbc04b4902a5c53fa969416c Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 10:46:57 -0400 Subject: [PATCH 07/12] Fix for core reference --- packages/pulse-core/lib/pulse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pulse-core/lib/pulse.ts b/packages/pulse-core/lib/pulse.ts index eea9a8c8..61d53516 100644 --- a/packages/pulse-core/lib/pulse.ts +++ b/packages/pulse-core/lib/pulse.ts @@ -60,7 +60,7 @@ export class Pulse { if (!this.ready) this.ready = true; // Copy core object structure without destroying this.core object reference - if (core) for (let p in core) this.core[p] = core[p]; + if (core) for (let p in core) this._core[p] = core[p]; this._computed.forEach(instance => instance.recompute()); From f318d5b385fd697b1b445cf9a086b7cf9695328d Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 11:12:21 -0400 Subject: [PATCH 08/12] Improved the custom details block contrast --- docs/.vuepress/theme/styles/custom-blocks.styl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/.vuepress/theme/styles/custom-blocks.styl b/docs/.vuepress/theme/styles/custom-blocks.styl index 147752b0..d3a2b732 100755 --- a/docs/.vuepress/theme/styles/custom-blocks.styl +++ b/docs/.vuepress/theme/styles/custom-blocks.styl @@ -1,3 +1,4 @@ +$pulseCodeBackground = #282e3f; .custom-block .custom-block-title font-weight 600 @@ -32,7 +33,7 @@ border-radius 2px margin 1.6em 0 padding 1.6em - background-color #eee + background-color $pulseCodeBackground h4 margin-top 0 figure, p From 9d82937e2451292a73d8e67fdb681da18937f16d Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 11:13:19 -0400 Subject: [PATCH 09/12] removed the controller doc in v4 --- docs/.vuepress/config.js | 2 +- docs/v4/docs/controllers.md | 24 ++++++++++-------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a7638914..7b3c283d 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -173,7 +173,7 @@ module.exports = { 'docs/state', 'docs/collections', 'docs/actions', - 'docs/controllers', + // 'docs/controllers', 'docs/core', 'docs/route', 'docs/persisting-data', diff --git a/docs/v4/docs/controllers.md b/docs/v4/docs/controllers.md index 019be878..53d98900 100644 --- a/docs/v4/docs/controllers.md +++ b/docs/v4/docs/controllers.md @@ -22,17 +22,15 @@ core.accounts.myAction(); The first parameter of the Controller function is `ControllerConfig` -```js -const App = new Pulse(); - -const config = { - collection: App.Collection()(), - state: { - MY_STATE: App.State(), - MY_COMPUTED_STATE: App.Computed(() => true) - } +```ts +import {collection, state} from '@pulsejs/core' + +const accounts = { + collection: collection(), + MY_STATE: state(), + MY_COMPUTED_STATE: state(() => true) }; -export const accounts = App.Controller(config); +export const accounts; ``` ## Config Structure @@ -60,7 +58,7 @@ For TypeScript users, the inferred types of the object you pass in will be prese In some cases you will prefer to use more than the default Controller categories, you might want to spread actions to the root of the controller instance so they can be access like the following. -```js +```ts accounts.myAction(); ``` @@ -83,15 +81,13 @@ This is how a controller folder should be organized. ### `index.ts` ```ts -// import instance -import App from '../../app'; // import state import { state, computed, collection } from './state'; // import actions, helpers and routes import * as actions from './actions'; // init controller, merge state and computed state -const controller = App.Controller({ state: { ...state, ...computed }, collection }).root(actions); +const controller = { state: { ...state, ...computed }, collection }; ``` The order of imports above is important, state/collections must be imported first to also allow them to be imported into `actions.ts` without creating a cyclic import. Sometimes this can cause `import * as ...` to return an empty object at runtime, following this structure will avoid that. From cdef591d30ca00aeec07ce6b4bc7852a5ceb7070 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 11:30:43 -0400 Subject: [PATCH 10/12] Updated the inline code element styles in docs --- docs/.vuepress/theme/styles/code.styl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/.vuepress/theme/styles/code.styl b/docs/.vuepress/theme/styles/code.styl index 9d3aa9a5..335d20c0 100755 --- a/docs/.vuepress/theme/styles/code.styl +++ b/docs/.vuepress/theme/styles/code.styl @@ -4,7 +4,8 @@ padding 0.25rem 0.5rem margin 0 font-size 0.85em - background-color rgba(27,31,35,0.05) + // background-color rgba(27,31,35,0.05) + background-color $codeBgColor border-radius 3px .token &.deleted From 747c8e28a076d96131de043fa33350833f1f6b3f Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 11:30:59 -0400 Subject: [PATCH 11/12] Futher refined core documentation --- docs/v4/docs/core.md | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/docs/v4/docs/core.md b/docs/v4/docs/core.md index 6df834f1..eb206f49 100644 --- a/docs/v4/docs/core.md +++ b/docs/v4/docs/core.md @@ -81,21 +81,22 @@ At this point, your core should look something like this: ### New Directory: `controllers` -Create a folder for your conrollers. Pulse advocates splitting up your core into modules using the [Controller]() class to containerize the module. However this step is optional, you're free to structure your core however you'd like. +Create a folder for your conrollers. Pulse advocates splitting up your core into modules using an object; however, this step is optional. You're free to structure your core however you'd like. -> See [Controller]() documentation for more detail + ```ts +import {state, action} from '@pulsejs/core'; import core from './core'; // type from the future export const accounts = { IS_NEW_ACCOUNT: state().type(Boolean), - actions: { - logout() { - App.reset(core.authentication.state) - } - } + logout: action(() => { + core.authentication.token.reset() + }) + }); +export default accounts; ``` ### New File: `core.ts` @@ -125,11 +126,12 @@ export default core; ## Structure at scale -Pulse is flexible, so you are free to do you own thing, but you must ensure that at the very least instance creation comes first, core construction comes last. +Pulse is flexible, so you are free to do you own thing, but here is a core structure we recommend. ::: vue **/core** -├── .**index.ts** +├── **index.ts** _Export core and whatever else you want to expose to the application_ +├── **core.ts** _Construct the core_ │ ├── `/controllers` │ │ └── **accounts** │ │ │ ├── **index.ts** _Create and export controller_ @@ -137,13 +139,8 @@ Pulse is flexible, so you are free to do you own thing, but you must ensure that │ │ │ ├── **actions.ts** _All account actions as exported function_ │ │ │ ├── **interfaces.ts** _Typescript interfaces for accounts_ │ │ │ ├── **routes.ts** _api/socket endpoints for accounts_ -│ ├── `/api` -│ │ └── **index.ts** -│ │ └── **rest.service.ts** _For rest api users_ -│ │ └── **socket.service.ts** _For websocket users_ │ ├── `/utils` │ │ └── **index.ts** │ ├── `/data` _(Optional)_ -│ │ ├── **lists.json** -└── **core.ts** _Construct the core_ +│ │ ├── **lists.json** ::: From 5484f427797edc456de88de35dfd70ed161ee1a0 Mon Sep 17 00:00:00 2001 From: Philippe Clesca Date: Tue, 14 Sep 2021 12:22:37 -0400 Subject: [PATCH 12/12] reinstated the index change dur to integration issues --- packages/pulse-core/lib/index.ts | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/packages/pulse-core/lib/index.ts b/packages/pulse-core/lib/index.ts index 81f2b3a8..c069e9c1 100644 --- a/packages/pulse-core/lib/index.ts +++ b/packages/pulse-core/lib/index.ts @@ -1,17 +1,3 @@ -// Types -export { SetFunc } from './state'; -export { IJob } from './runtime'; -export { FuncType } from './action'; -export { SubscriptionContainer } from './sub'; -export { APIConfig, PulseResponse } from './api'; -export { PrimaryKey, GroupName, GroupAddOptions } from './collection/group'; -export { StorageConfig } from './storage'; -export { EventPayload, EventConfig, EventsObjFunc, EventCallbackFunc } from './event'; -export { GroupObj, DefaultDataItem, SelectorObj, Config } from './collection/collection'; - -// Instance -export * from './instance'; - +export * from './internal'; import { Pulse } from './pulse'; - export default Pulse;