From f3e449ac0418fa1458e79f8fba4249559cda7810 Mon Sep 17 00:00:00 2001 From: afimbres Date: Mon, 29 Jan 2024 15:15:01 -0800 Subject: [PATCH 01/16] plugin core doc addition --- docs/site/pages/writing-plugins.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/site/pages/writing-plugins.mdx b/docs/site/pages/writing-plugins.mdx index 613d91c42..bf21c1493 100644 --- a/docs/site/pages/writing-plugins.mdx +++ b/docs/site/pages/writing-plugins.mdx @@ -13,6 +13,22 @@ platform: core,react Core plugins are the easiest way to extend Player functionality regardless of what platform you are using Player on. To make writing core plugins easy `@player-ui/player` exposes an interface `PlayerPlugin` that denotes everything needed. The two mandatory features are a `name` property which is lets Player know how to refer to the plugin and an implemented `apply` function that takes a `player` object. Optionally a `symbol` property can be used to provide a unique identifier that can be used to retrieve the plugin from Player. +The first step for making a plugin is creating our plugin class, making sure it inherits the `PlayerPlugin` class from `@player/core`. By convention, a class constant with the name of your plugin should be defined. + +```javascript +export default class MyFirstPlayerPlugin implements PlayerPlugin { + name = 'my-first-player-plugin'; + + {/* A constructor can go here */} + + apply(player: Player) { + {/* Your logic here */} + } + + {/* More logic or helper functions can go here */} +} +``` + The `apply` function is where the actual logic of the plugin lives. By tapping the hooks exposed via `player.hooks` you gain access to the internal pipeline of components that comprise Player and can inject your functionality into their exposed hooks. For example if you want to do something any time Player's state changes you could do the following: ```javascript From 99acda1fc649ed25b7b6fa4a77c9c8ec8698d4da Mon Sep 17 00:00:00 2001 From: afimbres Date: Tue, 30 Jan 2024 11:25:01 -0800 Subject: [PATCH 02/16] some more cleanup and information --- docs/site/pages/writing-plugins.mdx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/site/pages/writing-plugins.mdx b/docs/site/pages/writing-plugins.mdx index bf21c1493..476db06e6 100644 --- a/docs/site/pages/writing-plugins.mdx +++ b/docs/site/pages/writing-plugins.mdx @@ -13,11 +13,11 @@ platform: core,react Core plugins are the easiest way to extend Player functionality regardless of what platform you are using Player on. To make writing core plugins easy `@player-ui/player` exposes an interface `PlayerPlugin` that denotes everything needed. The two mandatory features are a `name` property which is lets Player know how to refer to the plugin and an implemented `apply` function that takes a `player` object. Optionally a `symbol` property can be used to provide a unique identifier that can be used to retrieve the plugin from Player. -The first step for making a plugin is creating our plugin class, making sure it inherits the `PlayerPlugin` class from `@player/core`. By convention, a class constant with the name of your plugin should be defined. +The first step for creating a plugin is making our plugin class, making sure it implements the `PlayerPlugin` interface from `@player/core`. By convention, a name attribute with the dash-cased name of your plugin should be defined. ```javascript -export default class MyFirstPlayerPlugin implements PlayerPlugin { - name = 'my-first-player-plugin'; +export default class ExamplePlayerPlugin implements PlayerPlugin { + name = 'example-player-plugin'; {/* A constructor can go here */} @@ -25,7 +25,7 @@ export default class MyFirstPlayerPlugin implements PlayerPlugin { {/* Your logic here */} } - {/* More logic or helper functions can go here */} + {/* Helper methods can go here */} } ``` @@ -57,7 +57,7 @@ _Note: For the React Player you can import and load the plugin the same way you -React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a `name` attribute is required and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: +React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a `name` attribute in dash-case is required and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: - The `webComponent` hook allows you to modify a React component that is stored in the React Player for use when it renders content. This happens during the initialization phase and ise useful if you want to wrap components in various content providers. - The `playerComponent` hook allows you to modify a component or execute functionality when the React Player is rendering a component after the view has been reconciled in Player. This is useful if you want to inject additional props to components or collect data on which component was rendered. @@ -94,6 +94,9 @@ export class FunctionPlugin implements ReactPlayerPlugin { ); }); } + + {/* Helper methods can go here */} +} ``` Lastly React plugins can also act as a core plugin in cases where core functionality needs to be extended for the React plugin to work. Since both the `PlayerPlugin` and `ReactPlayerPlugin` are typescript interfaces a plugin can implement both and be considered a valid plugin. From 85c0b428c2d34a2cb78c3b6e5c4a60c4b70125c4 Mon Sep 17 00:00:00 2001 From: afimbres Date: Tue, 30 Jan 2024 12:56:54 -0800 Subject: [PATCH 03/16] Added dsl validate command --- docs/site/pages/tools/cli.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/site/pages/tools/cli.mdx b/docs/site/pages/tools/cli.mdx index 3936be02a..f41e4aea8 100644 --- a/docs/site/pages/tools/cli.mdx +++ b/docs/site/pages/tools/cli.mdx @@ -63,6 +63,22 @@ DESCRIPTION Compile Player DSL files into JSON ``` +- [`player dsl validate`](#player-dsl-validate) +Runs isolated TSC compiler on authored Player DSL .tsx files. + +``` +USAGE + $ player dsl validate [-f ] [-c ] + +FLAGS + -c, --config= Path to a specific config file to load. + By default, will automatically search for an rc or config file to load + -f, --files=... A list of files or globs to validate + +DESCRIPTION + Runs isolated TSC compiler on authored Player DSL .tsx files. +``` + - [`player json validate`](#player-json-validate) Validate Player JSON content From 8f65ad31369e9b8a7c30031fc6df0c5ad37596df Mon Sep 17 00:00:00 2001 From: afimbres Date: Tue, 30 Jan 2024 14:10:27 -0800 Subject: [PATCH 04/16] clean up first set of observation wording --- docs/site/pages/writing-plugins.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/site/pages/writing-plugins.mdx b/docs/site/pages/writing-plugins.mdx index 476db06e6..8fb4eaf6b 100644 --- a/docs/site/pages/writing-plugins.mdx +++ b/docs/site/pages/writing-plugins.mdx @@ -13,9 +13,9 @@ platform: core,react Core plugins are the easiest way to extend Player functionality regardless of what platform you are using Player on. To make writing core plugins easy `@player-ui/player` exposes an interface `PlayerPlugin` that denotes everything needed. The two mandatory features are a `name` property which is lets Player know how to refer to the plugin and an implemented `apply` function that takes a `player` object. Optionally a `symbol` property can be used to provide a unique identifier that can be used to retrieve the plugin from Player. -The first step for creating a plugin is making our plugin class, making sure it implements the `PlayerPlugin` interface from `@player/core`. By convention, a name attribute with the dash-cased name of your plugin should be defined. +The first step for creating a plugin is making our plugin class, making sure it implements the `PlayerPlugin` interface from `@player-ui/player`. By convention, a name attribute with the dash-cased name of your plugin should be defined. -```javascript +```typescript export default class ExamplePlayerPlugin implements PlayerPlugin { name = 'example-player-plugin'; @@ -57,7 +57,7 @@ _Note: For the React Player you can import and load the plugin the same way you -React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a `name` attribute in dash-case is required and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: +React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a `name` attribute that should be dash-cased by convention is required, and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: - The `webComponent` hook allows you to modify a React component that is stored in the React Player for use when it renders content. This happens during the initialization phase and ise useful if you want to wrap components in various content providers. - The `playerComponent` hook allows you to modify a component or execute functionality when the React Player is rendering a component after the view has been reconciled in Player. This is useful if you want to inject additional props to components or collect data on which component was rendered. From 47ee1f0c62b06e203bfdaa5eba225e0e6de3f793 Mon Sep 17 00:00:00 2001 From: afimbres Date: Wed, 31 Jan 2024 09:41:29 -0800 Subject: [PATCH 05/16] Updated descriptions to include TSC compiling --- docs/site/pages/tools/cli.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/site/pages/tools/cli.mdx b/docs/site/pages/tools/cli.mdx index f41e4aea8..c040ec8f9 100644 --- a/docs/site/pages/tools/cli.mdx +++ b/docs/site/pages/tools/cli.mdx @@ -45,7 +45,7 @@ Plugins are the way to change runtime behavior of the CLI actions. This includes # Commands - [`player dsl compile`](#player-dsl-compile) -Compile Player DSL files into JSON +Compile Player DSL files into JSON after running TSC compiler against Typescript files ``` USAGE @@ -60,11 +60,11 @@ FLAGS --skip-validation Option to skip validating the generated JSON DESCRIPTION - Compile Player DSL files into JSON + Compile Player DSL files into JSON after running TSC compiler against Typescript files ``` - [`player dsl validate`](#player-dsl-validate) -Runs isolated TSC compiler on authored Player DSL .tsx files. +Runs isolated TSC compiler on authored Player DSL Typescript files. ``` USAGE @@ -76,7 +76,7 @@ FLAGS -f, --files=... A list of files or globs to validate DESCRIPTION - Runs isolated TSC compiler on authored Player DSL .tsx files. + Runs isolated TSC compiler on authored Player DSL Typescript files. ``` - [`player json validate`](#player-json-validate) From 9f254102e72877a02d141035cf0b4e76d90878da Mon Sep 17 00:00:00 2001 From: afimbres Date: Wed, 31 Jan 2024 12:06:06 -0800 Subject: [PATCH 06/16] Plugin implementation doc v1 --- docs/site/config/navigation.ts | 4 + docs/site/pages/plugin-implementation.mdx | 89 +++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 docs/site/pages/plugin-implementation.mdx diff --git a/docs/site/config/navigation.ts b/docs/site/config/navigation.ts index 85719d9ea..60392715f 100644 --- a/docs/site/config/navigation.ts +++ b/docs/site/config/navigation.ts @@ -48,6 +48,10 @@ const navigation: Navigation = { title: 'Writing Plugins', path: '/writing-plugins', }, + { + title: 'Plugin Implementation', + path: '/plugin-implementation', + }, { title: 'Multi-Flow Experiences', path: '/guides/multi-flow-experiences', diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx new file mode 100644 index 000000000..d7be086bc --- /dev/null +++ b/docs/site/pages/plugin-implementation.mdx @@ -0,0 +1,89 @@ +--- +title: Plugin Implementation +--- +# Plugin Implementation + +Plugins main capabilities are to tap into the player's lifecycle hooks and to add new functionality to the player. In this section we'll go over the steps to implement a plugin. + +We'll use the [stage-revert-data](./plugins/stage-revert-data.md) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: + +```typescript +export default class StageRevertDataPlugin implements PlayerPlugin { + name = 'stage-revert-data-plugin'; + + apply(player: Player) { + let dataController: DataController; + let stageData: String; + let commitTransitions: String[]; + let commitShadowModel: Boolean = false; + + const GatedDataMiddleware = new ValidationMiddleware( + () => + commitShadowModel + ? undefined + : { + message: 'staging data', + severity: 'error', + }, + { shouldIncludeInvalid: () => true } + ); +``` +We defined variables that will be used in the plugin: +- `dataController`: The data orchestrator of our Player instance +- `stageData`: State attribute that enables that comes from the view attribute content to enabling the staging of data +- `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute. +- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, if `stageData` is set to true and the next view name is included in `commitTransitions`. +- `GatedDataMiddleware` Data Middleware that will be used to intercept the data pipeline if `stageData` is set to true. + +The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `reolveView` hook. By defining our own property method `call` we can intercept the current view state and read the `stageData` and `commitTransitions` properties. + +```javascript + player.hooks.viewController.tap(this.name, (vc) => { + vc.hooks.resolveView.intercept({ + call: (view, id, state) => { + stageData = state?.attributes?.stageData; + commitTransitions = state?.attributes?.commitTransitions; + }, + }); + }); +``` +`Note`: notice how each time we tap into a hook, we use the `this.name` property as the name of the plugin. This is important to avoid conflicts with other plugins. + +Next we tap into the `dataController`, so we can scope the data controller instance for future use. Then we tap into the `resolveDataStages` plugin in this data controller instance. If the `stage` property is set to true, we add our `GatedDataMiddleware` to the data pipeline. If not, we return the data pipeline as is. + +```javascript + player.hooks.dataController.tap(this.name, (dc: DataController) => { + dataController = dc; + + dc.hooks.resolveDataStages.tap(this.name, (dataPipeline) => { + return stageData + ? [...dataPipeline, GatedDataMiddleware] + : [...dataPipeline]; + }); + }); +``` +Finally, we tap into the `flowController` so we can intercept the `flow` hook. We then tap into the `transition` hook, which is called every time the player transitions from one view to another. If the `commitTransitions` includes the next view name, we set the `commitShadowModel` flag to true, and add the shadow model paths to the `GatedDataMiddleware`. If not, we clear the shadow model paths and set the `commitShadowModel` flag to false. + +```javascript + player.hooks.flowController.tap(this.name, (flowController) => { + flowController.hooks.flow.tap(this.name, (flow) => { + flow.hooks.transition.tap(this.name, (from, to) => { + if (from) { + if (commitTransitions.includes(to.name)) { + commitShadowModel = true; + player.logger.debug( + 'Shadow Model Data to be committed %s', + GatedDataMiddleware.shadowModelPaths + ); + dataController.set(GatedDataMiddleware.shadowModelPaths); + } + + commitShadowModel = false; + GatedDataMiddleware.shadowModelPaths.clear(); + } + }); + }); + }); +``` + +And this is how we implement a plugin that manages the staging of data based on the view state attributes. \ No newline at end of file From f02fa878800908e4f39a40534a91a24b715b7835 Mon Sep 17 00:00:00 2001 From: afimbres Date: Wed, 31 Jan 2024 12:54:51 -0800 Subject: [PATCH 07/16] plugin docs addl cleanup --- docs/site/pages/plugin-implementation.mdx | 2 +- docs/site/pages/plugins/stage-revert-data.mdx | 2 +- docs/site/pages/writing-plugins.mdx | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index d7be086bc..bdc7c94cc 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -5,7 +5,7 @@ title: Plugin Implementation Plugins main capabilities are to tap into the player's lifecycle hooks and to add new functionality to the player. In this section we'll go over the steps to implement a plugin. -We'll use the [stage-revert-data](./plugins/stage-revert-data.md) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: +We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: ```typescript export default class StageRevertDataPlugin implements PlayerPlugin { diff --git a/docs/site/pages/plugins/stage-revert-data.mdx b/docs/site/pages/plugins/stage-revert-data.mdx index 8eab2303a..ed2335c6d 100644 --- a/docs/site/pages/plugins/stage-revert-data.mdx +++ b/docs/site/pages/plugins/stage-revert-data.mdx @@ -3,7 +3,7 @@ title: Stage Revert Data platform: core --- -# Stage Rvert Data +# Stage Revert Data Plugin This plugin enables users to temporarily stage data changes before committing to the actual data model diff --git a/docs/site/pages/writing-plugins.mdx b/docs/site/pages/writing-plugins.mdx index 8fb4eaf6b..25d2507a2 100644 --- a/docs/site/pages/writing-plugins.mdx +++ b/docs/site/pages/writing-plugins.mdx @@ -52,6 +52,8 @@ apply(player: Player) { It is not uncommon for core plugins to have constructors for cases where the plugin needs to take some configuration. In cases where plugin configs are more complicated than basic feature flags, it is recommended to make an interface to represent the config object. As an added benefit it also makes it easier to down stream consumers to use your plugin. +For a more comprehensive guide on plugins, check out this [Plugin Implementation](./plugin-implementation) example. + _Note: For the React Player you can import and load the plugin the same way you would a React Player Plugin but for the iOS and Android Players you will need to wrap the javascript bundle in a iOS/Android plugin to ensure it is available on your platform._ From 34da9dc6a226dc5e3bcfce43e019efc1d8bcc961 Mon Sep 17 00:00:00 2001 From: afimbres Date: Thu, 1 Feb 2024 15:07:30 -0800 Subject: [PATCH 08/16] Overview plugin links fix --- docs/site/pages/plugins/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/pages/plugins/index.mdx b/docs/site/pages/plugins/index.mdx index 27b435f7f..010ea8d8f 100644 --- a/docs/site/pages/plugins/index.mdx +++ b/docs/site/pages/plugins/index.mdx @@ -9,4 +9,4 @@ Internally they allow access to many of the core sub-systems, which can add feat ![Plugins Overview Diagram](/plugin_overview.png?darkModeInvert) -The scope of what a plugin is capable of is pretty broad, but are typically broken down into smaller reusable modules. Some are more end-user focused ([Common Expression Plugin](./common-expression) and [Common Types Plugin](./common-types)) while others are more relavant for other plugin developers ([Expression Plugin](./expression) and [Types Provider Plugin](./types-provider)) +The scope of what a plugin is capable of is pretty broad, but are typically broken down into smaller reusable modules. Some are more end-user focused ([Common Expression Plugin](../plugins/common-expressions) and [Common Types Plugin](../plugins/common-types)) while others are more relavant for other plugin developers ([Expression Plugin](../plugins/expression) and [Types Provider Plugin](../plugins/types-provider)) From 26c28f1d8396ad8b92a0be6090b290a4dcfa994e Mon Sep 17 00:00:00 2001 From: afimbres Date: Thu, 1 Feb 2024 17:15:57 -0800 Subject: [PATCH 09/16] Fixing invalid character on plugin implementation doc --- docs/site/pages/plugin-implementation.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index bdc7c94cc..af2a0f80f 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -1,6 +1,7 @@ --- title: Plugin Implementation --- + # Plugin Implementation Plugins main capabilities are to tap into the player's lifecycle hooks and to add new functionality to the player. In this section we'll go over the steps to implement a plugin. From b039bcbb45fd86be6b8b57178656128620253a8d Mon Sep 17 00:00:00 2001 From: afimbres Date: Fri, 2 Feb 2024 13:24:56 -0800 Subject: [PATCH 10/16] Added snippets reference --- docs/site/pages/plugin-implementation.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index af2a0f80f..03435c9f5 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -4,7 +4,7 @@ title: Plugin Implementation # Plugin Implementation -Plugins main capabilities are to tap into the player's lifecycle hooks and to add new functionality to the player. In this section we'll go over the steps to implement a plugin. +Plugins main capabilities are to extend or add new functionality by tapping into player's pipeline of components via hooks . In this section we'll go over the steps to implement a plugin. We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: @@ -87,4 +87,6 @@ Finally, we tap into the `flowController` so we can intercept the `flow` hook. W }); ``` -And this is how we implement a plugin that manages the staging of data based on the view state attributes. \ No newline at end of file +And this is how we implement a plugin that manages the staging of data based on the view state attributes. + +Code Snippets Reference: [StageRevertDataPlugin](https://github.com/player-ui/player/blob/main/plugins/stage-revert-data/core/src/index.ts) \ No newline at end of file From e52fa8aced595088a6450e41a2da943aea751847 Mon Sep 17 00:00:00 2001 From: afimbres Date: Fri, 2 Feb 2024 14:10:13 -0800 Subject: [PATCH 11/16] plugin hook implementation wording cleanup --- docs/site/pages/plugin-implementation.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index 03435c9f5..0a991c30b 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -31,12 +31,12 @@ export default class StageRevertDataPlugin implements PlayerPlugin { ``` We defined variables that will be used in the plugin: - `dataController`: The data orchestrator of our Player instance -- `stageData`: State attribute that enables that comes from the view attribute content to enabling the staging of data +- `stageData`: State attribute that comes from the view attribute content to enabling the staging of data - `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute. -- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, if `stageData` is set to true and the next view name is included in `commitTransitions`. +- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, only if `stageData` is set to true and the next view name is included in `commitTransitions`. - `GatedDataMiddleware` Data Middleware that will be used to intercept the data pipeline if `stageData` is set to true. -The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `reolveView` hook. By defining our own property method `call` we can intercept the current view state and read the `stageData` and `commitTransitions` properties. +The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `resolveView` hook. By defining our own property method `call` we can intercept the current view state and read the `stageData` and `commitTransitions` properties. ```javascript player.hooks.viewController.tap(this.name, (vc) => { @@ -63,7 +63,7 @@ Next we tap into the `dataController`, so we can scope the data controller insta }); }); ``` -Finally, we tap into the `flowController` so we can intercept the `flow` hook. We then tap into the `transition` hook, which is called every time the player transitions from one view to another. If the `commitTransitions` includes the next view name, we set the `commitShadowModel` flag to true, and add the shadow model paths to the `GatedDataMiddleware`. If not, we clear the shadow model paths and set the `commitShadowModel` flag to false. +Finally, we tap into the `flowController` so we can intercept the `flow` hook. We then tap into the `transition` hook, which is called every time the player transitions from one view to another. If the `commitTransitions` includes the next view name, we set the `commitShadowModel` flag to true, and commit the data stored in the shadow model through `GatedDataMiddleware` into the data model. Whether the data was committed from the shadow model or not, we clear the shadow model paths in the `GatedDataMiddleware` instance and set the `commitShadowModel` flag to false as final steps. ```javascript player.hooks.flowController.tap(this.name, (flowController) => { From 7ba52cd5cad5352dbdd4c6575a9504d1bb2dd215 Mon Sep 17 00:00:00 2001 From: afimbres Date: Mon, 5 Feb 2024 12:21:40 -0800 Subject: [PATCH 12/16] Asset reference link fixed --- docs/site/pages/guides/designing-semantic-assets.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/pages/guides/designing-semantic-assets.mdx b/docs/site/pages/guides/designing-semantic-assets.mdx index 56e37330f..5a5f7cce3 100644 --- a/docs/site/pages/guides/designing-semantic-assets.mdx +++ b/docs/site/pages/guides/designing-semantic-assets.mdx @@ -6,7 +6,7 @@ title: Designing Semantic Assets While not a _hard_ requirement by Player, the API design for assets plays an important role in it's adoption, especially if the intent is to re-use content across platforms. In many cases, Player content is written, and edited many more times than assets are created, and thus it's schema plays an important role in it's effective adoption. -Player ships with a set of [Reference Assets](assets/reference) to get started, but intentionally doesn't include anything beyond some basics. We believe it's up to each consumer to define their own semantics (if at all), that best suites their applications. +Player ships with a set of [Reference Assets](../assets/reference) to get started, but intentionally doesn't include anything beyond some basics. We believe it's up to each consumer to define their own semantics (if at all), that best suites their applications. ## Intent Based Schema From b6fe347320b150a6f93c8b395f131f5359544bd5 Mon Sep 17 00:00:00 2001 From: afimbres Date: Mon, 5 Feb 2024 16:23:58 -0800 Subject: [PATCH 13/16] Doc: Plugin react wording correction. --- docs/site/pages/writing-plugins.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/pages/writing-plugins.mdx b/docs/site/pages/writing-plugins.mdx index e848bb963..d6c93b18b 100644 --- a/docs/site/pages/writing-plugins.mdx +++ b/docs/site/pages/writing-plugins.mdx @@ -59,7 +59,7 @@ _Note: For the React Player you can import and load the plugin the same way you -React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a `name` attribute that should be dash-cased by convention is required, and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: +React Player Plugins are very similar to core plugins in both their composition and use. The `@player-ui/react` package exposes an interface `ReactPlayerPlugin` that, much like the `PlayerPlugin` interface provides the necessary attributes that are required for a React Player plugin. Again a dash-cased `name` attribute should be used by convention, and a function `applyReact` is required that takes a `ReactPlayer` instance. Similarly to core plugins in the `applyReact` function you have access to the React Player object and access to the three exposed hooks: - The `webComponent` hook allows you to modify a React component that is stored in the React Player for use when it renders content. This happens during the initialization phase and ise useful if you want to wrap components in various content providers. - The `playerComponent` hook allows you to modify a component or execute functionality when the React Player is rendering a component after the view has been reconciled in Player. This is useful if you want to inject additional props to components or collect data on which component was rendered. From 12e9390e02f77afe7fe1c03fd59de1ab132c31a6 Mon Sep 17 00:00:00 2001 From: Alex Fimbres Date: Tue, 6 Feb 2024 10:06:36 -0800 Subject: [PATCH 14/16] Update docs/site/pages/plugin-implementation.mdx Co-authored-by: Ketan Reddy --- docs/site/pages/plugin-implementation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index 0a991c30b..831034b01 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -4,7 +4,7 @@ title: Plugin Implementation # Plugin Implementation -Plugins main capabilities are to extend or add new functionality by tapping into player's pipeline of components via hooks . In this section we'll go over the steps to implement a plugin. +The main purpose of a Plugin is to extend or add new functionality by tapping into Player's pipeline of components via hooks. In this section we'll go over the steps to implement a plugin. We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: From d9574349263413bcc3c86c3f3dd86d88e4ef9eb9 Mon Sep 17 00:00:00 2001 From: afimbres Date: Tue, 6 Feb 2024 10:41:35 -0800 Subject: [PATCH 15/16] docs: plugin implementation 1st observations --- docs/site/pages/plugin-implementation.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index 831034b01..abc797b91 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -6,7 +6,9 @@ title: Plugin Implementation The main purpose of a Plugin is to extend or add new functionality by tapping into Player's pipeline of components via hooks. In this section we'll go over the steps to implement a plugin. -We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, in the `apply` method we'll add the following code: +We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, we'll use the `apply` method which provides access to the Player instance, which then gives access to the necessary hooks. First we define the variables that will be used in the plugin when accessing the hooks: + +```typescript ```typescript export default class StageRevertDataPlugin implements PlayerPlugin { @@ -31,12 +33,12 @@ export default class StageRevertDataPlugin implements PlayerPlugin { ``` We defined variables that will be used in the plugin: - `dataController`: The data orchestrator of our Player instance -- `stageData`: State attribute that comes from the view attribute content to enabling the staging of data -- `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute. +- `stageData`: View attribute that comes from the view state, used for enabling the staging of data +- `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute as well. - `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, only if `stageData` is set to true and the next view name is included in `commitTransitions`. - `GatedDataMiddleware` Data Middleware that will be used to intercept the data pipeline if `stageData` is set to true. -The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `resolveView` hook. By defining our own property method `call` we can intercept the current view state and read the `stageData` and `commitTransitions` properties. +The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `resolveView` hook. Player hooks are implemented with the [Tapable](https://github.com/webpack/tapable) package, so we can use the interception API's `call` method, this triggers everytime the hook is triggered, then we get access to the current view state and read the `stageData` and `commitTransitions` attributes. ```javascript player.hooks.viewController.tap(this.name, (vc) => { From 1630e25f1008c1e5eb805788faacbaa24a5f5431 Mon Sep 17 00:00:00 2001 From: afimbres Date: Tue, 6 Feb 2024 15:43:15 -0800 Subject: [PATCH 16/16] Docs: plugin implementation obervations pt2 --- docs/site/pages/plugin-implementation.mdx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/site/pages/plugin-implementation.mdx b/docs/site/pages/plugin-implementation.mdx index abc797b91..575c46d25 100644 --- a/docs/site/pages/plugin-implementation.mdx +++ b/docs/site/pages/plugin-implementation.mdx @@ -6,9 +6,7 @@ title: Plugin Implementation The main purpose of a Plugin is to extend or add new functionality by tapping into Player's pipeline of components via hooks. In this section we'll go over the steps to implement a plugin. -We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, we'll use the `apply` method which provides access to the Player instance, which then gives access to the necessary hooks. First we define the variables that will be used in the plugin when accessing the hooks: - -```typescript +We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, we'll use the `apply` method which provides access to the Player instance, which then gives access to the necessary hooks. ```typescript export default class StageRevertDataPlugin implements PlayerPlugin { @@ -31,16 +29,16 @@ export default class StageRevertDataPlugin implements PlayerPlugin { { shouldIncludeInvalid: () => true } ); ``` -We defined variables that will be used in the plugin: -- `dataController`: The data orchestrator of our Player instance +For this case we needed to define variables that will store references for the scope the hooks will share: +- `dataController`: Reference to the data controller hook in the Player instance, can be used to read, update or commit new changes to the data model - `stageData`: View attribute that comes from the view state, used for enabling the staging of data - `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute as well. -- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, only if `stageData` is set to true and the next view name is included in `commitTransitions`. -- `GatedDataMiddleware` Data Middleware that will be used to intercept the data pipeline if `stageData` is set to true. +- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, only if `stageData` is set to true and the next target view name is included in `commitTransitions`. +- `GatedDataMiddleware` Instance from `ValidationMiddleware` to be used as a middleware to intercept the data-model pipeline before any data is committed and cache the data instead, only if `stageData` is set to true. The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `resolveView` hook. Player hooks are implemented with the [Tapable](https://github.com/webpack/tapable) package, so we can use the interception API's `call` method, this triggers everytime the hook is triggered, then we get access to the current view state and read the `stageData` and `commitTransitions` attributes. -```javascript +```typescript player.hooks.viewController.tap(this.name, (vc) => { vc.hooks.resolveView.intercept({ call: (view, id, state) => { @@ -54,7 +52,7 @@ The next step is to tap into the necessary Player hooks. First we tap into the ` Next we tap into the `dataController`, so we can scope the data controller instance for future use. Then we tap into the `resolveDataStages` plugin in this data controller instance. If the `stage` property is set to true, we add our `GatedDataMiddleware` to the data pipeline. If not, we return the data pipeline as is. -```javascript +```typescript player.hooks.dataController.tap(this.name, (dc: DataController) => { dataController = dc; @@ -67,7 +65,7 @@ Next we tap into the `dataController`, so we can scope the data controller insta ``` Finally, we tap into the `flowController` so we can intercept the `flow` hook. We then tap into the `transition` hook, which is called every time the player transitions from one view to another. If the `commitTransitions` includes the next view name, we set the `commitShadowModel` flag to true, and commit the data stored in the shadow model through `GatedDataMiddleware` into the data model. Whether the data was committed from the shadow model or not, we clear the shadow model paths in the `GatedDataMiddleware` instance and set the `commitShadowModel` flag to false as final steps. -```javascript +```typescript player.hooks.flowController.tap(this.name, (flowController) => { flowController.hooks.flow.tap(this.name, (flow) => { flow.hooks.transition.tap(this.name, (from, to) => {