diff --git a/.gitignore b/.gitignore index 9727332..2232350 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ packages/media/.env **/*/.env **/*/.dev.vars **/*/.wrangler +**/*/*.tgz **/*/vite.config.ts.timestamp* .history **/*/.db/* diff --git a/app/package.json b/app/package.json index 34a5e12..fb02b8e 100644 --- a/app/package.json +++ b/app/package.json @@ -3,7 +3,7 @@ "type": "module", "sideEffects": false, "bin": "./dist/cli/index.js", - "version": "0.3.3", + "version": "0.3.4-alpha1", "scripts": { "build:all": "bun run build && bun run build:cli", "dev": "vite", diff --git a/app/src/modules/SystemApi.ts b/app/src/modules/SystemApi.ts index 2451b78..3241141 100644 --- a/app/src/modules/SystemApi.ts +++ b/app/src/modules/SystemApi.ts @@ -16,6 +16,10 @@ export class SystemApi extends ModuleApi { }; } + readConfig() { + return this.get<{ version: number } & ModuleConfigs>("config"); + } + readSchema(options?: { config?: boolean; secrets?: boolean }) { return this.get("schema", { config: options?.config ? 1 : 0, diff --git a/app/src/ui/client/ClientProvider.tsx b/app/src/ui/client/ClientProvider.tsx index 6e13bfb..4fd6719 100644 --- a/app/src/ui/client/ClientProvider.tsx +++ b/app/src/ui/client/ClientProvider.tsx @@ -12,44 +12,38 @@ export type ClientProviderProps = { }; export const ClientProvider = ({ children, baseUrl, user }: ClientProviderProps) => { - const [actualBaseUrl, setActualBaseUrl] = useState(null); + //const [actualBaseUrl, setActualBaseUrl] = useState(null); const winCtx = useBkndWindowContext(); + const _ctx_baseUrl = useBaseUrl(); + let actualBaseUrl = baseUrl ?? _ctx_baseUrl ?? ""; try { - const _ctx_baseUrl = useBaseUrl(); - if (_ctx_baseUrl) { - console.warn("wrapped many times"); - setActualBaseUrl(_ctx_baseUrl); + if (!baseUrl) { + if (_ctx_baseUrl) { + actualBaseUrl = _ctx_baseUrl; + console.warn("wrapped many times, take from context", actualBaseUrl); + } else if (typeof window !== "undefined") { + actualBaseUrl = window.location.origin; + console.log("setting from window", actualBaseUrl); + } } } catch (e) { - console.error("error", e); - } - - useEffect(() => { - // Only set base URL if running on the client side - if (typeof window !== "undefined") { - setActualBaseUrl(baseUrl || window.location.origin); - } - }, [baseUrl]); - - if (!actualBaseUrl) { - // Optionally, return a fallback during SSR rendering - return null; // or a loader/spinner if desired + console.error("error .....", e); } const api = new Api({ host: actualBaseUrl, user: user ?? winCtx.user }); return ( - + {children} ); }; -export const useApi = (host?: ApiOptions["host"]) => { +export const useApi = (host?: ApiOptions["host"]): Api => { const context = useContext(ClientContext); - if (host && host !== context.baseUrl) { - return new Api({ host }); + if (!context?.api || (host && host.length > 0 && host !== context.baseUrl)) { + return new Api({ host: host ?? "" }); } return context.api; diff --git a/app/src/ui/lib/mantine/theme.ts b/app/src/ui/lib/mantine/theme.ts index 0dfe287..e880b9d 100644 --- a/app/src/ui/lib/mantine/theme.ts +++ b/app/src/ui/lib/mantine/theme.ts @@ -15,7 +15,7 @@ import { } from "@mantine/core"; import { twMerge } from "tailwind-merge"; -// default: https://github.com/mantinedev/mantine/blob/master/src/mantine-core/src/core/MantineProvider/default-theme.ts +// default: https://github.com/mantinedev/mantine/blob/master/packages/%40mantine/core/src/core/MantineProvider/default-theme.ts export function createMantineTheme(scheme: "light" | "dark"): { theme: ReturnType; diff --git a/bun.lockb b/bun.lockb index 8a89fbc..26c6843 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/examples/plasmic/.gitignore b/examples/plasmic/.gitignore new file mode 100644 index 0000000..d0d878e --- /dev/null +++ b/examples/plasmic/.gitignore @@ -0,0 +1 @@ +.next \ No newline at end of file diff --git a/examples/plasmic/next-env.d.ts b/examples/plasmic/next-env.d.ts new file mode 100644 index 0000000..a4a7b3f --- /dev/null +++ b/examples/plasmic/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/examples/plasmic/next.config.ts b/examples/plasmic/next.config.ts new file mode 100644 index 0000000..3915163 --- /dev/null +++ b/examples/plasmic/next.config.ts @@ -0,0 +1,8 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ + reactStrictMode: true, +}; + +export default nextConfig; diff --git a/examples/plasmic/package.json b/examples/plasmic/package.json new file mode 100644 index 0000000..d530a6c --- /dev/null +++ b/examples/plasmic/package.json @@ -0,0 +1,26 @@ +{ + "name": "plasmic-nextjs", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@plasmicapp/loader-nextjs": "^1.0.409", + "bknd": "workspace:*", + "@bknd/plasmic": "workspace:*", + "next": "15.0.4", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "typescript": "^5", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "postcss": "^8" + } +} diff --git a/examples/plasmic/postcss.config.mjs b/examples/plasmic/postcss.config.mjs new file mode 100644 index 0000000..1a69fd2 --- /dev/null +++ b/examples/plasmic/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/examples/plasmic/src/pages/[[...catchall]].tsx b/examples/plasmic/src/pages/[[...catchall]].tsx new file mode 100644 index 0000000..4de4a49 --- /dev/null +++ b/examples/plasmic/src/pages/[[...catchall]].tsx @@ -0,0 +1,78 @@ +import { PLASMIC } from "@/plasmic-init"; +import { + type ComponentRenderData, + PlasmicComponent, + PlasmicRootProvider, + extractPlasmicQueryData +} from "@plasmicapp/loader-nextjs"; +import type { GetServerSideProps } from "next"; +// biome-ignore lint/suspicious/noShadowRestrictedNames: +import Error from "next/error"; +import { useRouter } from "next/router"; +import * as React from "react"; + +export const getServerSideProps: GetServerSideProps = async (context) => { + const { catchall } = context.params ?? {}; + + // Convert the catchall param into a path string + const plasmicPath = + typeof catchall === "string" + ? catchall + : Array.isArray(catchall) + ? `/${catchall.join("/")}` + : "/"; + const plasmicData = await PLASMIC.maybeFetchComponentData(plasmicPath); + if (!plasmicData) { + // This is some non-Plasmic catch-all page + return { + props: {} + }; + } + + // This is a path that Plasmic knows about. + const pageMeta = plasmicData.entryCompMetas[0]; + + // Cache the necessary data fetched for the page. + const queryCache = await extractPlasmicQueryData( + + {/* @ts-ignore */} + + + ); + + // Pass the data in as props. + return { + props: { plasmicData, queryCache } + }; +}; + +export default function CatchallPage(props: { + plasmicData?: ComponentRenderData; + queryCache?: Record; +}) { + const { plasmicData, queryCache } = props; + const router = useRouter(); + if (!plasmicData || plasmicData.entryCompMetas.length === 0) { + return ; + } + const pageMeta = plasmicData.entryCompMetas[0]; + return ( + // Pass in the data fetched in getStaticProps as prefetchedData + + {/* @ts-ignore */} + + + ); +} diff --git a/examples/plasmic/src/pages/_app.tsx b/examples/plasmic/src/pages/_app.tsx new file mode 100644 index 0000000..80eb165 --- /dev/null +++ b/examples/plasmic/src/pages/_app.tsx @@ -0,0 +1,11 @@ +import "@/styles/globals.css"; +import { ClientProvider } from "bknd/client"; +import type { AppProps } from "next/app"; + +export default function App({ Component, pageProps }: AppProps) { + return ( + + + + ); +} diff --git a/examples/plasmic/src/pages/_document.tsx b/examples/plasmic/src/pages/_document.tsx new file mode 100644 index 0000000..628a733 --- /dev/null +++ b/examples/plasmic/src/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from "next/document"; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/examples/plasmic/src/pages/admin/[[...admin]].tsx b/examples/plasmic/src/pages/admin/[[...admin]].tsx new file mode 100644 index 0000000..fb28734 --- /dev/null +++ b/examples/plasmic/src/pages/admin/[[...admin]].tsx @@ -0,0 +1,25 @@ +// pages/admin/[[...admin]].tsx +import { withApi } from "bknd/adapter/nextjs"; +import dynamic from "next/dynamic"; +import "bknd/dist/styles.css"; + +/*export const config = { + runtime: "experimental-edge" +}*/ + +const Admin = dynamic(() => import("bknd/ui").then((mod) => mod.Admin), { + ssr: false, +}); + +export const getServerSideProps = withApi(async (context) => { + return { + props: { + user: context.api.getUser(), + }, + }; +}); + +export default function AdminPage() { + if (typeof document === "undefined") return null; + return ; +} diff --git a/examples/plasmic/src/pages/api/[...route].ts b/examples/plasmic/src/pages/api/[...route].ts new file mode 100644 index 0000000..f296f98 --- /dev/null +++ b/examples/plasmic/src/pages/api/[...route].ts @@ -0,0 +1,16 @@ +import { serve } from "bknd/adapter/nextjs"; + +export const config = { + runtime: "edge", + unstable_allowDynamic: ["**/*.js"] +}; + +export default serve({ + connection: { + type: "libsql", + config: { + url: process.env.DB_URL!, + authToken: process.env.DB_TOKEN! + } + } +}); diff --git a/examples/plasmic/src/pages/plasmic-host.tsx b/examples/plasmic/src/pages/plasmic-host.tsx new file mode 100644 index 0000000..7dac28d --- /dev/null +++ b/examples/plasmic/src/pages/plasmic-host.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; +import { PlasmicCanvasHost } from '@plasmicapp/loader-nextjs'; +import { PLASMIC } from '@/plasmic-init'; + +export default function PlasmicHost() { + return PLASMIC && ; +} \ No newline at end of file diff --git a/examples/plasmic/src/pages/test.tsx b/examples/plasmic/src/pages/test.tsx new file mode 100644 index 0000000..5b66ecc --- /dev/null +++ b/examples/plasmic/src/pages/test.tsx @@ -0,0 +1,6 @@ +import { useApi } from "bknd/client"; + +export default function Test() { + const api = useApi(undefined); + return
{api.baseUrl}
; +} diff --git a/examples/plasmic/src/plasmic-init.ts b/examples/plasmic/src/plasmic-init.ts new file mode 100644 index 0000000..9c77d9d --- /dev/null +++ b/examples/plasmic/src/plasmic-init.ts @@ -0,0 +1,17 @@ +import { initPlasmicLoader } from "@plasmicapp/loader-nextjs"; +import { loader } from "@bknd/plasmic"; + +export const PLASMIC = initPlasmicLoader({ + projects: [ + { + id: process.env.PLASMIC_ID!, + token: process.env.PLASMIC_TOKEN!, + } + ], + preview: true, //process.env.NODE_ENV === "development", +}) + +loader(PLASMIC); +/* +PLASMIC.registerComponent(BkndData, BkndDataMeta); +PLASMIC.registerGlobalContext(BkndContext, BkndContextMeta as any);*/ diff --git a/examples/plasmic/src/styles/globals.css b/examples/plasmic/src/styles/globals.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/examples/plasmic/src/styles/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/plasmic/tailwind.config.ts b/examples/plasmic/tailwind.config.ts new file mode 100644 index 0000000..109807b --- /dev/null +++ b/examples/plasmic/tailwind.config.ts @@ -0,0 +1,18 @@ +import type { Config } from "tailwindcss"; + +export default { + content: [ + "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", + "./src/components/**/*.{js,ts,jsx,tsx,mdx}", + "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + colors: { + background: "var(--background)", + foreground: "var(--foreground)", + }, + }, + }, + plugins: [], +} satisfies Config; diff --git a/examples/plasmic/tsconfig.json b/examples/plasmic/tsconfig.json new file mode 100644 index 0000000..ecf7ecf --- /dev/null +++ b/examples/plasmic/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "noImplicitAny": false, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/packages/plasmic/components/WouterLink.tsx b/packages/plasmic/components/WouterLink.tsx deleted file mode 100644 index a7472dc..0000000 --- a/packages/plasmic/components/WouterLink.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { CodeComponentMeta } from "@plasmicapp/host"; -import { Link } from "wouter"; - -export function WouterLink({ href, className, children, ...props }) { - return ( - - {children} - - ); -} - -export const WouterLinkMeta: CodeComponentMeta = { - name: "WouterLink", - importPath: import.meta.dir, - props: { - href: { - type: "href", - }, - children: { - type: "slot", - }, - }, -}; diff --git a/packages/plasmic/index.ts b/packages/plasmic/index.ts deleted file mode 100644 index 05e7de8..0000000 --- a/packages/plasmic/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { loader as loadBkndComponents, CatchAllPage, createWouterPlasmicApp } from "./loader"; - -export * from "./components"; -export * from "./contexts"; diff --git a/packages/plasmic/loader.tsx b/packages/plasmic/loader.tsx deleted file mode 100644 index f81547f..0000000 --- a/packages/plasmic/loader.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { PlasmicCanvasHost, type registerComponent } from "@plasmicapp/host"; -import { - type ComponentRenderData, - PlasmicComponent, - type PlasmicComponentLoader, - PlasmicRootProvider -} from "@plasmicapp/loader-react"; -import { forwardRef, useEffect, useState } from "react"; -import { Link, Route, Router, Switch } from "wouter"; -import { - BkndData, - BkndDataMeta, - Image, - ImageMeta, - LazyRender, - LazyRenderMeta, - WouterLink, - WouterLinkMeta -} from "./components"; -import { BkndContext, BkndContextMeta } from "./contexts"; - -export function loader(PLASMIC: PlasmicComponentLoader) { - PLASMIC.registerComponent(BkndData, BkndDataMeta); - PLASMIC.registerComponent(WouterLink, WouterLinkMeta); - PLASMIC.registerComponent(Image, ImageMeta); - PLASMIC.registerComponent(LazyRender, LazyRenderMeta); - PLASMIC.registerGlobalContext(BkndContext, BkndContextMeta as any); -} - -const CustomLink = forwardRef((props, ref) => { - //console.log("rendering custom link", props); - //return null; - if ("data-replace" in props) { - return ; - } - //return ; - // @ts-ignore it's because of the link - return ; -}); - -const Wrapper = ({ children }) => { - return ( -
-
{children}
-
- ); -}; - -export function CatchAllPage({ - PLASMIC, - prefix = "" -}: { PLASMIC: PlasmicComponentLoader; prefix?: string }) { - const [loading, setLoading] = useState(true); - const [pageData, setPageData] = useState(null); - - //const params = useParams(); - const pathname = location.pathname.replace(prefix, ""); - const path = pathname.length === 0 ? "/" : pathname; - //console.log("path", path, params); - useEffect(() => { - async function load() { - const pageData = await PLASMIC.maybeFetchComponentData(path); - //console.log("pageData", pageData); - setPageData(pageData); - setLoading(false); - } - load(); - }, []); - - if (loading) { - return Loading ...; - } - if (!pageData) { - return Not found; - } - - const pageMeta = pageData.entryCompMetas[0]; - - // The page will already be cached from the `load` call above. - return ( - - - - ); -} - -export function createWouterPlasmicApp(PLASMIC: PlasmicComponentLoader, prefix = "") { - return function App() { - return ( - - - - } - /> - - - ); - }; -} diff --git a/packages/plasmic/package.json b/packages/plasmic/package.json index 2ad935c..8d128c5 100644 --- a/packages/plasmic/package.json +++ b/packages/plasmic/package.json @@ -1,5 +1,6 @@ { "name": "@bknd/plasmic", + "version": "0.3.4-alpha1", "type": "module", "sideEffects": false, "scripts": { @@ -8,41 +9,61 @@ "build:only": "rm -rf dist && bun tsup", "types": "bun tsc -p tsconfig.json --noEmit --skipLibCheck", "build:types": "bun tsc --emitDeclarationOnly", - "updater": "bun x npm-check-updates -ui" + "updater": "bun x npm-check-updates -ui", + "pack": "rm -rf *.tgz && npm pack && mv *.tgz latest.tgz", + "prepublishOnly": "bun run build" }, - "dependencies": { - "wouter": "^3.3.5" + "publishConfig": { + "access": "public" }, + "dependencies": {}, "devDependencies": { "@types/bun": "latest", + "bknd": "workspace:*", + "tsdx": "^0.14.1", "typescript": "^5.0.0" }, "peerDependencies": { - "@plasmicapp/host": ">=1.0.0", - "bknd": "workspace:*", + "bknd": "*", "react": ">=18", - "react-dom": ">=18" + "react-dom": ">=18", + "@plasmicapp/host": ">=1.0.0", + "@plasmicapp/query": ">=0.1.0" }, "tsup": { - "entry": ["index.ts"], - "minify": true, + "entry": [ + "src/index.ts" + ], + "minify": false, "clean": true, - "external": ["react", "react-dom", "@plasmicapp/host", "@plasmicapp/loader-react", "@plasmicapp/loader-core"], - "format": ["esm"], + "external": [ + "react", + "react-dom", + "@plasmicapp/host", + "@plasmicapp/query", + "swr" + ], + "format": [ + "esm", + "cjs" + ], "platform": "browser", - "shims": true, "bundle": true, "metafile": true, - "splitting": false, + "splitting": true, "sourceMap": true, "outDir": "dist" }, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js", - "require": "./dist/index.js" - } - }, - "files": ["dist"] + "types": "dist/index.d.ts", + "module": "dist/index.js", + "main": "dist/index.cjs", + "files": [ + "dist", + "README.md", + "!dist/*.tsbuildinfo", + "!dist/*.map", + "!dist/**/*.map", + "!dist/metafile*", + "!dist/**/metafile*" + ] } diff --git a/packages/plasmic/components/Image.tsx b/packages/plasmic/src/components/Image.tsx similarity index 86% rename from packages/plasmic/components/Image.tsx rename to packages/plasmic/src/components/Image.tsx index 5c02e68..9c50439 100644 --- a/packages/plasmic/components/Image.tsx +++ b/packages/plasmic/src/components/Image.tsx @@ -1,6 +1,7 @@ -"use client"; - import type { CodeComponentMeta } from "@plasmicapp/host"; +import registerComponent, { type ComponentMeta } from "@plasmicapp/host/registerComponent"; +// biome-ignore lint/style/useImportType: +import React from "react"; //import { PlasmicCanvasContext } from "@plasmicapp/loader-react"; import { useContext, useEffect, useRef, useState } from "react"; @@ -39,7 +40,7 @@ function numeric(value: number | string): number { function getDimensionDefaults( width: number | string | undefined, height: number | string | undefined, - ratio: number | undefined, + ratio: number | undefined ) { let _width = width; let _height = height; @@ -61,7 +62,7 @@ function getDimensionDefaults( function getPlaceholderStyle( width: number | string | undefined, height: number | string | undefined, - ratio: number | undefined, + ratio: number | undefined ) { let paddingBottom = 0; if (width && height) { @@ -73,7 +74,7 @@ function getPlaceholderStyle( } return { - paddingBottom: paddingBottom + "%", + paddingBottom: paddingBottom + "%" }; } @@ -126,7 +127,7 @@ export const Image: React.FC = ({ } }); }, - { threshold: loadTreshold }, + { threshold: loadTreshold } ); if (imgRef.current) { observer.observe(imgRef.current); @@ -150,7 +151,7 @@ export const Image: React.FC = ({ const { width: _width, height: _height, - ratio: _ratio, + ratio: _ratio } = getDimensionDefaults(width, height, ratio); const imgStyle: any = { @@ -163,7 +164,7 @@ export const Image: React.FC = ({ height: "auto", //height: _height || "auto", //height: !transitioned ? _height || "auto" : "auto", - opacity: forceLoad || loaded ? 1 : 0, + opacity: forceLoad || loaded ? 1 : 0 }; const placeholderStyle: any = { @@ -174,7 +175,7 @@ export const Image: React.FC = ({ width: _width || "100%", height: 0, //height: transitioned ? "auto" : 0, - ...getPlaceholderStyle(_width, _height, _ratio), + ...getPlaceholderStyle(_width, _height, _ratio) }; const wrapperStyle: any = { @@ -186,7 +187,7 @@ export const Image: React.FC = ({ lineHeight: 0, //height: _height, maxWidth: "100%", - maxHeight: "100%", + maxHeight: "100%" }; if (loaded) { wrapperStyle.height = "auto"; @@ -213,13 +214,24 @@ export const Image: React.FC = ({ ); }; -export const ImageMeta: CodeComponentMeta> = { +export function registerImage( + loader?: { registerComponent: typeof registerComponent }, + customMeta?: ComponentMeta +) { + if (loader) { + loader.registerComponent(Image, customMeta ?? ImageMeta); + } else { + registerComponent(Image, customMeta ?? ImageMeta); + } +} + +export const ImageMeta: CodeComponentMeta = { name: "ImageLazy", - importPath: import.meta.dir, + importPath: "@bknd/plasmic", props: { src: { type: "imageUrl", - displayName: "Image", + displayName: "Image" }, alt: "string", width: "number", @@ -230,14 +242,14 @@ export const ImageMeta: CodeComponentMeta> = { //backgroundColor: "color", transitionSpeed: { type: "number", - helpText: "How fast image should fade in. Default is 200 (ms).", + helpText: "How fast image should fade in. Default is 200 (ms)." }, loadTreshold: { type: "number", displayName: "Treshold", //defaultValue: 0.1, helpText: - "Number between 0 and 1. Default is 0.1. Determines how much of the image must be in viewport before it gets loaded", - }, - }, + "Number between 0 and 1. Default is 0.1. Determines how much of the image must be in viewport before it gets loaded" + } + } }; diff --git a/packages/plasmic/components/LazyRender.tsx b/packages/plasmic/src/components/LazyRender.tsx similarity index 73% rename from packages/plasmic/components/LazyRender.tsx rename to packages/plasmic/src/components/LazyRender.tsx index 2de5e06..a49e3a3 100644 --- a/packages/plasmic/components/LazyRender.tsx +++ b/packages/plasmic/src/components/LazyRender.tsx @@ -1,4 +1,7 @@ import type { CodeComponentMeta } from "@plasmicapp/host"; +import registerComponent, { type ComponentMeta } from "@plasmicapp/host/registerComponent"; +// biome-ignore lint/style/useImportType: +import React from "react"; import { useEffect, useRef, useState } from "react"; interface LazyRenderProps { @@ -22,7 +25,7 @@ export const LazyRender: React.FC = ({ threshold = 0.1, delay = 0, fallback = , - onBecomesVisible, + onBecomesVisible }) => { const [isVisible, setIsVisible] = useState(forceLoad); const ref = useRef(null); @@ -43,7 +46,7 @@ export const LazyRender: React.FC = ({ } const observerOptions: IntersectionObserverInit = { - threshold: threshold < 1 ? threshold : 0.1, + threshold: threshold < 1 ? threshold : 0.1 }; const observerCallback: IntersectionObserverCallback = (entries) => { @@ -74,38 +77,49 @@ export const LazyRender: React.FC = ({ ); }; -export const LazyRenderMeta: CodeComponentMeta> = { +export function registerLazyRender( + loader?: { registerComponent: typeof registerComponent }, + customMeta?: ComponentMeta +) { + if (loader) { + loader.registerComponent(LazyRender, customMeta ?? LazyRenderMeta); + } else { + registerComponent(LazyRender, customMeta ?? LazyRenderMeta); + } +} + +export const LazyRenderMeta: CodeComponentMeta = { name: "LazyRender", - importPath: import.meta.dir, + importPath: "@bknd/plasmic", props: { forceLoad: { type: "boolean", - defaultValue: false, + defaultValue: false }, forceFallback: { type: "boolean", - defaultValue: false, + defaultValue: false }, threshold: { type: "number", - defaultValue: 0.1, + defaultValue: 0.1 }, fallback: { - type: "slot", + type: "slot" //allowedComponents: ["*"], }, delay: { type: "number", - defaultValue: 0, + defaultValue: 0 }, onBecomesVisible: { type: "code", - lang: "javascript", + lang: "javascript" }, children: { - type: "slot", + type: "slot" //allowedComponents: ["*"], - }, - }, + } + } }; diff --git a/packages/plasmic/components/data/BkndData.tsx b/packages/plasmic/src/components/data/BkndData.tsx similarity index 67% rename from packages/plasmic/components/data/BkndData.tsx rename to packages/plasmic/src/components/data/BkndData.tsx index f5fef9d..6f2068c 100644 --- a/packages/plasmic/components/data/BkndData.tsx +++ b/packages/plasmic/src/components/data/BkndData.tsx @@ -1,11 +1,13 @@ -import { type CodeComponentMeta, DataProvider, usePlasmicCanvasContext } from "@plasmicapp/host"; +import { DataProvider, usePlasmicCanvasContext } from "@plasmicapp/host"; +import registerComponent, { type ComponentMeta } from "@plasmicapp/host/registerComponent"; +import { usePlasmicQueryData } from "@plasmicapp/query"; +import { useApi, useEntityQuery } from "bknd/client"; import type { RepoQuery } from "bknd/data"; -import { useEntities, useEntity } from "bknd/ui"; -import { encodeSearch } from "bknd/utils"; -import { useContext, useEffect, useState } from "react"; +// biome-ignore lint/style/useImportType: +import React from "react"; import { usePlasmicBkndContext } from "../../contexts/BkndContext"; -type BkndEntitiesProps = { +type BkndDataProps = { children?: React.ReactNode; loading?: React.ReactNode; error?: React.ReactNode; @@ -23,10 +25,11 @@ type BkndEntitiesProps = { dataName?: string; entityId?: number; entity?: string; + select?: string[]; sortBy: string; sortDir: "asc" | "desc"; where?: string; - mode?: "fetch" | "react-query"; + mode?: "fetch" | "swr"; noLayout?: boolean; preview?: boolean; previewSlot?: "loading" | "error" | "empty"; @@ -61,11 +64,13 @@ export function BkndData({ sortBy = "id", sortDir = "asc", mode = "fetch", + select = [], noLayout, preview, previewSlot, ...props -}: BkndEntitiesProps) { +}: BkndDataProps) { + //console.log("--bknd data"); const inEditor = !!usePlasmicCanvasContext(); const plasmicContext = usePlasmicBkndContext(); @@ -100,6 +105,7 @@ export function BkndData({ } const query = { + select: select.length > 0 ? select : undefined, limit: entityId ? undefined : limit, offset: entityId ? undefined : offset, where: _where, @@ -108,7 +114,7 @@ export function BkndData({ join: joinRefs }; - console.log("---context", plasmicContext); + //console.log("---context", plasmicContext); if (plasmicContext.appConfig?.data?.entities) { const { entities, relations } = plasmicContext.appConfig.data; console.log("entities", entities); @@ -149,8 +155,7 @@ export function BkndData({ children }; - const Component = - mode === "react-query" ? : ; + const Component = mode === "swr" ? : ; return noLayout ? Component :
{Component}
; } @@ -175,32 +180,19 @@ const ModeFetch = ({ entity, query }: ModeProps) => { - const [data, setData] = useState([]); - const [isLoading, setLoading] = useState(true); - const [hasError, setError] = useState(); - const plasmicContext = usePlasmicBkndContext(); - const basepath = "/api/data"; - const path = entityId ? `${basepath}/${entity}/${entityId}` : `${basepath}/${entity}`; - console.log("query", path, query); - const url = `${plasmicContext.baseUrl}${path}?${encodeSearch(query)}`; - useEffect(() => { - (async () => { - try { - const res = await fetch(url); - const result = (await res.json()) as any; - //console.log("result", result); - setData(result.data); - setLoading(false); - setError(undefined); - } catch (e) { - console.error(e); - setError(String(e)); - setLoading(false); - } - })(); - }, [url]); + const api = useApi(); + const endpoint = entityId + ? api.data.readOne(entity, entityId, query) + : api.data.readMany(entity, query); - console.log("--data", { name: dataName ?? entity ?? "data", data, isLoading, hasError }); + const { + data, + error: hasError, + isLoading + } = usePlasmicQueryData(endpoint.key(), async () => { + const res = await endpoint.execute(); + return res.data; + }); if (isLoading) { return ; @@ -213,7 +205,6 @@ const ModeFetch = ({ if (data.length === 0) { return ; } - console.log("--here1"); return ( @@ -222,85 +213,48 @@ const ModeFetch = ({ ); }; -const ModeReactQuery = (props: ModeProps) => { - return props.entityId ? ( - - ) : ( - - ); -}; +const ModeSWR = ({ children, loading, error, dataName, entityId, empty, entity }: ModeProps) => { + const $q = useEntityQuery(entity, entityId); -const ModeReactQuerySingle = ({ - children, - loading, - error, - dataName, - entityId, - empty, - entity -}: ModeProps) => { - const container = useEntity(entity, entityId); - const { isLoading, isError } = container.status.fetch; - - if (isLoading) { + if ($q.isLoading) { return ; } - if (isError) { + if ($q.error) { return ; } - if (!container.data) { + if (!$q.data) { return ; } return ( - + {children} ); }; -const ModeReactQueryMultiple = ({ - children, - loading, - error, - empty, - dataName, - entity, - query -}: ModeProps) => { - const container = useEntities(entity, query); - const { isLoading, isError } = container.status.fetch; - - if (isLoading) { - return ; +export function registerBkndData( + loader?: { registerComponent: typeof registerComponent }, + customMeta?: ComponentMeta +) { + if (loader) { + loader.registerComponent(BkndData, customMeta ?? BkndDataMeta); + } else { + registerComponent(BkndData, customMeta ?? BkndDataMeta); } +} - if (isError) { - return ; - } - - if (!container.data || container.data.length === 0) { - return ; - } - - return ( - - {children} - - ); -}; - -export const BkndDataMeta: CodeComponentMeta> = { +export const BkndDataMeta: ComponentMeta = { name: "BKND Data", section: "BKND", - importPath: import.meta.dir, + importPath: "@bknd/plasmic", providesData: true, props: { entity: { type: "choice", - options: (props, ctx) => ctx.entities + options: (props, ctx) => ctx?.entities ?? [] }, dataName: { type: "string" @@ -308,6 +262,10 @@ export const BkndDataMeta: CodeComponentMeta ctx?.fields ?? [] + }, limit: { type: "number", defaultValue: 10, @@ -326,13 +284,13 @@ export const BkndDataMeta: CodeComponentMeta ctx.references + options: (props, ctx) => ctx?.references ?? [] }, joinRefs: { displayName: "Join", type: "choice", multiSelect: true, - options: (props, ctx) => ctx.references + options: (props, ctx) => ctx?.references ?? [] }, where: { type: "code", @@ -340,7 +298,7 @@ export const BkndDataMeta: CodeComponentMeta ctx.fields + options: (props, ctx) => ctx?.fields ?? [] }, sortDir: { type: "choice", @@ -361,7 +319,7 @@ export const BkndDataMeta: CodeComponentMeta +import React from "react"; import { createContext, useContext, useEffect, useMemo, useState } from "react"; // Users will be able to set these props in Studio. @@ -18,17 +24,6 @@ type BkndContextProps = { const BkndContextContext = createContext({} as any); -function getBaseUrlFromWindow() { - if (typeof window === "undefined") { - return ""; - } - - const protocol = window.location.protocol; - const host = window.location.host; - - return `${protocol}//${host}`; -} - // @todo: it's an issue that we need auth, so we cannot make baseurl adjustable (maybe add an option to useAuth with a specific base url?) export const BkndContext = ({ children, @@ -36,19 +31,15 @@ export const BkndContext = ({ initialAuth }: React.PropsWithChildren) => { const auth = useAuth(); - const baseurl = useBaseUrl(); + const baseurl = baseUrl ?? useBaseUrl(); + const api = useApi({ host: baseurl }); const [data, setData] = useState({ baseUrl: baseurl, - /*baseUrl: (baseUrl && baseUrl.length > 0 ? baseUrl : getBaseUrlFromWindow()).replace( - /\/+$/, - "" - ),*/ auth: auth ?? initialAuth, appConfig: undefined }); const inEditor = !!usePlasmicCanvasContext(); - console.log("context:user", data); useEffect(() => { setData((prev) => ({ ...prev, auth: auth })); @@ -57,8 +48,10 @@ export const BkndContext = ({ useEffect(() => { (async () => { if (inEditor) { - const res = await fetch(`${baseurl}/api/system/config`); - const result = (await res.json()) as BkndGlobalContextProps["appConfig"]; + const result = await api.system.readConfig(); + + /*const res = await fetch(`${baseurl}/api/system/config`); + const result = (await res.json()) as BkndGlobalContextProps["appConfig"];*/ console.log("appconfig", result); setData((prev) => ({ ...prev, appConfig: result })); } @@ -101,13 +94,12 @@ export const BkndContext = ({ [baseUrl] ); - console.log("plasmic.bknd.context", data); + console.log("plasmic.bknd.context", { baseUrl }); return ( - {/*{children}*/} - {children} + {children} @@ -119,8 +111,20 @@ export function usePlasmicBkndContext() { return context; } -export const BkndContextMeta = { +export function registerBkndContext( + loader?: { registerGlobalContext: typeof registerGlobalContext }, + customMeta?: GlobalContextMeta +) { + if (loader) { + loader.registerGlobalContext(BkndContext, customMeta ?? BkndContextMeta); + } else { + registerGlobalContext(BkndContext, customMeta ?? BkndContextMeta); + } +} + +export const BkndContextMeta: GlobalContextMeta = { name: "BkndContext", + importPath: "@bknd/plasmic", props: { baseUrl: { type: "string" }, initialAuth: { type: "object" } }, providesData: true, globalActions: { diff --git a/packages/plasmic/contexts/index.ts b/packages/plasmic/src/contexts/index.ts similarity index 100% rename from packages/plasmic/contexts/index.ts rename to packages/plasmic/src/contexts/index.ts diff --git a/packages/plasmic/src/index.ts b/packages/plasmic/src/index.ts new file mode 100644 index 0000000..2f57de8 --- /dev/null +++ b/packages/plasmic/src/index.ts @@ -0,0 +1,17 @@ +import type { registerComponent, registerGlobalContext } from "@plasmicapp/host"; +import { registerImage } from "./components/Image"; +import { registerLazyRender } from "./components/LazyRender"; +import { registerBkndData } from "./components/data/BkndData"; +import { registerBkndContext } from "./contexts/BkndContext"; + +export function registerAll(loader?: { + registerComponent: typeof registerComponent; + registerGlobalContext: typeof registerGlobalContext; +}) { + registerBkndData(loader); + registerBkndContext(loader); + registerImage(loader); + registerLazyRender(loader); +} + +export { registerBkndData, registerBkndContext }; diff --git a/packages/plasmic/tsconfig.json b/packages/plasmic/tsconfig.json index 7f2aec6..d8a2e77 100644 --- a/packages/plasmic/tsconfig.json +++ b/packages/plasmic/tsconfig.json @@ -4,19 +4,23 @@ "lib": ["ESNext", "DOM"], "target": "ESNext", "module": "ESNext", - "jsx": "react-jsx", + "jsx": "react", "allowJs": true, "moduleResolution": "bundler", "allowImportingTsExtensions": false, "verbatimModuleSyntax": true, "strict": true, "outDir": "dist", + "declarationDir": "dist", "declaration": true, "skipLibCheck": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": false, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + "rootDir": "src", + "baseUrl": "src", + "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo" }, - "include": ["index.ts", "loader.tsx", "components", "contexts"], - "exclude": ["@bknd/app", "@bknd/core", "dist", "node_modules", "build.ts"] + "include": ["src/**/*"], + "exclude": ["bknd", "dist", "node_modules"] }