diff --git a/packages/plugin-sdk-react/README.md b/packages/plugin-sdk-react/README.md new file mode 100644 index 0000000..d80dff2 --- /dev/null +++ b/packages/plugin-sdk-react/README.md @@ -0,0 +1,48 @@ +

+ + + + Sigma Logo + + +

+ +React bindings for the [`@sigmacomputing/plugin`](https://www.npmjs.com/package/@sigmacomputing/plugin) Client SDK. + +This package provides the `SigmaClientProvider` context provider and a set of +React hooks (`usePlugin`, `useConfig`, `useElementColumns`, `useElementData`, +etc.) that wrap the framework-agnostic client exported from +`@sigmacomputing/plugin`. + +## Installation + +```sh +yarn add @sigmacomputing/plugin @sigmacomputing/plugin-sdk-react +# or +npm install @sigmacomputing/plugin @sigmacomputing/plugin-sdk-react +``` + +`react` (`>= 16.8`) is required as a peer dependency. + +## Usage + +```tsx +import { client } from '@sigmacomputing/plugin'; +import { SigmaClientProvider, useConfig } from '@sigmacomputing/plugin-sdk-react'; + +function MyPlugin() { + const config = useConfig(); + return
{JSON.stringify(config, null, 2)}
; +} + +export function App() { + return ( + + + + ); +} +``` + +See the [`@sigmacomputing/plugin` README](https://github.com/sigmacomputing/plugin/blob/main/packages/plugin-sdk/README.md) +for the full hook reference. diff --git a/packages/plugin-sdk-react/package.json b/packages/plugin-sdk-react/package.json new file mode 100644 index 0000000..6bd9815 --- /dev/null +++ b/packages/plugin-sdk-react/package.json @@ -0,0 +1,54 @@ +{ + "name": "@sigmacomputing/plugin-sdk-react", + "version": "1.2.0", + "description": "React bindings for the Sigma Computing Plugin Client SDK", + "license": "MIT", + "type": "module", + "scripts": { + "build": "tsdown", + "build:watch": "tsdown --watch", + "format": "yarn g:format", + "lint": "yarn g:lint", + "publish": "yarn g:publlish", + "test": "vitest run", + "test:watch": "vitest", + "types": "yarn g:types" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "dependencies": { + "@sigmacomputing/plugin": "^1.2.0", + "dequal": "^2.0.3" + }, + "devDependencies": { + "tsdown": "^0.21.10", + "vitest": "^4.1.5" + }, + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.js", + "types": "./dist/cjs/index.d.cts", + "unpkg": "./dist/umd/sigmacomputing-plugin-sdk-react.umd.js", + "jsdelivr": "./dist/umd/sigmacomputing-plugin-sdk-react.umd.js", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.cts", + "default": "./dist/cjs/index.cjs" + } + }, + "./package.json": "./package.json" + }, + "files": [ + "dist/**/*", + "src/**/*", + "!src/**/__tests__/**/*" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/packages/plugin-sdk/src/react/Context.ts b/packages/plugin-sdk-react/src/Context.ts similarity index 57% rename from packages/plugin-sdk/src/react/Context.ts rename to packages/plugin-sdk-react/src/Context.ts index 2f1f941..7675119 100644 --- a/packages/plugin-sdk/src/react/Context.ts +++ b/packages/plugin-sdk-react/src/Context.ts @@ -1,6 +1,5 @@ import * as React from 'react'; -import { client } from '../client'; -import { PluginInstance } from '../types'; +import { client, PluginInstance } from '@sigmacomputing/plugin'; export const PluginContext = React.createContext(client); diff --git a/packages/plugin-sdk/src/react/Provider.tsx b/packages/plugin-sdk-react/src/Provider.tsx similarity index 87% rename from packages/plugin-sdk/src/react/Provider.tsx rename to packages/plugin-sdk-react/src/Provider.tsx index d5a4070..dbf9139 100644 --- a/packages/plugin-sdk/src/react/Provider.tsx +++ b/packages/plugin-sdk-react/src/Provider.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { PluginInstance } from '../types'; +import { PluginInstance } from '@sigmacomputing/plugin'; import { PluginContext } from './Context'; diff --git a/packages/plugin-sdk/src/react/__tests__/hooks.test.tsx b/packages/plugin-sdk-react/src/__tests__/hooks.test.tsx similarity index 99% rename from packages/plugin-sdk/src/react/__tests__/hooks.test.tsx rename to packages/plugin-sdk-react/src/__tests__/hooks.test.tsx index 99f4cf7..ad65992 100644 --- a/packages/plugin-sdk/src/react/__tests__/hooks.test.tsx +++ b/packages/plugin-sdk-react/src/__tests__/hooks.test.tsx @@ -1,9 +1,8 @@ import { act, renderHook } from '@testing-library/react'; import * as React from 'react'; -import { initialize } from '../../client/initialize'; -import { PluginInstance } from '../../types'; -import { SigmaClientProvider } from '../Provider'; +import { initialize, PluginInstance } from '@sigmacomputing/plugin'; + import { useActionEffect, useActionTrigger, @@ -19,6 +18,7 @@ import { useUrlParameter, useVariable, } from '../hooks'; +import { SigmaClientProvider } from '../Provider'; type Subscriber = (value: T) => void; diff --git a/packages/plugin-sdk/src/react/hooks.ts b/packages/plugin-sdk-react/src/hooks.ts similarity index 98% rename from packages/plugin-sdk/src/react/hooks.ts rename to packages/plugin-sdk-react/src/hooks.ts index adfd0b1..2ff08db 100644 --- a/packages/plugin-sdk/src/react/hooks.ts +++ b/packages/plugin-sdk-react/src/hooks.ts @@ -1,3 +1,4 @@ +import { dequal } from 'dequal/lite'; import * as React from 'react'; import { @@ -9,8 +10,7 @@ import { WorkbookVariable, PluginStyle, UrlParameter, -} from '../types'; -import { deepEqual } from '../utils/deepEqual'; +} from '@sigmacomputing/plugin'; import { PluginContext } from './Context'; @@ -34,7 +34,7 @@ export function useEditorPanelConfig( React.useEffect(() => { if (nextOptions == null) return; - if (!deepEqual(nextOptions, optionsRef.current)) { + if (!dequal(nextOptions, optionsRef.current)) { client.config.configureEditorPanel(nextOptions); optionsRef.current = nextOptions; } diff --git a/packages/plugin-sdk-react/src/index.ts b/packages/plugin-sdk-react/src/index.ts new file mode 100644 index 0000000..6960485 --- /dev/null +++ b/packages/plugin-sdk-react/src/index.ts @@ -0,0 +1,3 @@ +export * from './hooks'; +export type { SigmaClientProviderProps } from './Provider'; +export { SigmaClientProvider } from './Provider'; diff --git a/packages/plugin-sdk-react/tsconfig.app.json b/packages/plugin-sdk-react/tsconfig.app.json new file mode 100644 index 0000000..2ed40b8 --- /dev/null +++ b/packages/plugin-sdk-react/tsconfig.app.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.app.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + }, + "include": ["src"] +} diff --git a/packages/plugin-sdk-react/tsconfig.json b/packages/plugin-sdk-react/tsconfig.json new file mode 100644 index 0000000..473104a --- /dev/null +++ b/packages/plugin-sdk-react/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", + + "noEmit": true + }, + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/packages/plugin-sdk-react/tsconfig.node.json b/packages/plugin-sdk-react/tsconfig.node.json new file mode 100644 index 0000000..42f7286 --- /dev/null +++ b/packages/plugin-sdk-react/tsconfig.node.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.node.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" + }, + "include": ["tsdown.config.ts", "vitest.config.ts"] +} diff --git a/packages/plugin-sdk-react/tsdown.config.ts b/packages/plugin-sdk-react/tsdown.config.ts new file mode 100644 index 0000000..8d85220 --- /dev/null +++ b/packages/plugin-sdk-react/tsdown.config.ts @@ -0,0 +1,37 @@ +import { defineConfig } from 'tsdown'; + +// @ts-ignore - base config is defined outside of this package +import baseConfig from '../../tsdown.base.ts'; + +// Split into two configs so dequal stays external for ESM/CJS (consumers +// install it via npm) but is bundled into the UMD build, where shipping +// a self-contained file matters more than dedup. + +const baseFormat = baseConfig.format as Record; + +export default [ + defineConfig({ + ...baseConfig, + format: { + esm: baseFormat.esm, + cjs: baseFormat.cjs, + }, + }), + defineConfig({ + ...baseConfig, + deps: { alwaysBundle: [/^dequal(\/|$)/] }, + format: { + umd: { + outputOptions: { + ...baseFormat.umd.outputOptions, + entryFileNames: 'sigmacomputing-plugin-sdk-react.umd.js', + globals: { + ...baseFormat.umd.outputOptions.globals, + '@sigmacomputing/plugin': 'SigmaPlugin', + }, + name: 'SigmaPluginReact', + }, + }, + }, + }), +]; diff --git a/packages/plugin-sdk-react/vitest.config.ts b/packages/plugin-sdk-react/vitest.config.ts new file mode 100644 index 0000000..150a68b --- /dev/null +++ b/packages/plugin-sdk-react/vitest.config.ts @@ -0,0 +1,2 @@ +// @ts-ignore - base config is defined outside of this package +export { default } from '../../vitest.base.ts'; diff --git a/packages/plugin-sdk/package.json b/packages/plugin-sdk/package.json index 5098326..53d8ab7 100644 --- a/packages/plugin-sdk/package.json +++ b/packages/plugin-sdk/package.json @@ -14,14 +14,6 @@ "test:watch": "vitest", "types": "yarn g:types" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - }, "devDependencies": { "tsdown": "^0.21.10", "vitest": "^4.1.5" diff --git a/packages/plugin-sdk/src/index.ts b/packages/plugin-sdk/src/index.ts index ff3725e..8f011eb 100644 --- a/packages/plugin-sdk/src/index.ts +++ b/packages/plugin-sdk/src/index.ts @@ -1,5 +1,5 @@ export * from './types'; -export * from './react'; export * from './client'; +export { initialize } from './client/initialize'; export { polyfillRequestAnimationFrame } from './utils/polyfillRequestAnimationFrame'; diff --git a/packages/plugin-sdk/src/react.ts b/packages/plugin-sdk/src/react.ts deleted file mode 100644 index ae662c6..0000000 --- a/packages/plugin-sdk/src/react.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './react/hooks'; -export type { SigmaClientProviderProps } from './react/Provider'; -export { SigmaClientProvider } from './react/Provider'; diff --git a/packages/plugin-sdk/tsdown.config.ts b/packages/plugin-sdk/tsdown.config.ts index fdb5930..b14ad3f 100644 --- a/packages/plugin-sdk/tsdown.config.ts +++ b/packages/plugin-sdk/tsdown.config.ts @@ -1,15 +1,2 @@ -import { defineConfig, mergeConfig } from 'tsdown'; - // @ts-ignore - base config is defined outside of this package -import baseConfig from '../../tsdown.base.ts'; - -import packageJson from './package.json' with { type: 'json' }; - -export default mergeConfig( - baseConfig, - defineConfig({ - define: { - __VERSION__: JSON.stringify(packageJson.version), - }, - }), -); +export { default } from '../../tsdown.base.ts'; diff --git a/packages/plugin-sdk/vitest.config.ts b/packages/plugin-sdk/vitest.config.ts index c3e1107..150a68b 100644 --- a/packages/plugin-sdk/vitest.config.ts +++ b/packages/plugin-sdk/vitest.config.ts @@ -1,15 +1,2 @@ -import { defineConfig, mergeConfig } from 'vitest/config'; - // @ts-ignore - base config is defined outside of this package -import baseConfig from '../../vitest.base.ts'; - -import packageJson from './package.json' with { type: 'json' }; - -export default mergeConfig( - baseConfig, - defineConfig({ - define: { - __VERSION__: JSON.stringify(packageJson.version), - }, - }), -); +export { default } from '../../vitest.base.ts'; diff --git a/scripts/bump-version.ts b/scripts/bump-version.ts index 9a115df..ab94027 100644 --- a/scripts/bump-version.ts +++ b/scripts/bump-version.ts @@ -109,13 +109,34 @@ const writeNewVersion = (pkgPath: string, version: string): void => { writeFileSync(pkgPath, raw.replace(pattern, `$1${version}$2`)); }; +const escapeRegex = (value: string): string => + value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +const bumpInternalDeps = ( + pkgPath: string, + internalPackageNames: readonly string[], + version: string, +): void => { + let raw = readFileSync(pkgPath, 'utf8'); + for (const depName of internalPackageNames) { + const pattern = new RegExp( + `("${escapeRegex(depName)}"\\s*:\\s*")(?!workspace:)[^"]+(")`, + 'g', + ); + raw = raw.replace(pattern, `$1^${version}$2`); + } + writeFileSync(pkgPath, raw); +}; + type TurboQueryLsResponse = { packages: { items: { name: string; path: string }[]; }; }; -const findWorkspacePackageJsons = (): string[] => { +type WorkspacePackage = { name: string; pkgPath: string }; + +const findWorkspacePackages = (): WorkspacePackage[] => { const result = spawnSync( 'yarn', ['turbo', 'query', 'ls', '--output', 'json'], @@ -137,9 +158,10 @@ const findWorkspacePackageJsons = (): string[] => { result.stdout.slice(jsonStart), ) as TurboQueryLsResponse; - return parsed.packages.items.map(item => - path.join(item.path, 'package.json'), - ); + return parsed.packages.items.map(item => ({ + name: item.name, + pkgPath: path.join(item.path, 'package.json'), + })); }; const main = async (): Promise => { @@ -147,9 +169,13 @@ const main = async (): Promise => { const choices = buildChoices(current); const choice = await promptChoice(current.version, choices); - const targets = [PACKAGE_JSON_PATH, ...findWorkspacePackageJsons()]; + const workspaces = findWorkspacePackages(); + const internalPackageNames = workspaces.map(w => w.name); + const targets = [PACKAGE_JSON_PATH, ...workspaces.map(w => w.pkgPath)]; + for (const pkgPath of targets) { writeNewVersion(pkgPath, choice.next); + bumpInternalDeps(pkgPath, internalPackageNames, choice.next); console.log(`Bumped ${pkgPath}: ${current.version} -> ${choice.next}`); } }; diff --git a/vitest.base.ts b/vitest.base.ts index d84730c..a3de5fd 100644 --- a/vitest.base.ts +++ b/vitest.base.ts @@ -1,8 +1,11 @@ import { playwright } from '@vitest/browser-playwright'; import { defineConfig } from 'vitest/config'; +import packageJson from './package.json' with { type: 'json' }; + export default defineConfig({ define: { + __VERSION__: JSON.stringify(packageJson.version), __VITEST_BROWSER__: true.toString(), }, oxc: { diff --git a/yarn.lock b/yarn.lock index 6620614..602ae3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1193,6 +1193,19 @@ __metadata: languageName: node linkType: hard +"@sigmacomputing/plugin-sdk-react@workspace:packages/plugin-sdk-react": + version: 0.0.0-use.local + resolution: "@sigmacomputing/plugin-sdk-react@workspace:packages/plugin-sdk-react" + dependencies: + "@sigmacomputing/plugin": "npm:^1.2.0" + dequal: "npm:^2.0.3" + tsdown: "npm:^0.21.10" + vitest: "npm:^4.1.5" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + languageName: unknown + linkType: soft + "@sigmacomputing/plugin-sdk-root@workspace:.": version: 0.0.0-use.local resolution: "@sigmacomputing/plugin-sdk-root@workspace:." @@ -1226,17 +1239,12 @@ __metadata: languageName: unknown linkType: soft -"@sigmacomputing/plugin@workspace:packages/plugin-sdk": +"@sigmacomputing/plugin@npm:^1.2.0, @sigmacomputing/plugin@workspace:packages/plugin-sdk": version: 0.0.0-use.local resolution: "@sigmacomputing/plugin@workspace:packages/plugin-sdk" dependencies: tsdown: "npm:^0.21.10" vitest: "npm:^4.1.5" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react: - optional: true languageName: unknown linkType: soft