diff --git a/README.md b/README.md index b37c2f6..6b39de7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,16 @@ # useFunnel -Manage your funnels declaratively and explicitly. +**Freedom From Details** : Instead of relying directly on the router, it provides instructions on where to route. + +**Flexible Customization** : We advocate funnel management via queryString, but you can also implement it another way via useCoreFunnel. + +**Nested funnel support** : Managing nested funnels is one of the biggest headaches. We offer a way to deal with this + +**Guard support** : Provides a way to block access by malicious users. + +**Separate declaration and use of funnels** : For flexible design, we separate the part that defines the funnel from the part that uses it. + # Quick Start @@ -129,6 +138,20 @@ declare const useCoreFunnel: >( ]; ``` +## funnelOptions + +```tsx +type FunnelOptions> = { + steps: T; + step?: T[number] | undefined; + funnelId: string; +}; +``` + +`funnelOptions` shares the same concept as queryOptions in tanstack query. Used to create a type-safe option object. + +`funnelId` is generally used as the key value of querystring. + ## Guard ```tsx @@ -149,6 +172,24 @@ interface GuardProps { `fallback` is the fallback that will be displayed when the condition is Falsy. +simple Example + +```tsx + 0.5} + onRestrict=() => { + router.replace('/home') + }} + > + { + router.push(`/guard?${controller.createStep("c")}`); + }} + step="b" + /> + +``` + ## useFunnel For App Router ```tsx @@ -185,11 +226,96 @@ createStep(step:string , options:{ searchParams?: URLSearchParams; deleteQueryParams?: string[] | string; qsOptions?: QueryString.IStringifyBaseOptions; - }) +}) ``` For deleteQueryParams, enter the key value of queryParams you want to delete. qsOptions uses StringifyBaseOptions from the qs library. +# Nested Funnel Example + +```tsx +export const aFunnelOptions = () => + funnelOptions({ + funnelId: "sadkl", + steps: ["astart", "ado", "aend"] as const, + }); + +export const bFunnelOptions = () => + funnelOptions({ + funnelId: "sadkl2", + steps: ["bstart", "bdo", "bend"] as const, + }); + +export const NestedFunnel = () => { + const [AFunnel, aController] = useFunnel(aFunnelOptions()); + const [BFunnel, bController] = useFunnel(bFunnelOptions()); + const searchParams = useSearchParams(); + const router = useRouter(); + + return ( +
+ + + { + router.push(`/nested?${aController.createStep("ado")}`); + }} + step={"astart"} + /> + + + { + router.push( + `/nested?${bController.createStep("bstart", { searchParams, deleteQueryParams: aController.funnelId })}` + ); + }} + step={"ado"} + /> + + + { + router.push(`/nested?${aController.createStep("astart")}`); + }} + step={"aend"} + /> + + + + + + { + router.push(`/nested?${bController.createStep("bdo")}`); + }} + step={"bstart"} + /> + + + { + router.push(`/nested?${bController.createStep("bend")}`); + }} + step={"bdo"} + /> + + + { + router.push( + `/nested?${aController.createStep("aend", { searchParams, deleteQueryParams: bController.funnelId })}` + ); + }} + step={"bend"} + /> + + +
+ ); +}; +``` + # Get More Example [App Router Example](https://github.com/XionWCFM/funnel/tree/main/apps/app-router-example) diff --git a/packages/funnel-app-router-adapter/package.json b/packages/funnel-app-router-adapter/package.json index d375822..84f91d3 100644 --- a/packages/funnel-app-router-adapter/package.json +++ b/packages/funnel-app-router-adapter/package.json @@ -1,8 +1,9 @@ { "name": "@xionhub/funnel-app-router-adapter", - "version": "0.0.0", - "private": true, + "version": "0.0.2", + "private": false, "license": "MIT", + "main": "./dist/index.js", "exports": { ".": { "import": { @@ -15,6 +16,7 @@ } } }, + "files": ["dist"], "scripts": { "build": "tsup" }, diff --git a/packages/funnel-client/package.json b/packages/funnel-client/package.json index 3314d5e..2ac78d4 100644 --- a/packages/funnel-client/package.json +++ b/packages/funnel-client/package.json @@ -1,8 +1,10 @@ { "name": "@xionhub/funnel-client", - "version": "0.0.0", - "private": true, + "version": "0.0.2", + "private": false, "license": "MIT", + "main": "./dist/index.js", + "exports": { ".": { "import": { @@ -15,6 +17,8 @@ } } }, + "files": ["dist"], + "scripts": { "build": "tsup" }, diff --git a/packages/funnel-client/src/external/funnel-client.ts b/packages/funnel-client/src/external/funnel-client.ts index bcac342..e7a204d 100644 --- a/packages/funnel-client/src/external/funnel-client.ts +++ b/packages/funnel-client/src/external/funnel-client.ts @@ -15,6 +15,13 @@ export class FunnelClient> { constructor(props: FunnelOptions) { this.funnelId = props.funnelId; this.steps = props.steps; + this.createStep = this.createStep.bind(this); + this.getQueryString = this.getQueryString.bind(this); + this.createStepObject = this.createStepObject.bind(this); + this.deleteStep = this.deleteStep.bind(this); + this.stringifyStep = this.stringifyStep.bind(this); + this.parseQueryString = this.parseQueryString.bind(this); + } createStep(step: T[number], options?: CreateStepOptionsType) { diff --git a/packages/funnel-core/package.json b/packages/funnel-core/package.json index cbef53e..2fb7faf 100644 --- a/packages/funnel-core/package.json +++ b/packages/funnel-core/package.json @@ -1,8 +1,9 @@ { "name": "@xionhub/funnel-core", - "version": "0.0.0", - "private": true, + "version": "0.0.2", + "private": false, "license": "MIT", + "main": "./dist/index.js", "exports": { ".": { "import": { @@ -15,6 +16,7 @@ } } }, + "files": ["dist"], "scripts": { "build": "tsup" },