feat: integrate shiny-react module namespace support - #11
Merged
Conversation
Covers vendored source changes from wch/shiny-react#3, Python post_message namespace fix, upstream examples as reference material, build/export wiring, and JavaScript unit test plan. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10-task plan covering: Vitest infrastructure, ShinyModuleContext, use-shiny namespace support, ImageOutput update, ShinyReactComponentElement, global API wiring, Python post_message fix, upstream examples, and final build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…yMessageHandler Each hook now accepts an optional `namespace` parameter and also reads from ShinyModuleProvider context. Explicit namespace takes precedence over context. IDs are prefixed via applyNamespace() before registry lookups. Includes tests covering plain, explicit, context, and override scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add namespace prop and context-based namespace resolution to ImageOutput. The component now applies namespaces to clientdata input IDs and the output binding, enabling proper Shiny module support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ShinyReactComponentElement, a base HTMLElement subclass for creating custom elements that render React components with automatic Shiny integration. Features include namespace support via ShinyModuleProvider, slot preservation for blended content, data-* config parsing, and proper Shiny binding lifecycle management. Update shiny-react index.ts to export ShinyReactComponentElement, ShinyModuleProvider, and useShinyModuleNamespace. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ndow.shinyjson Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verbatim copies from wch/shiny-react#3 (gadenbuie:feat/multiple-react-roots). These use the @posit/shiny-react copy-paste pattern and won't run as-is within shinyjson. They serve as reference for future adaptation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ImageOutput was applying namespace to IDs then passing them to
useShinyInput/useShinyOutput, which also applied namespace from
context — resulting in IDs like "mod1-mod1-plot".
The namespace option on hooks now accepts `string | null`:
- undefined (omitted): use context namespace
- null: explicitly skip namespacing
- string: use this specific namespace
ImageOutput passes `{ namespace: null }` to suppress the hooks'
own namespacing since it already embeds the namespace in IDs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously captureSlots used either/or logic: if any [data-slot] elements existed, non-slotted children were silently dropped. Now named slots and __children__ coexist, matching native web component <slot> semantics. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pre-commit trailing-whitespace hook was modifying Vite's minified output, causing verify-js-built CI to fail because a clean rebuild produces different whitespace than the committed files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
schloerke
marked this pull request as ready for review
March 18, 2026 20:09
Collaborator
Author
|
Going to merge. Copilot can still post it's review and be fixed in a followup |
There was a problem hiding this comment.
Pull request overview
This PR vendors upstream shiny-react module namespace support into shinyjson’s JS bundle, fixes Python-side post_message() so custom message types are correctly namespaced inside Shiny modules, and adds a comprehensive JS test setup plus upstream examples for reference.
Changes:
- Add module namespace primitives (
ShinyModuleProvider,useShinyModuleNamespace,applyNamespace) and export them for downstream use. - Extend namespace support into
ImageOutputand align Pythonpost_message()with Shiny module namespacing viaresolve_id(), with a regression test. - Add Vitest/jsdom test infrastructure and copy upstream shiny-react examples into
examples/shiny-react-upstream/(plus tooling excludes/ignores).
Reviewed changes
Copilot reviewed 185 out of 192 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| pyproject.toml | Excludes upstream example directory from Ruff checks. |
| pkg-r/inst/lib/shiny/GIT_VERSION | Updates vendored JS asset version for the R package. |
| pkg-py/tests/test_post_message.py | Adds coverage for namespaced message types via resolve_id(). |
| pkg-py/src/shinyjson/www/GIT_VERSION | Updates vendored JS asset version for the Python package. |
| pkg-py/src/shinyjson/_post_message.py | Namespaces message type using resolve_id() before sending. |
| js/vitest.config.ts | Adds Vitest configuration (jsdom env) for JS unit tests. |
| js/src/shiny-react/index.ts | Exposes new namespace provider/hook and custom element base class. |
| js/src/shiny-react/tests/ShinyModuleContext.test.tsx | Tests namespacing utility and provider behavior. |
| js/src/shiny-react/ShinyModuleContext.tsx | Implements React context + helper for module namespaces. |
| js/src/shiny-react/ImageOutput.tsx | Adds optional namespace prop + context-based namespacing integration. |
| js/src/index.ts | Publishes new exports on window.shinyjson. |
| js/package.json | Adds vitest + testing dependencies and a npm test script. |
| examples/shiny-react-upstream/9-blended/tsconfig.json | Upstream example (blended) TS config. |
| examples/shiny-react-upstream/9-blended/srcts/main.tsx | Upstream example (blended) custom element usage. |
| examples/shiny-react-upstream/9-blended/r/app.R | Upstream example (blended) R app. |
| examples/shiny-react-upstream/9-blended/package.json | Upstream example (blended) build scripts/deps. |
| examples/shiny-react-upstream/8-modules/tsconfig.json | Upstream example (modules) TS config. |
| examples/shiny-react-upstream/8-modules/srcts/main.tsx | Upstream example (modules) React entrypoint. |
| examples/shiny-react-upstream/8-modules/srcts/CounterWidget.tsx | Upstream example (modules) widget using shiny-react hooks. |
| examples/shiny-react-upstream/8-modules/srcts/App.tsx | Upstream example (modules) provider-wrapped instances. |
| examples/shiny-react-upstream/8-modules/srcts-standard/styles.css | Upstream example (modules) standard/custom-element styling. |
| examples/shiny-react-upstream/8-modules/srcts-standard/main.tsx | Upstream example (modules) custom element definition entrypoint. |
| examples/shiny-react-upstream/8-modules/srcts-standard/CounterWidget.tsx | Upstream example (modules) widget used by custom element. |
| examples/shiny-react-upstream/8-modules/r/shinyreact.R | Upstream example (modules) R helpers. |
| examples/shiny-react-upstream/8-modules/r/app.R | Upstream example (modules) R app. |
| examples/shiny-react-upstream/8-modules/py/shinyreact.py | Upstream example (modules) Python helpers (async post_message). |
| examples/shiny-react-upstream/8-modules/py/app.py | Upstream example (modules) Python app. |
| examples/shiny-react-upstream/8-modules/package.json | Upstream example (modules) build scripts/deps. |
| examples/shiny-react-upstream/7-chat/tsconfig.json | Upstream example (chat) TS config. |
| examples/shiny-react-upstream/7-chat/srcts/main.tsx | Upstream example (chat) React entrypoint. |
| examples/shiny-react-upstream/7-chat/srcts/hooks/useImageUpload.ts | Upstream example (chat) image upload hook. |
| examples/shiny-react-upstream/7-chat/srcts/hooks/useDragAndDrop.ts | Upstream example (chat) DnD hook. |
| examples/shiny-react-upstream/7-chat/srcts/contexts/ThemeContext.tsx | Upstream example (chat) theme context. |
| examples/shiny-react-upstream/7-chat/srcts/components/ui/scroll-area.tsx | Upstream example (chat) UI component. |
| examples/shiny-react-upstream/7-chat/srcts/components/ui/input.tsx | Upstream example (chat) UI component. |
| examples/shiny-react-upstream/7-chat/srcts/components/ui/card.tsx | Upstream example (chat) UI component. |
| examples/shiny-react-upstream/7-chat/srcts/components/ui/button.tsx | Upstream example (chat) UI component. |
| examples/shiny-react-upstream/7-chat/srcts/components/ui/avatar.tsx | Upstream example (chat) UI component. |
| examples/shiny-react-upstream/7-chat/srcts/components/ImagePreview.tsx | Upstream example (chat) attachment preview UI. |
| examples/shiny-react-upstream/7-chat/r/shinyreact.R | Upstream example (chat) R helpers. |
| examples/shiny-react-upstream/7-chat/r/app.R | Upstream example (chat) R app. |
| examples/shiny-react-upstream/7-chat/py/shinyreact.py | Upstream example (chat) Python helpers. |
| examples/shiny-react-upstream/7-chat/py/requirements.txt | Upstream example (chat) Python requirements. |
| examples/shiny-react-upstream/7-chat/py/app.py | Upstream example (chat) Python app. |
| examples/shiny-react-upstream/7-chat/package.json | Upstream example (chat) build scripts/deps. |
| examples/shiny-react-upstream/7-chat/components.json | Upstream example (chat) shadcn/ui config. |
| examples/shiny-react-upstream/7-chat/build.ts | Upstream example (chat) build tooling. |
| examples/shiny-react-upstream/7-chat/.gitignore | Upstream example (chat) local ignore rules. |
| examples/shiny-react-upstream/6-dashboard/tsconfig.json | Upstream example (dashboard) TS config. |
| examples/shiny-react-upstream/6-dashboard/srcts/main.tsx | Upstream example (dashboard) React entrypoint. |
| examples/shiny-react-upstream/6-dashboard/srcts/css.d.ts | Upstream example (dashboard) CSS module typing. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/table.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/skeleton.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/separator.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/input.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/card.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/button.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/ui/badge.tsx | Upstream example (dashboard) UI component. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/Sidebar.tsx | Upstream example (dashboard) sidebar UI. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/MetricsCards.tsx | Upstream example (dashboard) metrics UI. |
| examples/shiny-react-upstream/6-dashboard/srcts/components/Dashboard.tsx | Upstream example (dashboard) main UI. |
| examples/shiny-react-upstream/6-dashboard/r/shinyreact.R | Upstream example (dashboard) R helpers. |
| examples/shiny-react-upstream/6-dashboard/py/shinyreact.py | Upstream example (dashboard) Python helpers. |
| examples/shiny-react-upstream/6-dashboard/py/app.py | Upstream example (dashboard) Python app. |
| examples/shiny-react-upstream/6-dashboard/package.json | Upstream example (dashboard) build scripts/deps. |
| examples/shiny-react-upstream/6-dashboard/components.json | Upstream example (dashboard) shadcn/ui config. |
| examples/shiny-react-upstream/6-dashboard/build.ts | Upstream example (dashboard) build tooling. |
| examples/shiny-react-upstream/6-dashboard/.gitignore | Upstream example (dashboard) local ignore rules. |
| examples/shiny-react-upstream/5-shadcn/tsconfig.json | Upstream example (shadcn) TS config. |
| examples/shiny-react-upstream/5-shadcn/srcts/main.tsx | Upstream example (shadcn) React entrypoint. |
| examples/shiny-react-upstream/5-shadcn/srcts/css.d.ts | Upstream example (shadcn) CSS module typing. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ui/separator.tsx | Upstream example (shadcn) UI component. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ui/input.tsx | Upstream example (shadcn) UI component. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ui/card.tsx | Upstream example (shadcn) UI component. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ui/button.tsx | Upstream example (shadcn) UI component. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ui/badge.tsx | Upstream example (shadcn) UI component. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/TextInputCard.tsx | Upstream example (shadcn) input/output card. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/PlotCard.tsx | Upstream example (shadcn) ImageOutput usage. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/ButtonEventCard.tsx | Upstream example (shadcn) event-priority input usage. |
| examples/shiny-react-upstream/5-shadcn/srcts/components/App.tsx | Upstream example (shadcn) app composition. |
| examples/shiny-react-upstream/5-shadcn/r/shinyreact.R | Upstream example (shadcn) R helpers. |
| examples/shiny-react-upstream/5-shadcn/r/app.R | Upstream example (shadcn) R app. |
| examples/shiny-react-upstream/5-shadcn/py/shinyreact.py | Upstream example (shadcn) Python helpers. |
| examples/shiny-react-upstream/5-shadcn/py/app.py | Upstream example (shadcn) Python app. |
| examples/shiny-react-upstream/5-shadcn/package.json | Upstream example (shadcn) build scripts/deps. |
| examples/shiny-react-upstream/5-shadcn/components.json | Upstream example (shadcn) shadcn/ui config. |
| examples/shiny-react-upstream/5-shadcn/build.ts | Upstream example (shadcn) build tooling. |
| examples/shiny-react-upstream/5-shadcn/.gitignore | Upstream example (shadcn) local ignore rules. |
| examples/shiny-react-upstream/4-messages/tsconfig.json | Upstream example (messages) TS config. |
| examples/shiny-react-upstream/4-messages/srcts/main.tsx | Upstream example (messages) React entrypoint. |
| examples/shiny-react-upstream/4-messages/srcts/App.tsx | Upstream example (messages) message handler demo. |
| examples/shiny-react-upstream/4-messages/r/shinyreact.R | Upstream example (messages) R helpers. |
| examples/shiny-react-upstream/4-messages/r/app.R | Upstream example (messages) R app. |
| examples/shiny-react-upstream/4-messages/py/shinyreact.py | Upstream example (messages) Python helpers. |
| examples/shiny-react-upstream/4-messages/py/app.py | Upstream example (messages) Python app. |
| examples/shiny-react-upstream/4-messages/package.json | Upstream example (messages) build scripts/deps. |
| examples/shiny-react-upstream/4-messages/README.md | Upstream example (messages) documentation. |
| examples/shiny-react-upstream/4-messages/.gitignore | Upstream example (messages) local ignore rules. |
| examples/shiny-react-upstream/3-outputs/tsconfig.json | Upstream example (outputs) TS config. |
| examples/shiny-react-upstream/3-outputs/srcts/main.tsx | Upstream example (outputs) React entrypoint. |
| examples/shiny-react-upstream/3-outputs/srcts/StatisticsCard.tsx | Upstream example (outputs) output rendering. |
| examples/shiny-react-upstream/3-outputs/srcts/SliderCard.tsx | Upstream example (outputs) input control. |
| examples/shiny-react-upstream/3-outputs/srcts/PlotCard.tsx | Upstream example (outputs) ImageOutput usage. |
| examples/shiny-react-upstream/3-outputs/srcts/InputOutputCard.tsx | Upstream example (outputs) shared UI wrapper. |
| examples/shiny-react-upstream/3-outputs/srcts/DataTableCard.tsx | Upstream example (outputs) table output rendering. |
| examples/shiny-react-upstream/3-outputs/srcts/Card.tsx | Upstream example (outputs) shared UI wrapper. |
| examples/shiny-react-upstream/3-outputs/srcts/App.tsx | Upstream example (outputs) app composition. |
| examples/shiny-react-upstream/3-outputs/r/shinyreact.R | Upstream example (outputs) R helpers. |
| examples/shiny-react-upstream/3-outputs/r/mtcars.csv | Upstream example (outputs) sample data. |
| examples/shiny-react-upstream/3-outputs/r/app.R | Upstream example (outputs) R app. |
| examples/shiny-react-upstream/3-outputs/py/shinyreact.py | Upstream example (outputs) Python helpers. |
| examples/shiny-react-upstream/3-outputs/py/mtcars.csv | Upstream example (outputs) sample data. |
| examples/shiny-react-upstream/3-outputs/py/app.py | Upstream example (outputs) Python app. |
| examples/shiny-react-upstream/3-outputs/package.json | Upstream example (outputs) build scripts/deps. |
| examples/shiny-react-upstream/3-outputs/.gitignore | Upstream example (outputs) local ignore rules. |
| examples/shiny-react-upstream/2-inputs/tsconfig.json | Upstream example (inputs) TS config. |
| examples/shiny-react-upstream/2-inputs/srcts/main.tsx | Upstream example (inputs) React entrypoint. |
| examples/shiny-react-upstream/2-inputs/srcts/TextInputCard.tsx | Upstream example (inputs) input/output demo. |
| examples/shiny-react-upstream/2-inputs/srcts/SliderInputCard.tsx | Upstream example (inputs) input/output demo. |
| examples/shiny-react-upstream/2-inputs/srcts/SelectInputCard.tsx | Upstream example (inputs) input/output demo. |
| examples/shiny-react-upstream/2-inputs/srcts/RadioInputCard.tsx | Upstream example (inputs) input/output demo. |
| examples/shiny-react-upstream/2-inputs/srcts/NumberInputCard.tsx | Upstream example (inputs) input/output demo. |
| examples/shiny-react-upstream/2-inputs/srcts/InputOutputCard.tsx | Upstream example (inputs) shared UI wrapper. |
| examples/shiny-react-upstream/2-inputs/srcts/FileInputCard.tsx | Upstream example (inputs) file input demo. |
| examples/shiny-react-upstream/2-inputs/srcts/DateInputCard.tsx | Upstream example (inputs) date input demo. |
| examples/shiny-react-upstream/2-inputs/srcts/CheckboxInputCard.tsx | Upstream example (inputs) checkbox demo. |
| examples/shiny-react-upstream/2-inputs/srcts/Card.tsx | Upstream example (inputs) shared UI wrapper. |
| examples/shiny-react-upstream/2-inputs/srcts/ButtonInputCard.tsx | Upstream example (inputs) event-priority demo. |
| examples/shiny-react-upstream/2-inputs/srcts/BatchFormCard.tsx | Upstream example (inputs) batch submission demo. |
| examples/shiny-react-upstream/2-inputs/srcts/App.tsx | Upstream example (inputs) app composition. |
| examples/shiny-react-upstream/2-inputs/r/shinyreact.R | Upstream example (inputs) R helpers. |
| examples/shiny-react-upstream/2-inputs/r/app.R | Upstream example (inputs) R app. |
| examples/shiny-react-upstream/2-inputs/py/shinyreact.py | Upstream example (inputs) Python helpers. |
| examples/shiny-react-upstream/2-inputs/py/app.py | Upstream example (inputs) Python app. |
| examples/shiny-react-upstream/2-inputs/package.json | Upstream example (inputs) build scripts/deps. |
| examples/shiny-react-upstream/2-inputs/README.md | Upstream example (inputs) documentation. |
| examples/shiny-react-upstream/2-inputs/.gitignore | Upstream example (inputs) local ignore rules. |
| examples/shiny-react-upstream/1-hello-world/tsconfig.json | Upstream example (hello world) TS config. |
| examples/shiny-react-upstream/1-hello-world/srcts/main.tsx | Upstream example (hello world) React entrypoint. |
| examples/shiny-react-upstream/1-hello-world/srcts/HelloWorldComponent.tsx | Upstream example (hello world) basic hook usage. |
| examples/shiny-react-upstream/1-hello-world/r/shinyreact.R | Upstream example (hello world) R helpers. |
| examples/shiny-react-upstream/1-hello-world/r/app.R | Upstream example (hello world) R app. |
| examples/shiny-react-upstream/1-hello-world/py/shinyreact.py | Upstream example (hello world) Python helpers. |
| examples/shiny-react-upstream/1-hello-world/py/app.py | Upstream example (hello world) Python app. |
| examples/shiny-react-upstream/1-hello-world/package.json | Upstream example (hello world) build scripts/deps. |
| examples/shiny-react-upstream/1-hello-world/README.md | Upstream example (hello world) documentation. |
| examples/shiny-react-upstream/1-hello-world/.gitignore | Upstream example (hello world) local ignore rules. |
| Makefile | Adds js-test target to run Vitest. |
| .pre-commit-config.yaml | Excludes generated dist/vendor dirs from whitespace/EOL hooks. |
| .gitignore | Ignores built assets for upstream examples (pattern added). |
Files not reviewed (1)
- js/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
schloerke
added a commit
that referenced
this pull request
Mar 18, 2026
- Await async post_message() in 8-modules example - Update ShinyModuleContext JSDoc to reflect nesting behavior - Clarify applyNamespace docs for empty string/null/undefined - Add namespace prop JSDoc to ImageOutput component - Remove debug print(env_file) in 7-chat example - Fix tailwind.css path in 5-shadcn components.json - Fix 5-shadcn package.json name/description, add private:true - Fix indentation in 8-modules srcts-standard/main.tsx Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
schloerke
added a commit
that referenced
this pull request
Mar 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integrates module namespace support from wch/shiny-react#3 into shinyjson's vendored shiny-react copy, and copies the upstream examples as reference material.
Summary
ShinyModuleContext— New React context provider (ShinyModuleProvider),useShinyModuleNamespace()hook, andapplyNamespace()utility for prefixing IDs with module namespacesShinyReactComponentElement— BaseHTMLElementsubclass for custom web elements that render React components with automatic namespace wrapping, slot preservation,data-*config parsing, and Shiny binding lifecycleuseShinyInput,useShinyOutput,useShinyMessageHandler, andImageOutputall accept an optionalnamespaceparameter and auto-read fromShinyModuleProvidercontextpost_messagefix — Wraps message type inresolve_id()so messages inside Shiny modules are correctly namespacedexamples/shiny-react-upstream/as reference material for future adaptationVerification
After
make js-build && make update-dist:All checks pass: 24 JS tests, 20 Python tests, TypeScript compiles, pyright clean.