diff --git a/.changeset/fresh-ways-deliver.md b/.changeset/fresh-ways-deliver.md deleted file mode 100644 index 59026f4c..00000000 --- a/.changeset/fresh-ways-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rozenite/controls-plugin': minor ---- - -Adds a new Controls plugin for exposing app-owned text values, toggles, and actions directly in React Native DevTools. \ No newline at end of file diff --git a/packages/controls-plugin/README.md b/packages/controls-plugin/README.md new file mode 100644 index 00000000..0752f3f1 --- /dev/null +++ b/packages/controls-plugin/README.md @@ -0,0 +1,118 @@ +![rozenite-banner](https://www.rozenite.dev/rozenite-banner.jpg) + +### A Rozenite plugin for exposing app-defined controls directly in React Native DevTools. + +The Controls Plugin lets you create a custom control panel for your app inside Rozenite. You define sections and items on the device, then use DevTools to read runtime values, flip toggles, switch options, submit text input, and trigger actions without building extra debug screens. + +![Controls Plugin](https://rozenite.dev/controls-plugin.png) + +## Installation + +```bash +npm install @rozenite/controls-plugin +``` + +## Usage + +```ts +import { createSection, useRozeniteControlsPlugin } from '@rozenite/controls-plugin'; +import { useMemo, useState } from 'react'; + +function App() { + const [verboseLogging, setVerboseLogging] = useState(false); + const [environment, setEnvironment] = useState('local'); + const [releaseLabel, setReleaseLabel] = useState('build-001'); + + const sections = useMemo( + () => [ + createSection({ + id: 'runtime-status', + title: 'Runtime Status', + items: [ + { + id: 'current-environment', + type: 'text', + title: 'Environment', + value: environment, + }, + { + id: 'verbose-logging', + type: 'toggle', + title: 'Verbose Logging', + value: verboseLogging, + onUpdate: setVerboseLogging, + }, + { + id: 'environment-selector', + type: 'select', + title: 'Environment', + value: environment, + options: [ + { label: 'Local', value: 'local' }, + { label: 'Staging', value: 'staging' }, + { label: 'Production', value: 'production' }, + ], + onUpdate: setEnvironment, + }, + { + id: 'release-label', + type: 'input', + title: 'Release Label', + value: releaseLabel, + placeholder: 'build-001', + applyLabel: 'Apply', + onUpdate: setReleaseLabel, + }, + { + id: 'reset-session', + type: 'button', + title: 'Reset Session', + actionLabel: 'Reset', + onPress: () => { + setVerboseLogging(false); + setEnvironment('local'); + setReleaseLabel('build-001'); + }, + }, + ], + }), + ], + [environment, releaseLabel, verboseLogging] + ); + + useRozeniteControlsPlugin({ sections }); + + return ; +} +``` + +## Supported Controls + +- `text`: Show read-only runtime values such as current environment, build label, or connection status. +- `toggle`: Enable or disable boolean flags from DevTools. +- `select`: Switch between predefined options such as backend targets or feature variants. +- `input`: Edit text values and apply them from DevTools. +- `button`: Trigger one-off actions such as reset, sync, refetch, or clear cache. + +## Organizing the Panel + +Group related controls into sections so the panel stays readable as your app grows: + +- Use one section for read-only diagnostics and another for mutable settings. +- Keep labels short and descriptive so they scan well in DevTools. +- Add `description` when a control changes app behavior in a non-obvious way. +- Use stable `id` values so controls remain predictable across reloads. + +## Validation and Disabled States + +Controls can guide users toward safe actions: + +- Use `validate` to block invalid values and show a clear error message in DevTools. +- Use `disabled` when a control should be visible but unavailable in the current state. +- For text input, `applyLabel` can make the action clearer than a generic submit button. + +## Notes + +- The panel appears in React Native DevTools as `Controls`. +- Updates flow both ways: local state changes are reflected in DevTools, and DevTools actions update the device. +- The hook is disabled in production builds. diff --git a/packages/controls-plugin/package.json b/packages/controls-plugin/package.json index 83811333..d61061b7 100644 --- a/packages/controls-plugin/package.json +++ b/packages/controls-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@rozenite/controls-plugin", - "version": "0.0.0", - "description": "Device-owned controls for Rozenite.", + "version": "1.4.0", + "description": "A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.", "type": "module", "main": "./dist/react-native.cjs", "module": "./dist/react-native.js", diff --git a/website/src/docs/official-plugins/_meta.json b/website/src/docs/official-plugins/_meta.json index d1d15e97..e0fadb20 100644 --- a/website/src/docs/official-plugins/_meta.json +++ b/website/src/docs/official-plugins/_meta.json @@ -49,6 +49,11 @@ "name": "storage", "label": "Storage" }, + { + "type": "file", + "name": "controls", + "label": "Controls" + }, { "type": "file", "name": "require-profiler", diff --git a/website/src/docs/official-plugins/controls.mdx b/website/src/docs/official-plugins/controls.mdx new file mode 100644 index 00000000..f0934557 --- /dev/null +++ b/website/src/docs/official-plugins/controls.mdx @@ -0,0 +1,160 @@ +import { PackageManagerTabs } from '@rspress/core/theme'; + +# Controls Plugin + +![](/controls-plugin.png) + +The Controls plugin lets you expose app-defined runtime controls inside React Native DevTools. Instead of adding temporary debug screens or hidden menus, you can give your team a dedicated panel for toggles, pickers, inputs, actions, and read-only status values. + +## What is Controls Plugin? + +The Controls plugin is a lightweight way to build a custom DevTools surface for your app. It provides: + +- **Read-only Status Fields**: Show current runtime values such as environment, build label, counters, or sync state +- **Toggles**: Turn feature flags and boolean options on or off from DevTools +- **Select Menus**: Switch between predefined options such as local, staging, and production +- **Text Inputs**: Update text-based settings without changing in-app UI +- **Action Buttons**: Trigger one-off actions such as reset, sync, refetch, or checkpoint creation + +## Installation + +Make sure to go through the [Getting Started guide](/docs/getting-started) before installing the plugin. + +Install the Controls plugin as a development dependency: + + + +## Base Setup + +```ts title="App.tsx" +import { createSection, useRozeniteControlsPlugin } from '@rozenite/controls-plugin'; +import { useMemo, useState } from 'react'; + +function App() { + const [verboseLogging, setVerboseLogging] = useState(false); + const [environment, setEnvironment] = useState('local'); + const [releaseLabel, setReleaseLabel] = useState('build-001'); + + const sections = useMemo( + () => [ + createSection({ + id: 'runtime-status', + title: 'Runtime Status', + items: [ + { + id: 'environment-label', + type: 'text', + title: 'Environment', + value: environment, + }, + { + id: 'verbose-logging', + type: 'toggle', + title: 'Verbose Logging', + value: verboseLogging, + onUpdate: setVerboseLogging, + }, + { + id: 'environment-selector', + type: 'select', + title: 'Environment', + value: environment, + options: [ + { label: 'Local', value: 'local' }, + { label: 'Staging', value: 'staging' }, + { label: 'Production', value: 'production' }, + ], + onUpdate: setEnvironment, + }, + { + id: 'release-label', + type: 'input', + title: 'Release Label', + value: releaseLabel, + placeholder: 'build-001', + applyLabel: 'Apply', + onUpdate: setReleaseLabel, + }, + { + id: 'reset-session', + type: 'button', + title: 'Reset Session', + actionLabel: 'Reset', + onPress: () => { + setVerboseLogging(false); + setEnvironment('local'); + setReleaseLabel('build-001'); + }, + }, + ], + }), + ], + [environment, releaseLabel, verboseLogging] + ); + + useRozeniteControlsPlugin({ sections }); + + return ; +} +``` + +## Usage + +Once configured, the Controls plugin appears in your React Native DevTools sidebar as `Controls`. + +Use it when you want to: + +- flip feature flags without building dedicated debug UI +- change runtime targets such as environment or API variant +- submit text values like labels, tokens, or test identifiers +- trigger app actions directly from DevTools +- keep read-only status values visible while testing flows + +## Control Types + +### Text + +Use `text` items for values you want to observe but not edit, such as status, counters, or last action timestamps. + +### Toggle + +Use `toggle` items for boolean settings such as feature flags, logging switches, and debug modes. + +### Select + +Use `select` items when the user must choose from a fixed list of options. + +### Input + +Use `input` items for text-based values. This is useful for release labels, test IDs, user identifiers, or other string settings you want to edit from DevTools. + +### Button + +Use `button` items for single actions. Good examples are reset, sync, refresh, retry, and seed actions. + +## Organizing Sections + +Sections help keep the panel understandable: + +- Put diagnostics and editable controls in separate sections. +- Prefer short titles so the panel stays easy to scan. +- Add descriptions when a control has side effects or temporary constraints. +- Keep section and item IDs stable across reloads. + +## Validation and Availability + +You can shape the user experience without exposing implementation details in the panel: + +- Use `validate` to reject invalid values with a clear message. +- Use `disabled` when a control should stay visible but unavailable. +- Use `applyLabel` on text inputs when a custom action label reads better than the default. + +## Common Uses + +- feature flag management during manual testing +- switching between local, staging, and production services +- resetting temporary app state +- triggering checkpoints for demos or QA flows +- exposing internal diagnostics without adding a screen to the app + +**Next**: Explore other [Official Plugins](./overview.md) or learn how to build your own in the [Plugin Development guide](../plugin-development/plugin-development.md). diff --git a/website/src/docs/official-plugins/overview.mdx b/website/src/docs/official-plugins/overview.mdx index 8f4956bb..818dd2a4 100644 --- a/website/src/docs/official-plugins/overview.mdx +++ b/website/src/docs/official-plugins/overview.mdx @@ -78,6 +78,15 @@ Inspect multiple storage backends from one panel using adapters for MMKV, AsyncS - **Per-Storage Blacklist**: Hide sensitive or noisy keys per storage instance - **Async + Sync Coverage**: Works with both sync (MMKV) and async (AsyncStorage/SecureStore) APIs +### [Controls](./controls.md) + +Expose app-defined controls directly in React Native DevTools so your team can inspect state, change flags, update text values, choose predefined options, and trigger actions from one panel. This plugin provides: + +- **Custom Runtime Panels**: Organize controls into sections that match your app workflows +- **Read + Write Controls**: Combine status fields, toggles, selects, inputs, and buttons +- **Validation Feedback**: Prevent invalid changes and show clear errors in DevTools +- **No Extra Debug Screens**: Keep temporary controls out of your in-app UI + ## Installing Plugins Plugins should be installed as development dependencies since they are only needed during development: @@ -96,6 +105,8 @@ Plugins should be installed as development dependencies since they are only need + + See the individual plugin documentation for complete installation instructions including hook setup. ## Configuration @@ -112,4 +123,4 @@ Want to contribute to plugins or suggest new ones? Check out our [Plugin Develop --- -**Next**: Learn about the [Expo Atlas plugin](./expo-atlas.md), [TanStack Query plugin](./tanstack-query.md), [Network Activity Inspector](./network-activity.md), [Redux DevTools plugin](./redux-devtools.md), [Performance Monitor plugin](./performance-monitor.md), [MMKV plugin](./mmkv.md), or [Storage plugin](./storage.md). +**Next**: Learn about the [Expo Atlas plugin](./expo-atlas.md), [TanStack Query plugin](./tanstack-query.md), [Network Activity Inspector](./network-activity.md), [Redux DevTools plugin](./redux-devtools.md), [Performance Monitor plugin](./performance-monitor.md), [MMKV plugin](./mmkv.md), [Storage plugin](./storage.md), or [Controls plugin](./controls.md). diff --git a/website/src/public/controls-plugin.png b/website/src/public/controls-plugin.png new file mode 100644 index 00000000..b39bf588 Binary files /dev/null and b/website/src/public/controls-plugin.png differ