From 170a3e1b92513f44f6e097692d8df6f8f1301ef0 Mon Sep 17 00:00:00 2001 From: Iha Shin Date: Wed, 21 Aug 2024 23:01:00 +0900 Subject: [PATCH] feat: port future APIs to the Solid integration --- .pnp.cjs | 11 +- demo-solid/esbuild.config.js | 6 +- demo-solid/package.json | 18 +- demo-solid/src/activities/Article.loader.ts | 63 +++++++ demo-solid/src/activities/Article.tsx | 88 +++------- demo-solid/src/activities/Main.loader.ts | 76 +++++++++ demo-solid/src/activities/Main.tsx | 86 ++-------- demo-solid/src/components/ArticleCard.tsx | 2 +- demo-solid/src/components/FeedCard.tsx | 2 +- demo-solid/src/stackflow.ts | 93 ---------- demo-solid/src/stackflow/Stack.ts | 41 +++++ demo-solid/src/stackflow/index.ts | 1 + demo-solid/src/stackflow/stackflow.config.ts | 20 +++ .../stackflow.docs.tsx} | 18 +- demo-solid/src/useFlow.ts | 7 - integrations/solid/esbuild.config.js | 33 +++- integrations/solid/package.json | 29 +++- .../ActivityComponentType.tsx | 0 .../src/{ => __internal__}/MainRenderer.tsx | 2 +- .../src/{ => __internal__}/PluginRenderer.tsx | 10 +- .../StackflowSolidPlugin.ts | 0 .../activity/ActivityProvider.tsx | 0 .../src/{ => __internal__}/activity/index.ts | 1 - .../activity/makeActivityId.ts | 0 .../{ => __internal__}/activity/makeStepId.ts | 0 .../activity/useActivity.ts | 0 .../activity/useActivityParams.ts | 0 .../{ => __internal__}/core/CoreProvider.tsx | 0 .../src/{ => __internal__}/core/index.ts | 0 .../{ => __internal__}/core/useCoreActions.ts | 0 .../{ => __internal__}/core/useCoreState.ts | 0 .../plugins/PluginsProvider.tsx | 0 .../src/{ => __internal__}/plugins/index.ts | 0 .../{ => __internal__}/plugins/usePlugins.ts | 0 .../stack/StackProvider.tsx | 0 .../src/{ => __internal__}/stack/index.ts | 0 .../src/{ => __internal__}/stack/useStack.ts | 0 .../{ => __internal__}/utils/WithRequired.ts | 0 .../src/{ => __internal__}/utils/index.ts | 0 .../src/{ => __internal__}/utils/isBrowser.ts | 0 .../src/{ => __internal__}/utils/isServer.ts | 0 integrations/solid/src/future/Actions.ts | 29 ++++ .../src/future/ActivityComponentType.tsx | 9 + .../solid/src/future/StackComponentType.ts | 5 + integrations/solid/src/future/StepActions.ts | 5 + integrations/solid/src/future/index.ts | 23 +++ integrations/solid/src/future/loader/index.ts | 2 + .../solid/src/future/loader/loaderPlugin.tsx | 100 +++++++++++ .../solid/src/future/loader/useLoaderData.ts | 10 ++ integrations/solid/src/future/makeActions.ts | 80 +++++++++ .../solid/src/future/makeStepActions.ts | 46 +++++ integrations/solid/src/future/stackflow.tsx | 160 ++++++++++++++++++ .../solid/src/future/useActivityParams.ts | 13 ++ integrations/solid/src/future/useFlow.ts | 12 ++ integrations/solid/src/future/useStepFlow.ts | 14 ++ integrations/solid/src/index.ts | 9 +- .../solid/src/{ => stable}/BaseActivities.ts | 2 +- integrations/solid/src/stable/index.ts | 8 + .../solid/src/{ => stable}/stackflow.tsx | 16 +- .../solid/src/{ => stable}/useActions.ts | 6 +- .../solid/src/{ => stable}/useStepActions.ts | 6 +- yarn.lock | 11 +- 62 files changed, 867 insertions(+), 306 deletions(-) create mode 100644 demo-solid/src/activities/Article.loader.ts create mode 100644 demo-solid/src/activities/Main.loader.ts delete mode 100644 demo-solid/src/stackflow.ts create mode 100644 demo-solid/src/stackflow/Stack.ts create mode 100644 demo-solid/src/stackflow/index.ts create mode 100644 demo-solid/src/stackflow/stackflow.config.ts rename demo-solid/src/{stackflow-docs.tsx => stackflow/stackflow.docs.tsx} (65%) delete mode 100644 demo-solid/src/useFlow.ts rename integrations/solid/src/{activity => __internal__}/ActivityComponentType.tsx (100%) rename integrations/solid/src/{ => __internal__}/MainRenderer.tsx (95%) rename integrations/solid/src/{ => __internal__}/PluginRenderer.tsx (94%) rename integrations/solid/src/{ => __internal__}/StackflowSolidPlugin.ts (100%) rename integrations/solid/src/{ => __internal__}/activity/ActivityProvider.tsx (100%) rename integrations/solid/src/{ => __internal__}/activity/index.ts (80%) rename integrations/solid/src/{ => __internal__}/activity/makeActivityId.ts (100%) rename integrations/solid/src/{ => __internal__}/activity/makeStepId.ts (100%) rename integrations/solid/src/{ => __internal__}/activity/useActivity.ts (100%) rename integrations/solid/src/{ => __internal__}/activity/useActivityParams.ts (100%) rename integrations/solid/src/{ => __internal__}/core/CoreProvider.tsx (100%) rename integrations/solid/src/{ => __internal__}/core/index.ts (100%) rename integrations/solid/src/{ => __internal__}/core/useCoreActions.ts (100%) rename integrations/solid/src/{ => __internal__}/core/useCoreState.ts (100%) rename integrations/solid/src/{ => __internal__}/plugins/PluginsProvider.tsx (100%) rename integrations/solid/src/{ => __internal__}/plugins/index.ts (100%) rename integrations/solid/src/{ => __internal__}/plugins/usePlugins.ts (100%) rename integrations/solid/src/{ => __internal__}/stack/StackProvider.tsx (100%) rename integrations/solid/src/{ => __internal__}/stack/index.ts (100%) rename integrations/solid/src/{ => __internal__}/stack/useStack.ts (100%) rename integrations/solid/src/{ => __internal__}/utils/WithRequired.ts (100%) rename integrations/solid/src/{ => __internal__}/utils/index.ts (100%) rename integrations/solid/src/{ => __internal__}/utils/isBrowser.ts (100%) rename integrations/solid/src/{ => __internal__}/utils/isServer.ts (100%) create mode 100644 integrations/solid/src/future/Actions.ts create mode 100644 integrations/solid/src/future/ActivityComponentType.tsx create mode 100644 integrations/solid/src/future/StackComponentType.ts create mode 100644 integrations/solid/src/future/StepActions.ts create mode 100644 integrations/solid/src/future/index.ts create mode 100644 integrations/solid/src/future/loader/index.ts create mode 100644 integrations/solid/src/future/loader/loaderPlugin.tsx create mode 100644 integrations/solid/src/future/loader/useLoaderData.ts create mode 100644 integrations/solid/src/future/makeActions.ts create mode 100644 integrations/solid/src/future/makeStepActions.ts create mode 100644 integrations/solid/src/future/stackflow.tsx create mode 100644 integrations/solid/src/future/useActivityParams.ts create mode 100644 integrations/solid/src/future/useFlow.ts create mode 100644 integrations/solid/src/future/useStepFlow.ts rename integrations/solid/src/{ => stable}/BaseActivities.ts (79%) create mode 100644 integrations/solid/src/stable/index.ts rename integrations/solid/src/{ => stable}/stackflow.tsx (95%) rename integrations/solid/src/{ => stable}/useActions.ts (93%) rename integrations/solid/src/{ => stable}/useStepActions.ts (87%) diff --git a/.pnp.cjs b/.pnp.cjs index 626cb87b3..3c0426396 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -3393,6 +3393,7 @@ const RAW_RUNTIME_STATE = ["@seed-design/design-token", "npm:1.0.3"],\ ["@seed-design/stylesheet", "npm:1.0.4"],\ ["@stackflow/compat-await-push", "virtual:f02c81452ff867c51068ba24d1154dc4fd3d1c7604f453ffee4229d2511559426c90d236211f3a0cdc7936f57f86390b27d2faabd3ea70d6ab368b4517c54f80#workspace:extensions/compat-await-push"],\ + ["@stackflow/config", "workspace:config"],\ ["@stackflow/core", "workspace:core"],\ ["@stackflow/esbuild-config", "workspace:packages/esbuild-config"],\ ["@stackflow/link", "virtual:f02c81452ff867c51068ba24d1154dc4fd3d1c7604f453ffee4229d2511559426c90d236211f3a0cdc7936f57f86390b27d2faabd3ea70d6ab368b4517c54f80#workspace:extensions/link"],\ @@ -3416,7 +3417,8 @@ const RAW_RUNTIME_STATE = ["solid-js", "npm:1.8.18"],\ ["typescript", "patch:typescript@npm%3A5.5.3#optional!builtin::version=5.5.3&hash=379a07"],\ ["vite", "virtual:2c30557d8ca5e7c67e7558d45bc44bef6c7a622b34a97fa8102f3235f92769c87777d34ed37059c12d8f3a21841ea06cf4badc5dc796697b0f765c17db6e24e5#npm:5.3.2"],\ - ["vite-plugin-solid", "virtual:f02c81452ff867c51068ba24d1154dc4fd3d1c7604f453ffee4229d2511559426c90d236211f3a0cdc7936f57f86390b27d2faabd3ea70d6ab368b4517c54f80#npm:2.10.2"]\ + ["vite-plugin-solid", "virtual:f02c81452ff867c51068ba24d1154dc4fd3d1c7604f453ffee4229d2511559426c90d236211f3a0cdc7936f57f86390b27d2faabd3ea70d6ab368b4517c54f80#npm:2.10.2"],\ + ["zod", "npm:3.23.8"]\ ],\ "linkType": "SOFT"\ }]\ @@ -3783,6 +3785,7 @@ const RAW_RUNTIME_STATE = ["url-pattern", "npm:1.0.3"]\ ],\ "packagePeers": [\ + "@stackflow/config",\ "@stackflow/core",\ "@stackflow/solid",\ "@types/solid-js",\ @@ -4159,11 +4162,14 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/__virtual__/@stackflow-solid-virtual-25461bd459/1/integrations/solid/",\ "packageDependencies": [\ ["@stackflow/solid", "virtual:669046a185e83900af978519e5adddf8e8f1f8fed824849248ba56cf8fcd4e4208872f27e14c3c844d3b769f42be1ba6e0aa90f12df9fa6c38a55aedee211f53#workspace:integrations/solid"],\ + ["@stackflow/config", "workspace:config"],\ ["@stackflow/core", "workspace:core"],\ ["@stackflow/esbuild-config", "workspace:packages/esbuild-config"],\ ["@types/solid-js", null],\ + ["@types/stackflow__config", null],\ ["@types/stackflow__core", null],\ ["esbuild", "npm:0.23.0"],\ + ["esbuild-plugin-file-path-extensions", "npm:2.1.2"],\ ["esbuild-plugin-solid", "virtual:669046a185e83900af978519e5adddf8e8f1f8fed824849248ba56cf8fcd4e4208872f27e14c3c844d3b769f42be1ba6e0aa90f12df9fa6c38a55aedee211f53#patch:esbuild-plugin-solid@npm%3A0.6.0#~/.yarn/patches/esbuild-plugin-solid-npm-0.6.0-49835b85dc.patch::version=0.6.0&hash=bf8c52"],\ ["rimraf", "npm:3.0.2"],\ ["solid-js", "npm:1.8.18"],\ @@ -4172,6 +4178,7 @@ const RAW_RUNTIME_STATE = "packagePeers": [\ "@stackflow/core",\ "@types/solid-js",\ + "@types/stackflow__config",\ "@types/stackflow__core",\ "solid-js"\ ],\ @@ -4181,9 +4188,11 @@ const RAW_RUNTIME_STATE = "packageLocation": "./integrations/solid/",\ "packageDependencies": [\ ["@stackflow/solid", "workspace:integrations/solid"],\ + ["@stackflow/config", "workspace:config"],\ ["@stackflow/core", "workspace:core"],\ ["@stackflow/esbuild-config", "workspace:packages/esbuild-config"],\ ["esbuild", "npm:0.23.0"],\ + ["esbuild-plugin-file-path-extensions", "npm:2.1.2"],\ ["esbuild-plugin-solid", "virtual:669046a185e83900af978519e5adddf8e8f1f8fed824849248ba56cf8fcd4e4208872f27e14c3c844d3b769f42be1ba6e0aa90f12df9fa6c38a55aedee211f53#patch:esbuild-plugin-solid@npm%3A0.6.0#~/.yarn/patches/esbuild-plugin-solid-npm-0.6.0-49835b85dc.patch::version=0.6.0&hash=bf8c52"],\ ["rimraf", "npm:3.0.2"],\ ["solid-js", "npm:1.8.18"],\ diff --git a/demo-solid/esbuild.config.js b/demo-solid/esbuild.config.js index df7b28b6f..6e7fc5624 100644 --- a/demo-solid/esbuild.config.js +++ b/demo-solid/esbuild.config.js @@ -13,7 +13,8 @@ const external = Object.keys({ Promise.all([ context({ ...config({ - entryPoints: ["./src/stackflow-docs.tsx"], + entryPoints: ["./src/stackflow/stackflow.docs.tsx"], + outdir: "./dist/stackflow", vanillaExtractExternal: ["@seed-design"], plugins: [solidPlugin({ solid: { generate: "dom" } })], }), @@ -24,7 +25,8 @@ Promise.all([ ), context({ ...config({ - entryPoints: ["./src/stackflow-docs.tsx"], + entryPoints: ["./src/stackflow/stackflow.docs.tsx"], + outdir: "./dist/stackflow", vanillaExtractExternal: ["@seed-design"], plugins: [solidPlugin({ solid: { generate: "dom" } })], }), diff --git a/demo-solid/package.json b/demo-solid/package.json index 5a55ffccd..aa23c4690 100644 --- a/demo-solid/package.json +++ b/demo-solid/package.json @@ -6,15 +6,15 @@ "type": "module", "exports": { ".": { - "types": "./dist/stackflow-docs.d.ts", - "require": "./dist/stackflow-docs.js", - "import": "./dist/stackflow-docs.mjs" + "types": "./dist/stackflow/stackflow.docs.d.ts", + "require": "./dist/stackflow/stackflow.docs.js", + "import": "./dist/stackflow/stackflow.docs.mjs" }, - "./style.css": "./dist/stackflow-docs.css" + "./style.css": "./dist/stackflow/stackflow.docs.css" }, - "main": "./dist/stackflow-docs.js", - "module": "./dist/stackflow-docs.mjs", - "types": "./dist/stackflow-docs.d.ts", + "main": "./dist/stackflow/stackflow.docs.js", + "module": "./dist/stackflow/stackflow.docs.mjs", + "types": "./dist/stackflow/stackflow.docs.d.ts", "files": [ "dist", "src" @@ -33,6 +33,7 @@ "@seed-design/design-token": "^1.0.3", "@seed-design/stylesheet": "^1.0.4", "@stackflow/compat-await-push": "^1.1.12", + "@stackflow/config": "^1.1.0", "@stackflow/core": "^1.1.0", "@stackflow/link": "^1.4.4", "@stackflow/plugin-basic-ui": "^1.9.1", @@ -58,7 +59,8 @@ "esbuild-plugin-solid": "^0.6.0", "rimraf": "^3.0.2", "typescript": "^5.5.3", - "vite-plugin-solid": "^2.10.2" + "vite-plugin-solid": "^2.10.2", + "zod": "^3.23.8" }, "ultra": { "concurrent": [ diff --git a/demo-solid/src/activities/Article.loader.ts b/demo-solid/src/activities/Article.loader.ts new file mode 100644 index 000000000..9bdd81325 --- /dev/null +++ b/demo-solid/src/activities/Article.loader.ts @@ -0,0 +1,63 @@ +import type { ActivityLoaderArgs } from "@stackflow/config"; + +export function articleLoader({ params }: ActivityLoaderArgs<"Article">) { + const imageUrl = `https://picsum.photos/800/800/?id=${params.articleId}`; + + const recommenderCards = [ + { + articleId: "25140667", + price: 41, + title: "Ran", + }, + { + articleId: "60547101", + price: 24, + title: "Rest", + }, + { + articleId: "34751776", + price: 42, + title: "Those", + }, + { + articleId: "04114554", + price: 12, + title: "Beauty", + }, + { + articleId: "81339443", + price: 3, + title: "Mighty", + }, + { + articleId: "44738871", + price: 1, + title: "Afternoon", + }, + { + articleId: "57388513", + price: 31, + title: "Brown", + }, + { + articleId: "60883443", + price: 49, + title: "Musical", + }, + { + articleId: "00932094", + price: 26, + title: "Occasionally", + }, + { + articleId: "10749683", + price: 35, + title: "Having", + }, + ]; + + return { + imageUrl, + recommenderCards, + }; +} diff --git a/demo-solid/src/activities/Article.tsx b/demo-solid/src/activities/Article.tsx index 3847c59cf..32e166373 100644 --- a/demo-solid/src/activities/Article.tsx +++ b/demo-solid/src/activities/Article.tsx @@ -1,78 +1,28 @@ -import type { ActivityComponentType } from "@stackflow/solid"; -import { useActivityParams } from "@stackflow/solid"; -import { For, createMemo } from "solid-js"; +import { + type ActivityComponentType, + useActivityParams, + useLoaderData, +} from "@stackflow/solid/future"; +import { For } from "solid-js"; import ArticleCard from "../components/ArticleCard"; import ArticleProfile from "../components/ArticleProfile"; import Layout from "../components/Layout"; import * as css from "./Article.css"; +import type { articleLoader } from "./Article.loader"; -const recommenderCard = [ - { - articleId: "25140667", - price: 41, - title: "Ran", - }, - { - articleId: "60547101", - price: 24, - title: "Rest", - }, - { - articleId: "34751776", - price: 42, - title: "Those", - }, - { - articleId: "04114554", - price: 12, - title: "Beauty", - }, - { - articleId: "81339443", - price: 3, - title: "Mighty", - }, - { - articleId: "44738871", - price: 1, - title: "Afternoon", - }, - { - articleId: "57388513", - price: 31, - title: "Brown", - }, - { - articleId: "60883443", - price: 49, - title: "Musical", - }, - { - articleId: "00932094", - price: 26, - title: "Occasionally", - }, - { - articleId: "10749683", - price: 35, - title: "Having", - }, -]; - -export interface ArticleParams { - articleId: string; - title: string; +declare module "@stackflow/config" { + interface Register { + Article: { + articleId: string; + title?: string; + }; + } } -const Article: ActivityComponentType = () => { - const activityParams = useActivityParams<{ - articleId: string; - title: string; - }>(); - const imageUrl = createMemo( - () => `https://picsum.photos/800/800/?id=${activityParams()?.articleId}`, - ); +const Article: ActivityComponentType<"Article"> = () => { + const activityParams = useActivityParams<"Article">(); + const data = useLoaderData(); return ( @@ -80,7 +30,7 @@ const Article: ActivityComponentType = () => {
{activityParams()?.title} = () => {
Other Items by Emila
- + {(card) => }
diff --git a/demo-solid/src/activities/Main.loader.ts b/demo-solid/src/activities/Main.loader.ts new file mode 100644 index 000000000..041c04814 --- /dev/null +++ b/demo-solid/src/activities/Main.loader.ts @@ -0,0 +1,76 @@ +export function mainLoader() { + return { + cards: [ + { + articleId: "02542470", + price: 41, + title: "Master", + region: "Nagevan", + daysAgo: 4, + }, + { + articleId: "11257089", + price: 24, + title: "Wild", + region: "Inguima", + daysAgo: 4, + }, + { + articleId: "08407137", + price: 42, + title: "Universe", + region: "Litenego", + daysAgo: 4, + }, + { + articleId: "32979422", + price: 12, + title: "Private", + region: "Umumtaw", + daysAgo: 6, + }, + { + articleId: "37998208", + price: 3, + title: "Harbor", + region: "Gubdidgi", + daysAgo: 3, + }, + { + articleId: "01695878", + price: 1, + title: "Valuable", + region: "Jumjelewu", + daysAgo: 1, + }, + { + articleId: "09792471", + price: 31, + title: "Also", + region: "Salhega", + daysAgo: 1, + }, + { + articleId: "23939055", + price: 49, + title: "Ever", + region: "Jaifuup", + daysAgo: 9, + }, + { + articleId: "94689745", + price: 26, + title: "Production", + region: "Idcipwel", + daysAgo: 3, + }, + { + articleId: "49322156", + price: 35, + title: "Chest", + region: "Ajapaktar", + daysAgo: 7, + }, + ], + }; +} diff --git a/demo-solid/src/activities/Main.tsx b/demo-solid/src/activities/Main.tsx index 29e422f03..3e6986fab 100644 --- a/demo-solid/src/activities/Main.tsx +++ b/demo-solid/src/activities/Main.tsx @@ -1,4 +1,5 @@ -import type { ActivityComponentType } from "@stackflow/solid"; +import type { ActivityComponentType } from "@stackflow/solid/future"; +import { useLoaderData } from "@stackflow/solid/future"; import { For } from "solid-js"; import IconBell from "../assets/IconBell"; @@ -9,81 +10,16 @@ import BottomTab from "../components/BottomTab"; import FeedCard from "../components/FeedCard"; import Layout from "../components/Layout"; import * as css from "./Main.css"; +import type { mainLoader } from "./Main.loader"; -const cards = [ - { - articleId: "02542470", - price: 41, - title: "Master", - region: "Nagevan", - daysAgo: 4, - }, - { - articleId: "11257089", - price: 24, - title: "Wild", - region: "Inguima", - daysAgo: 4, - }, - { - articleId: "08407137", - price: 42, - title: "Universe", - region: "Litenego", - daysAgo: 4, - }, - { - articleId: "32979422", - price: 12, - title: "Private", - region: "Umumtaw", - daysAgo: 6, - }, - { - articleId: "37998208", - price: 3, - title: "Harbor", - region: "Gubdidgi", - daysAgo: 3, - }, - { - articleId: "01695878", - price: 1, - title: "Valuable", - region: "Jumjelewu", - daysAgo: 1, - }, - { - articleId: "09792471", - price: 31, - title: "Also", - region: "Salhega", - daysAgo: 1, - }, - { - articleId: "23939055", - price: 49, - title: "Ever", - region: "Jaifuup", - daysAgo: 9, - }, - { - articleId: "94689745", - price: 26, - title: "Production", - region: "Idcipwel", - daysAgo: 3, - }, - { - articleId: "49322156", - price: 35, - title: "Chest", - region: "Ajapaktar", - daysAgo: 7, - }, -]; +declare module "@stackflow/config" { + interface Register { + Main: {}; + } +} -const Main: ActivityComponentType = () => { +const Main: ActivityComponentType<"Main"> = () => { + const data = useLoaderData(); const appBarLeft = () => (
Woolston @@ -110,7 +46,7 @@ const Main: ActivityComponentType = () => { >
- {(card) => } + {(card) => }
diff --git a/demo-solid/src/components/ArticleCard.tsx b/demo-solid/src/components/ArticleCard.tsx index dc25e113d..d9d06a76c 100644 --- a/demo-solid/src/components/ArticleCard.tsx +++ b/demo-solid/src/components/ArticleCard.tsx @@ -1,5 +1,5 @@ +import { useFlow } from "@stackflow/solid/future"; import { type Component, createMemo } from "solid-js"; -import { useFlow } from "../useFlow"; import * as css from "./ArticleCard.css"; interface ArticleCardProps { diff --git a/demo-solid/src/components/FeedCard.tsx b/demo-solid/src/components/FeedCard.tsx index b34cc4da3..5daf1a5c4 100644 --- a/demo-solid/src/components/FeedCard.tsx +++ b/demo-solid/src/components/FeedCard.tsx @@ -1,5 +1,5 @@ +import { useFlow } from "@stackflow/solid/future"; import { type Component, createMemo } from "solid-js"; -import { useFlow } from "../useFlow"; import * as css from "./FeedCard.css"; interface FeedCardProps { diff --git a/demo-solid/src/stackflow.ts b/demo-solid/src/stackflow.ts deleted file mode 100644 index 9ef01bda9..000000000 --- a/demo-solid/src/stackflow.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { vars } from "@seed-design/design-token"; -import { basicUIPlugin } from "@stackflow/plugin-basic-ui/solid"; -import { devtoolsPlugin } from "@stackflow/plugin-devtools"; -import { historySyncPlugin } from "@stackflow/plugin-history-sync/solid"; -import { mapInitialActivityPlugin } from "@stackflow/plugin-map-initial-activity"; -import { basicRendererPlugin } from "@stackflow/plugin-renderer-basic/solid"; -import { stackflow } from "@stackflow/solid"; -import { decompressFromEncodedURIComponent } from "lz-string"; - -import Article from "./activities/Article"; -import Main from "./activities/Main"; - -export const { Stack, activities } = stackflow({ - transitionDuration: 150, - activities: { - Main, - Article: { - component: Article, - paramsSchema: { - type: "object", - properties: { - articleId: { - type: "string", - }, - title: { - type: "string", - }, - }, - required: ["articleId", "title"], - }, - }, - }, - plugins: [ - devtoolsPlugin(), - basicRendererPlugin(), - basicUIPlugin({ - theme: "cupertino", - backgroundColor: vars.$semantic.color.paperDefault, - appBar: { - textColor: vars.$scale.color.gray900, - iconColor: vars.$scale.color.gray900, - borderColor: vars.$semantic.color.divider3, - backButton: { - ariaLabel: "뒤로 가기", - }, - closeButton: { - ariaLabel: "닫기", - }, - }, - }), - historySyncPlugin({ - routes: { - Main: "/", - Article: "/articles/:articleId", - }, - fallbackActivity: () => "Main", - }), - mapInitialActivityPlugin({ - mapper(url) { - try { - if (!url.pathname.startsWith("/.lzstring/")) { - return null; - } - - const [, encodedString] = url.pathname.split("/.lzstring/"); - - const parsed = JSON.parse( - decompressFromEncodedURIComponent(encodedString), - ); - - if (typeof parsed.activityName !== "string") { - return null; - } - if ( - typeof parsed.activityParams !== "undefined" && - typeof parsed.activityParams !== "object" - ) { - return null; - } - - return { - activityName: parsed.activityName, - activityParams: parsed.activityParams || {}, - }; - } catch { - return null; - } - }, - }), - ], -}); - -export type TypeActivities = typeof activities; diff --git a/demo-solid/src/stackflow/Stack.ts b/demo-solid/src/stackflow/Stack.ts new file mode 100644 index 000000000..8fc8cba27 --- /dev/null +++ b/demo-solid/src/stackflow/Stack.ts @@ -0,0 +1,41 @@ +import { vars } from "@seed-design/design-token"; +import { basicUIPlugin } from "@stackflow/plugin-basic-ui/solid"; +import { historySyncPlugin } from "@stackflow/plugin-history-sync/solid"; +import { basicRendererPlugin } from "@stackflow/plugin-renderer-basic/solid"; +import { stackflow } from "@stackflow/solid/future"; +import { config } from "./stackflow.config"; + +import Article from "../activities/Article"; +import Main from "../activities/Main"; + +export const { Stack, actions } = stackflow({ + config, + components: { + Main, + Article, + }, + plugins: [ + basicRendererPlugin(), + basicUIPlugin({ + theme: "cupertino", + backgroundColor: vars.$semantic.color.paperDefault, + appBar: { + textColor: vars.$scale.color.gray900, + iconColor: vars.$scale.color.gray900, + borderColor: vars.$semantic.color.divider3, + backButton: { + ariaLabel: "뒤로 가기", + }, + closeButton: { + ariaLabel: "닫기", + }, + }, + }), + historySyncPlugin({ + config, + fallbackActivity: () => "Main", + }), + ], +}); + +export type Actions = typeof actions; diff --git a/demo-solid/src/stackflow/index.ts b/demo-solid/src/stackflow/index.ts new file mode 100644 index 000000000..92c29a03d --- /dev/null +++ b/demo-solid/src/stackflow/index.ts @@ -0,0 +1 @@ +export * from "./Stack"; diff --git a/demo-solid/src/stackflow/stackflow.config.ts b/demo-solid/src/stackflow/stackflow.config.ts new file mode 100644 index 000000000..daa478073 --- /dev/null +++ b/demo-solid/src/stackflow/stackflow.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "@stackflow/config"; +import { articleLoader } from "../activities/Article.loader"; +import { mainLoader } from "../activities/Main.loader"; + +export const config = defineConfig({ + activities: [ + { + name: "Main", + path: "/", + loader: mainLoader, + }, + { + name: "Article", + path: "/articles/:articleId", + loader: articleLoader, + }, + ], + transitionDuration: 270, + initialActivity: () => "Main", +}); diff --git a/demo-solid/src/stackflow-docs.tsx b/demo-solid/src/stackflow/stackflow.docs.tsx similarity index 65% rename from demo-solid/src/stackflow-docs.tsx rename to demo-solid/src/stackflow/stackflow.docs.tsx index 6715e8382..c33a08073 100644 --- a/demo-solid/src/stackflow-docs.tsx +++ b/demo-solid/src/stackflow/stackflow.docs.tsx @@ -1,15 +1,19 @@ import { vars } from "@seed-design/design-token"; import { basicUIPlugin } from "@stackflow/plugin-basic-ui/solid"; import { basicRendererPlugin } from "@stackflow/plugin-renderer-basic/solid"; -import { stackflow } from "@stackflow/solid"; +import { stackflow } from "@stackflow/solid/future"; import { render } from "solid-js/web"; +import { config } from "./stackflow.config"; -import { activities } from "./stackflow"; +import Article from "../activities/Article"; +import Main from "../activities/Main"; const { Stack } = stackflow({ - transitionDuration: 350, - activities, - initialActivity: () => "Main", + config, + components: { + Main, + Article, + }, plugins: [ basicRendererPlugin(), basicUIPlugin({ @@ -24,6 +28,6 @@ const { Stack } = stackflow({ ], }); -export const renderApp = (el: HTMLElement, initialContext?: any) => { - render(() => , el); +export const renderApp = (el: HTMLElement) => { + render(() => , el); }; diff --git a/demo-solid/src/useFlow.ts b/demo-solid/src/useFlow.ts deleted file mode 100644 index d59ecb986..000000000 --- a/demo-solid/src/useFlow.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useActions } from "@stackflow/solid"; - -import type { TypeActivities } from "./stackflow"; - -export function useFlow() { - return useActions(); -} diff --git a/integrations/solid/esbuild.config.js b/integrations/solid/esbuild.config.js index 9b244d080..b96bf786f 100644 --- a/integrations/solid/esbuild.config.js +++ b/integrations/solid/esbuild.config.js @@ -1,5 +1,8 @@ const { context } = require("esbuild"); const config = require("@stackflow/esbuild-config"); +const { + esbuildPluginFilePathExtensions, +} = require("esbuild-plugin-file-path-extensions"); const { solidPlugin } = require("esbuild-plugin-solid"); const pkg = require("./package.json"); @@ -12,19 +15,41 @@ const watch = process.argv.includes("--watch"); Promise.all( [true, false].flatMap((jsx) => [ - { format: "cjs", extPrefix: "" }, - { format: "esm", extPrefix: "m" }, - ].map(({ format, extPrefix }) => + { + format: "cjs", + extPrefix: "", + bundle: false, + external: undefined, + }, + { + format: "esm", + extPrefix: "m", + bundle: true, + external, + plugins: [ + esbuildPluginFilePathExtensions({ + esmExtension: jsx ? "mjsx" : "mjs", + }), + ], + platform: "node", + }, + ].map(({ format, extPrefix, bundle, external, plugins, platform }) => context({ ...config({ - plugins: !jsx ? [solidPlugin({ solid: { generate: "dom" } })] : [], + entryPoints: ["./src/**/*"], + plugins: [ + ...(!jsx ? [solidPlugin({ solid: { generate: "dom" } })] : []), + ...(plugins ?? []), + ], }), + bundle, format, outExtension: jsx ? { ".js": `.${extPrefix}jsx` } : { ".js": `.${extPrefix}js` }, jsx: "preserve", external, + platform, }).then((ctx) => watch ? ctx.watch() : ctx.rebuild().then(() => ctx.dispose()), ), diff --git a/integrations/solid/package.json b/integrations/solid/package.json index 9a4d9103c..d467ea184 100644 --- a/integrations/solid/package.json +++ b/integrations/solid/package.json @@ -18,6 +18,28 @@ "solid": "./dist/index.mjsx", "default": "./dist/index.mjs" } + }, + "./stable": { + "types": "./dist/stable/index.d.ts", + "require": { + "solid": "./dist/stable/index.jsx", + "default": "./dist/stable/index.js" + }, + "import": { + "solid": "./dist/stable/index.mjsx", + "default": "./dist/stable/index.mjs" + } + }, + "./future": { + "types": "./dist/future/index.d.ts", + "require": { + "solid": "./dist/future/index.jsx", + "default": "./dist/future/index.js" + }, + "import": { + "solid": "./dist/future/index.mjsx", + "default": "./dist/future/index.mjs" + } } }, "main": "./dist/index.js", @@ -37,16 +59,19 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "@stackflow/core": "^1.0.13", + "@stackflow/config": "^1.1.0", + "@stackflow/core": "^1.1.0", "@stackflow/esbuild-config": "^1.0.3", "esbuild": "^0.23.0", + "esbuild-plugin-file-path-extensions": "^2.1.2", "esbuild-plugin-solid": "patch:esbuild-plugin-solid@npm%3A0.6.0#~/.yarn/patches/esbuild-plugin-solid-npm-0.6.0-49835b85dc.patch", "rimraf": "^3.0.2", "solid-js": "^1.8.18", "typescript": "^5.5.3" }, "peerDependencies": { - "@stackflow/core": "^1", + "@stackflow/config": "^1.0.1-canary.0", + "@stackflow/core": "^1.1.0-canary.0", "solid-js": ">=1.4.0" }, "publishConfig": { diff --git a/integrations/solid/src/activity/ActivityComponentType.tsx b/integrations/solid/src/__internal__/ActivityComponentType.tsx similarity index 100% rename from integrations/solid/src/activity/ActivityComponentType.tsx rename to integrations/solid/src/__internal__/ActivityComponentType.tsx diff --git a/integrations/solid/src/MainRenderer.tsx b/integrations/solid/src/__internal__/MainRenderer.tsx similarity index 95% rename from integrations/solid/src/MainRenderer.tsx rename to integrations/solid/src/__internal__/MainRenderer.tsx index ab51d984e..37a9b401f 100644 --- a/integrations/solid/src/MainRenderer.tsx +++ b/integrations/solid/src/__internal__/MainRenderer.tsx @@ -1,8 +1,8 @@ import type { Component } from "solid-js"; import { mergeProps } from "solid-js"; +import type { ActivityComponentType } from "./ActivityComponentType"; import PluginRenderer, { createPluginRenderProps } from "./PluginRenderer"; -import type { ActivityComponentType } from "./activity"; import { useCoreState } from "./core"; import { usePlugins } from "./plugins"; import type { WithRequired } from "./utils"; diff --git a/integrations/solid/src/PluginRenderer.tsx b/integrations/solid/src/__internal__/PluginRenderer.tsx similarity index 94% rename from integrations/solid/src/PluginRenderer.tsx rename to integrations/solid/src/__internal__/PluginRenderer.tsx index de46a977d..d1c135134 100644 --- a/integrations/solid/src/PluginRenderer.tsx +++ b/integrations/solid/src/__internal__/PluginRenderer.tsx @@ -1,15 +1,9 @@ import type { Activity, Stack } from "@stackflow/core"; import type { Accessor, Component, JSXElement } from "solid-js"; -import { - createMemo, - getOwner, - mapArray, - mergeProps, - runWithOwner, -} from "solid-js"; +import { createMemo, mergeProps } from "solid-js"; +import type { ActivityComponentType } from "./ActivityComponentType"; import type { StackflowSolidPlugin } from "./StackflowSolidPlugin"; -import type { ActivityComponentType } from "./activity"; import { ActivityProvider } from "./activity"; import { useCoreState } from "./core"; import { usePlugins } from "./plugins"; diff --git a/integrations/solid/src/StackflowSolidPlugin.ts b/integrations/solid/src/__internal__/StackflowSolidPlugin.ts similarity index 100% rename from integrations/solid/src/StackflowSolidPlugin.ts rename to integrations/solid/src/__internal__/StackflowSolidPlugin.ts diff --git a/integrations/solid/src/activity/ActivityProvider.tsx b/integrations/solid/src/__internal__/activity/ActivityProvider.tsx similarity index 100% rename from integrations/solid/src/activity/ActivityProvider.tsx rename to integrations/solid/src/__internal__/activity/ActivityProvider.tsx diff --git a/integrations/solid/src/activity/index.ts b/integrations/solid/src/__internal__/activity/index.ts similarity index 80% rename from integrations/solid/src/activity/index.ts rename to integrations/solid/src/__internal__/activity/index.ts index 89e898aff..80001dcd6 100644 --- a/integrations/solid/src/activity/index.ts +++ b/integrations/solid/src/__internal__/activity/index.ts @@ -1,4 +1,3 @@ -export * from "./ActivityComponentType"; export * from "./ActivityProvider"; export * from "./makeActivityId"; export * from "./makeStepId"; diff --git a/integrations/solid/src/activity/makeActivityId.ts b/integrations/solid/src/__internal__/activity/makeActivityId.ts similarity index 100% rename from integrations/solid/src/activity/makeActivityId.ts rename to integrations/solid/src/__internal__/activity/makeActivityId.ts diff --git a/integrations/solid/src/activity/makeStepId.ts b/integrations/solid/src/__internal__/activity/makeStepId.ts similarity index 100% rename from integrations/solid/src/activity/makeStepId.ts rename to integrations/solid/src/__internal__/activity/makeStepId.ts diff --git a/integrations/solid/src/activity/useActivity.ts b/integrations/solid/src/__internal__/activity/useActivity.ts similarity index 100% rename from integrations/solid/src/activity/useActivity.ts rename to integrations/solid/src/__internal__/activity/useActivity.ts diff --git a/integrations/solid/src/activity/useActivityParams.ts b/integrations/solid/src/__internal__/activity/useActivityParams.ts similarity index 100% rename from integrations/solid/src/activity/useActivityParams.ts rename to integrations/solid/src/__internal__/activity/useActivityParams.ts diff --git a/integrations/solid/src/core/CoreProvider.tsx b/integrations/solid/src/__internal__/core/CoreProvider.tsx similarity index 100% rename from integrations/solid/src/core/CoreProvider.tsx rename to integrations/solid/src/__internal__/core/CoreProvider.tsx diff --git a/integrations/solid/src/core/index.ts b/integrations/solid/src/__internal__/core/index.ts similarity index 100% rename from integrations/solid/src/core/index.ts rename to integrations/solid/src/__internal__/core/index.ts diff --git a/integrations/solid/src/core/useCoreActions.ts b/integrations/solid/src/__internal__/core/useCoreActions.ts similarity index 100% rename from integrations/solid/src/core/useCoreActions.ts rename to integrations/solid/src/__internal__/core/useCoreActions.ts diff --git a/integrations/solid/src/core/useCoreState.ts b/integrations/solid/src/__internal__/core/useCoreState.ts similarity index 100% rename from integrations/solid/src/core/useCoreState.ts rename to integrations/solid/src/__internal__/core/useCoreState.ts diff --git a/integrations/solid/src/plugins/PluginsProvider.tsx b/integrations/solid/src/__internal__/plugins/PluginsProvider.tsx similarity index 100% rename from integrations/solid/src/plugins/PluginsProvider.tsx rename to integrations/solid/src/__internal__/plugins/PluginsProvider.tsx diff --git a/integrations/solid/src/plugins/index.ts b/integrations/solid/src/__internal__/plugins/index.ts similarity index 100% rename from integrations/solid/src/plugins/index.ts rename to integrations/solid/src/__internal__/plugins/index.ts diff --git a/integrations/solid/src/plugins/usePlugins.ts b/integrations/solid/src/__internal__/plugins/usePlugins.ts similarity index 100% rename from integrations/solid/src/plugins/usePlugins.ts rename to integrations/solid/src/__internal__/plugins/usePlugins.ts diff --git a/integrations/solid/src/stack/StackProvider.tsx b/integrations/solid/src/__internal__/stack/StackProvider.tsx similarity index 100% rename from integrations/solid/src/stack/StackProvider.tsx rename to integrations/solid/src/__internal__/stack/StackProvider.tsx diff --git a/integrations/solid/src/stack/index.ts b/integrations/solid/src/__internal__/stack/index.ts similarity index 100% rename from integrations/solid/src/stack/index.ts rename to integrations/solid/src/__internal__/stack/index.ts diff --git a/integrations/solid/src/stack/useStack.ts b/integrations/solid/src/__internal__/stack/useStack.ts similarity index 100% rename from integrations/solid/src/stack/useStack.ts rename to integrations/solid/src/__internal__/stack/useStack.ts diff --git a/integrations/solid/src/utils/WithRequired.ts b/integrations/solid/src/__internal__/utils/WithRequired.ts similarity index 100% rename from integrations/solid/src/utils/WithRequired.ts rename to integrations/solid/src/__internal__/utils/WithRequired.ts diff --git a/integrations/solid/src/utils/index.ts b/integrations/solid/src/__internal__/utils/index.ts similarity index 100% rename from integrations/solid/src/utils/index.ts rename to integrations/solid/src/__internal__/utils/index.ts diff --git a/integrations/solid/src/utils/isBrowser.ts b/integrations/solid/src/__internal__/utils/isBrowser.ts similarity index 100% rename from integrations/solid/src/utils/isBrowser.ts rename to integrations/solid/src/__internal__/utils/isBrowser.ts diff --git a/integrations/solid/src/utils/isServer.ts b/integrations/solid/src/__internal__/utils/isServer.ts similarity index 100% rename from integrations/solid/src/utils/isServer.ts rename to integrations/solid/src/__internal__/utils/isServer.ts diff --git a/integrations/solid/src/future/Actions.ts b/integrations/solid/src/future/Actions.ts new file mode 100644 index 000000000..1105f4cb3 --- /dev/null +++ b/integrations/solid/src/future/Actions.ts @@ -0,0 +1,29 @@ +import type { + InferActivityParams, + RegisteredActivityParamTypes, +} from "@stackflow/config"; + +export type Actions = { + push>( + activityName: K, + activityParams: InferActivityParams, + options?: { + animate?: boolean; + }, + ): { + activityId: string; + }; + replace>( + activityName: K, + activityParams: InferActivityParams, + options?: { + animate?: boolean; + activityId?: string; + }, + ): { + activityId: string; + }; + pop(): void; + pop(options: { animate?: boolean }): void; + pop(count: number, options?: { animate?: boolean }): void; +}; diff --git a/integrations/solid/src/future/ActivityComponentType.tsx b/integrations/solid/src/future/ActivityComponentType.tsx new file mode 100644 index 000000000..9937fc4c7 --- /dev/null +++ b/integrations/solid/src/future/ActivityComponentType.tsx @@ -0,0 +1,9 @@ +import type { + InferActivityParams, + RegisteredActivityParamTypes, +} from "@stackflow/config"; +import type { Component } from "solid-js"; + +export type ActivityComponentType< + ActivityName extends Extract, +> = Component<{ params: InferActivityParams }>; diff --git a/integrations/solid/src/future/StackComponentType.ts b/integrations/solid/src/future/StackComponentType.ts new file mode 100644 index 000000000..798a1b80b --- /dev/null +++ b/integrations/solid/src/future/StackComponentType.ts @@ -0,0 +1,5 @@ +import type { Component } from "solid-js"; + +export type StackComponentType = Component<{ + initialLoaderData?: any; +}>; diff --git a/integrations/solid/src/future/StepActions.ts b/integrations/solid/src/future/StepActions.ts new file mode 100644 index 000000000..c8838cf1b --- /dev/null +++ b/integrations/solid/src/future/StepActions.ts @@ -0,0 +1,5 @@ +export type StepActions = { + pushStep: (params: ActivityParams, options?: {}) => void; + replaceStep: (params: ActivityParams, options?: {}) => void; + popStep: (options?: {}) => void; +}; diff --git a/integrations/solid/src/future/index.ts b/integrations/solid/src/future/index.ts new file mode 100644 index 000000000..89f4ee1de --- /dev/null +++ b/integrations/solid/src/future/index.ts @@ -0,0 +1,23 @@ +/** + * Main + */ +export * from "./stackflow"; + +/** + * Types + */ +export * from "../__internal__/StackflowSolidPlugin"; +export * from "./ActivityComponentType"; +export * from "./StackComponentType"; +export * from "./Actions"; +export * from "./StepActions"; + +/** + * Hooks + */ +export * from "../__internal__/stack/useStack"; +export * from "../__internal__/activity/useActivity"; +export * from "./useActivityParams"; +export * from "./loader/useLoaderData"; +export * from "./useFlow"; +export * from "./useStepFlow"; diff --git a/integrations/solid/src/future/loader/index.ts b/integrations/solid/src/future/loader/index.ts new file mode 100644 index 000000000..034f3f9e5 --- /dev/null +++ b/integrations/solid/src/future/loader/index.ts @@ -0,0 +1,2 @@ +export * from "./loaderPlugin"; +export * from "./useLoaderData"; diff --git a/integrations/solid/src/future/loader/loaderPlugin.tsx b/integrations/solid/src/future/loader/loaderPlugin.tsx new file mode 100644 index 000000000..8002625f9 --- /dev/null +++ b/integrations/solid/src/future/loader/loaderPlugin.tsx @@ -0,0 +1,100 @@ +import type { ActivityDefinition, Config } from "@stackflow/config"; +import type { StackflowSolidPlugin } from "../../__internal__/StackflowSolidPlugin"; + +export function loaderPlugin( + config: Config>, +): StackflowSolidPlugin { + return () => ({ + key: "plugin-loader", + overrideInitialEvents({ initialEvents, initialContext }) { + if (initialEvents.length === 0) { + return []; + } + + return initialEvents.map((event) => { + if (event.name !== "Pushed") { + return event; + } + + if (initialContext.initialLoaderData) { + return { + ...event, + activityContext: { + ...event.activityContext, + loaderData: initialContext.initialLoaderData, + }, + }; + } + + const { activityName, activityParams } = event; + + const matchActivity = config.activities.find( + (activity) => activity.name === activityName, + ); + const loader = matchActivity?.loader; + + if (!loader) { + return event; + } + + const loaderData = loader({ + params: activityParams, + }); + + return { + ...event, + activityContext: { + ...event.activityContext, + loaderData, + }, + }; + }); + }, + onBeforePush({ actionParams, actions: { overrideActionParams } }) { + const { activityName, activityParams, activityContext } = actionParams; + + const loader = config.activities.find( + (activity) => activity.name === activityName, + )?.loader; + + if (!loader) { + return; + } + + const loaderData = loader({ + params: activityParams, + }); + + overrideActionParams({ + ...actionParams, + activityContext: { + ...activityContext, + loaderData, + }, + }); + }, + onBeforeReplace({ actionParams, actions: { overrideActionParams } }) { + const { activityName, activityParams, activityContext } = actionParams; + + const loader = config.activities.find( + (activity) => activity.name === activityName, + )?.loader; + + if (!loader) { + return; + } + + const loaderData = loader({ + params: activityParams, + }); + + overrideActionParams({ + ...actionParams, + activityContext: { + ...activityContext, + loaderData, + }, + }); + }, + }); +} diff --git a/integrations/solid/src/future/loader/useLoaderData.ts b/integrations/solid/src/future/loader/useLoaderData.ts new file mode 100644 index 000000000..3a0f69a8a --- /dev/null +++ b/integrations/solid/src/future/loader/useLoaderData.ts @@ -0,0 +1,10 @@ +import type { ActivityLoaderArgs } from "@stackflow/config"; +import type { Accessor } from "solid-js"; +import { useActivity } from "../../stable"; + +export function useLoaderData< + T extends (args: ActivityLoaderArgs) => any, +>(): Accessor> { + const activity = useActivity(); + return () => (activity()?.context as any)?.loaderData; +} diff --git a/integrations/solid/src/future/makeActions.ts b/integrations/solid/src/future/makeActions.ts new file mode 100644 index 000000000..4ff8c188b --- /dev/null +++ b/integrations/solid/src/future/makeActions.ts @@ -0,0 +1,80 @@ +import type { CoreStore } from "@stackflow/core"; +import { makeActivityId } from "../__internal__/activity"; +import type { Actions } from "./Actions"; + +function parseActionOptions(options?: { animate?: boolean }) { + if (!options) { + return { skipActiveState: false }; + } + + const isNullableAnimateOption = options.animate == null; + + if (isNullableAnimateOption) { + return { skipActiveState: false }; + } + + return { skipActiveState: !options.animate }; +} + +export function makeActions( + getCoreActions: () => CoreStore["actions"] | undefined, +): Actions { + return { + push(activityName, activityParams, options) { + const activityId = makeActivityId(); + + getCoreActions()?.push({ + activityId, + activityName, + activityParams, + skipEnterActiveState: parseActionOptions(options).skipActiveState, + }); + + return { + activityId, + }; + }, + replace(activityName, activityParams, options) { + const activityId = makeActivityId(); + + getCoreActions()?.replace({ + activityId: options?.activityId ?? makeActivityId(), + activityName, + activityParams, + skipEnterActiveState: parseActionOptions(options).skipActiveState, + }); + + return { + activityId, + }; + }, + pop( + count?: number | { animate?: boolean } | undefined, + options?: { animate?: boolean } | undefined, + ) { + let _count = 1; + let _options: { animate?: boolean } = {}; + + if (typeof count === "object") { + _options = { + ...count, + }; + } + if (typeof count === "number") { + _count = count; + } + if (options) { + _options = { + ...options, + }; + } + + for (let i = 0; i < _count; i += 1) { + getCoreActions()?.pop({ + skipExitActiveState: + i === 0 ? parseActionOptions(_options).skipActiveState : true, + }); + } + }, + }; +} diff --git a/integrations/solid/src/future/makeStepActions.ts b/integrations/solid/src/future/makeStepActions.ts new file mode 100644 index 000000000..99c601729 --- /dev/null +++ b/integrations/solid/src/future/makeStepActions.ts @@ -0,0 +1,46 @@ +import type { ActivityBaseParams } from "@stackflow/config"; +import type { CoreStore } from "@stackflow/core"; +import { makeStepId } from "../__internal__/activity"; +import type { StepActions } from "./StepActions"; + +export function makeStepActions( + getCoreActions: () => CoreStore["actions"] | undefined, +): StepActions { + return { + pushStep( + stepParams, + options?: { + targetActivityId?: string; + }, + ) { + const stepId = makeStepId(); + + getCoreActions()?.stepPush({ + stepId, + stepParams, + targetActivityId: options?.targetActivityId, + }); + }, + replaceStep( + stepParams, + options?: { + targetActivityId?: string; + }, + ) { + const stepId = makeStepId(); + + getCoreActions()?.stepReplace({ + stepId, + stepParams, + targetActivityId: options?.targetActivityId, + }); + }, + popStep(options?: { + targetActivityId?: string; + }) { + getCoreActions()?.stepPop({ + targetActivityId: options?.targetActivityId, + }); + }, + }; +} diff --git a/integrations/solid/src/future/stackflow.tsx b/integrations/solid/src/future/stackflow.tsx new file mode 100644 index 000000000..d8614cd79 --- /dev/null +++ b/integrations/solid/src/future/stackflow.tsx @@ -0,0 +1,160 @@ +import type { + ActivityBaseParams, + ActivityDefinition, + Config, +} from "@stackflow/config"; +import { + type CoreStore, + type PushedEvent, + makeCoreStore, + makeEvent, +} from "@stackflow/core"; +import MainRenderer from "../__internal__/MainRenderer"; +import { makeActivityId } from "../__internal__/activity"; +import { CoreProvider } from "../__internal__/core"; +import { PluginsProvider } from "../__internal__/plugins"; +import { isBrowser } from "../__internal__/utils"; +import type { ActivityComponentType, StackflowSolidPlugin } from "../stable"; +import type { Actions } from "./Actions"; +import type { StackComponentType } from "./StackComponentType"; +import type { StepActions } from "./StepActions"; +import { loaderPlugin } from "./loader"; +import { makeActions } from "./makeActions"; +import { makeStepActions } from "./makeStepActions"; + +export type StackflowPluginsEntry = + | StackflowSolidPlugin + | StackflowPluginsEntry[]; + +export type StackflowInput< + T extends ActivityDefinition, + R extends { + [activityName in T["name"]]: ActivityComponentType; + }, +> = { + config: Config; + components: R; + plugins?: Array; +}; + +export type StackflowOutput = { + Stack: StackComponentType; + actions: Actions; + stepActions: StepActions; +}; + +export function stackflow< + T extends ActivityDefinition, + R extends { + [activityName in T["name"]]: ActivityComponentType; + }, +>(input: StackflowInput): StackflowOutput { + const plugins = [ + ...(input.plugins ?? []) + .flat(Number.POSITIVE_INFINITY as 0) + .map((p) => p as StackflowSolidPlugin), + + /** + * `loaderPlugin()` must be placed after `historySyncPlugin()` + */ + loaderPlugin(input.config), + ]; + + const enoughPastTime = () => + new Date().getTime() - input.config.transitionDuration * 2; + + const staticCoreStore = makeCoreStore({ + initialEvents: [ + makeEvent("Initialized", { + transitionDuration: input.config.transitionDuration, + eventDate: enoughPastTime(), + }), + ...input.config.activities.map((activity) => + makeEvent("ActivityRegistered", { + activityName: activity.name, + eventDate: enoughPastTime(), + }), + ), + ], + plugins: [], + }); + + let currentCoreStore: CoreStore | undefined; + + const Stack: StackComponentType = (props) => { + let coreStore: CoreStore; + + /** + * In a browser environment, + * memoize `coreStore` so that only one `coreStore` exists throughout the entire app. + */ + if (isBrowser() && currentCoreStore) { + coreStore = currentCoreStore; + } else { + const initialPushedEventsByOption = input.config.initialActivity + ? [ + makeEvent("Pushed", { + activityId: makeActivityId(), + activityName: input.config.initialActivity(), + activityParams: {}, + eventDate: enoughPastTime(), + skipEnterActiveState: false, + }), + ] + : []; + + coreStore = makeCoreStore({ + initialEvents: [ + ...staticCoreStore.pullEvents(), + ...initialPushedEventsByOption, + ], + initialContext: { + initialLoaderData: props.initialLoaderData, + }, + plugins, + handlers: { + onInitialActivityIgnored: (initialPushedEvents) => { + console.warn( + `Stackflow - Some plugin overrides an "initialActivity" option. The "initialActivity" option you set to "${ + (initialPushedEvents[0] as PushedEvent).activityName + }" in the "stackflow" is ignored.`, + ); + }, + onInitialActivityNotFound: () => { + console.warn( + "Stackflow -" + + " There is no initial activity." + + " If you want to set the initial activity," + + " add the `initialActivity` option of the `stackflow()` function or" + + " add a plugin that sets the initial activity. (e.g. `@stackflow/plugin-history-sync`)", + ); + }, + }, + }); + + if (isBrowser()) { + coreStore.init(); + currentCoreStore = coreStore; + } + } + + return ( + + + + + + ); + }; + + return { + Stack, + actions: makeActions(() => currentCoreStore?.actions), + stepActions: makeStepActions(() => currentCoreStore?.actions), + }; +} diff --git a/integrations/solid/src/future/useActivityParams.ts b/integrations/solid/src/future/useActivityParams.ts new file mode 100644 index 000000000..a225edeb0 --- /dev/null +++ b/integrations/solid/src/future/useActivityParams.ts @@ -0,0 +1,13 @@ +import type { + InferActivityParams, + RegisteredActivityParamTypes, +} from "@stackflow/config"; +import { type Accessor, useContext } from "solid-js"; +import { ActivityContext } from "../__internal__/activity/ActivityProvider"; + +export function useActivityParams< + ActivityName extends Extract, +>(): Accessor> { + const activity = useContext(ActivityContext); + return () => activity()?.params as InferActivityParams; +} diff --git a/integrations/solid/src/future/useFlow.ts b/integrations/solid/src/future/useFlow.ts new file mode 100644 index 000000000..dc2ec5176 --- /dev/null +++ b/integrations/solid/src/future/useFlow.ts @@ -0,0 +1,12 @@ +import { useCoreActions } from "../__internal__/core"; +import type { Actions } from "./Actions"; +import { makeActions } from "./makeActions"; + +export type FlowOutput = { + useFlow: () => Actions; +}; + +export function useFlow(): Actions { + const coreActions = useCoreActions(); + return makeActions(coreActions); +} diff --git a/integrations/solid/src/future/useStepFlow.ts b/integrations/solid/src/future/useStepFlow.ts new file mode 100644 index 000000000..e5d1ec69d --- /dev/null +++ b/integrations/solid/src/future/useStepFlow.ts @@ -0,0 +1,14 @@ +import type { + InferActivityParams, + RegisteredActivityParamTypes, +} from "@stackflow/config"; +import { useCoreActions } from "../__internal__/core"; +import type { StepActions } from "./StepActions"; +import { makeStepActions } from "./makeStepActions"; + +export function useStepFlow< + ActivityName extends Extract, +>(activityName: ActivityName): StepActions> { + const coreActions = useCoreActions(); + return makeStepActions(coreActions); +} diff --git a/integrations/solid/src/index.ts b/integrations/solid/src/index.ts index d643ea389..012288a39 100644 --- a/integrations/solid/src/index.ts +++ b/integrations/solid/src/index.ts @@ -1,8 +1 @@ -export * from "./activity/ActivityComponentType"; -export * from "./activity/useActivity"; -export * from "./activity/useActivityParams"; -export * from "./stack/useStack"; -export * from "./stackflow"; -export * from "./StackflowSolidPlugin"; -export * from "./useActions"; -export * from "./useStepActions"; +export * from "./stable"; diff --git a/integrations/solid/src/BaseActivities.ts b/integrations/solid/src/stable/BaseActivities.ts similarity index 79% rename from integrations/solid/src/BaseActivities.ts rename to integrations/solid/src/stable/BaseActivities.ts index 5aed7180e..bb078148d 100644 --- a/integrations/solid/src/BaseActivities.ts +++ b/integrations/solid/src/stable/BaseActivities.ts @@ -1,6 +1,6 @@ import type { ActivityRegisteredEvent } from "@stackflow/core"; -import type { ActivityComponentType } from "./activity"; +import type { ActivityComponentType } from "../__internal__/ActivityComponentType"; export type BaseActivities = { [activityName: string]: diff --git a/integrations/solid/src/stable/index.ts b/integrations/solid/src/stable/index.ts new file mode 100644 index 000000000..de3df7307 --- /dev/null +++ b/integrations/solid/src/stable/index.ts @@ -0,0 +1,8 @@ +export * from "../__internal__/ActivityComponentType"; +export * from "../__internal__/activity/useActivity"; +export * from "../__internal__/activity/useActivityParams"; +export * from "../__internal__/stack/useStack"; +export * from "../__internal__/StackflowSolidPlugin"; +export * from "./stackflow"; +export * from "./useActions"; +export * from "./useStepActions"; diff --git a/integrations/solid/src/stackflow.tsx b/integrations/solid/src/stable/stackflow.tsx similarity index 95% rename from integrations/solid/src/stackflow.tsx rename to integrations/solid/src/stable/stackflow.tsx index 35d44f525..3092c0088 100644 --- a/integrations/solid/src/stackflow.tsx +++ b/integrations/solid/src/stable/stackflow.tsx @@ -5,15 +5,16 @@ import type { StackflowActions, } from "@stackflow/core"; import { makeCoreStore, makeEvent } from "@stackflow/core"; -import MainRenderer from "MainRenderer"; -import { CoreProvider } from "core"; -import { PluginsProvider } from "plugins"; import type { Component } from "solid-js"; - +import MainRenderer from "../__internal__/MainRenderer"; +import { CoreProvider } from "../__internal__/core"; +import { PluginsProvider } from "../__internal__/plugins"; + +import type { ActivityComponentType } from "../__internal__/ActivityComponentType"; +import type { StackflowSolidPlugin } from "../__internal__/StackflowSolidPlugin"; +import { makeActivityId, makeStepId } from "../__internal__/activity"; +import { isBrowser } from "../__internal__/utils"; import type { BaseActivities } from "./BaseActivities"; -import type { StackflowSolidPlugin } from "./StackflowSolidPlugin"; -import type { ActivityComponentType } from "./activity"; -import { makeActivityId, makeStepId } from "./activity"; import type { UseActionsOutputType } from "./useActions"; import { parseActionOptions, useActions } from "./useActions"; import type { @@ -21,7 +22,6 @@ import type { UseStepActionsOutputType, } from "./useStepActions"; import { useStepActions } from "./useStepActions"; -import { isBrowser } from "./utils"; export type StackComponentType = Component<{ initialContext?: any; diff --git a/integrations/solid/src/useActions.ts b/integrations/solid/src/stable/useActions.ts similarity index 93% rename from integrations/solid/src/useActions.ts rename to integrations/solid/src/stable/useActions.ts index 961773c4d..10116c3bf 100644 --- a/integrations/solid/src/useActions.ts +++ b/integrations/solid/src/stable/useActions.ts @@ -1,9 +1,9 @@ -import { useCoreActions, useCoreState } from "core"; import type { Accessor } from "solid-js"; +import { useCoreActions, useCoreState } from "../__internal__/core"; +import type { ActivityComponentType } from "../__internal__/ActivityComponentType"; +import { makeActivityId } from "../__internal__/activity"; import type { BaseActivities } from "./BaseActivities"; -import type { ActivityComponentType } from "./activity"; -import { makeActivityId } from "./activity"; export function parseActionOptions(options?: { animate?: boolean }) { if (!options) { diff --git a/integrations/solid/src/useStepActions.ts b/integrations/solid/src/stable/useStepActions.ts similarity index 87% rename from integrations/solid/src/useStepActions.ts rename to integrations/solid/src/stable/useStepActions.ts index 899307646..0e54df31d 100644 --- a/integrations/solid/src/useStepActions.ts +++ b/integrations/solid/src/stable/useStepActions.ts @@ -1,9 +1,9 @@ import type { Accessor } from "solid-js"; +import type { ActivityComponentType } from "../__internal__/ActivityComponentType"; +import { makeStepId } from "../__internal__/activity"; +import { useCoreActions, useCoreState } from "../__internal__/core"; import type { BaseActivities } from "./BaseActivities"; -import type { ActivityComponentType } from "./activity"; -import { makeStepId } from "./activity"; -import { useCoreActions, useCoreState } from "./core"; export type UseStepActionsOutputType

= { pending: Accessor; diff --git a/yarn.lock b/yarn.lock index 8e1cebeb9..296f3be1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2427,7 +2427,7 @@ __metadata: languageName: unknown linkType: soft -"@stackflow/core@npm:^1.0.13, @stackflow/core@npm:^1.1.0, @stackflow/core@workspace:core": +"@stackflow/core@npm:^1.1.0, @stackflow/core@workspace:core": version: 0.0.0-use.local resolution: "@stackflow/core@workspace:core" dependencies: @@ -2452,6 +2452,7 @@ __metadata: "@seed-design/design-token": "npm:^1.0.3" "@seed-design/stylesheet": "npm:^1.0.4" "@stackflow/compat-await-push": "npm:^1.1.12" + "@stackflow/config": "npm:^1.1.0" "@stackflow/core": "npm:^1.1.0" "@stackflow/esbuild-config": "npm:^1.0.1" "@stackflow/link": "npm:^1.4.4" @@ -2476,6 +2477,7 @@ __metadata: typescript: "npm:^5.5.3" vite: "npm:^5.3.2" vite-plugin-solid: "npm:^2.10.2" + zod: "npm:^3.23.8" languageName: unknown linkType: soft @@ -2903,15 +2905,18 @@ __metadata: version: 0.0.0-use.local resolution: "@stackflow/solid@workspace:integrations/solid" dependencies: - "@stackflow/core": "npm:^1.0.13" + "@stackflow/config": "npm:^1.1.0" + "@stackflow/core": "npm:^1.1.0" "@stackflow/esbuild-config": "npm:^1.0.3" esbuild: "npm:^0.23.0" + esbuild-plugin-file-path-extensions: "npm:^2.1.2" esbuild-plugin-solid: "patch:esbuild-plugin-solid@npm%3A0.6.0#~/.yarn/patches/esbuild-plugin-solid-npm-0.6.0-49835b85dc.patch" rimraf: "npm:^3.0.2" solid-js: "npm:^1.8.18" typescript: "npm:^5.5.3" peerDependencies: - "@stackflow/core": ^1 + "@stackflow/config": ^1.0.1-canary.0 + "@stackflow/core": ^1.1.0-canary.0 solid-js: ">=1.4.0" languageName: unknown linkType: soft