@sudowrite/shared-chat
v0.7.2
Published
Cross-platform Tamagui chat UI shared between Sudowrite web and React Native
Readme
@sudowrite/shared-chat
Cross-platform Tamagui chat UI shared between Sudowrite web and React Native.
Published to the public npm registry as
@sudowrite/shared-chat.
(Version 0.1.0 was briefly published as @rebecca-sudowrite/shared-chat
before the package moved to the @sudowrite org scope.)
Package layout
src/— Tamagui components, provider, and shared Storybook storiestamagui.config.ts— Sudowrite chat theme tokensdist/— Generated bynpm run build; gitignored, published to npm
Build outputs:
- Web (ESM/CJS):
dist/esm,dist/cjs - React Native:
dist/jsxvia thereact-nativeexport condition inpackage.json
Development
npm install
npm run build # tamagui-build → dist/ + types/
npm run type-check
npm run verify-native-export # validates package + native export conditions
npm run clean # remove generated artifactsDesign tokens and themes
Sudokit exposes the exact Sudowrite themes sorbet, moonbeam, sepia,
amber, forest, aurora-borealis, cauldron, and charcoal. The
compatibility names light and dark resolve to Sorbet and Charcoal,
respectively.
SharedChatProvider accepts the exact names (plus light and dark) and
handles the scheme-aware Tamagui mapping:
import { SharedChatProvider } from "@sudowrite/shared-chat";
<SharedChatProvider theme="forest">{children}</SharedChatProvider>;Consumers that use TamaguiProvider and the config directly must call
normalizeTamaguiThemeName. The unprefixed exact config aliases are
value-compatible, but Tamagui infers scheme, component-theme, and inverse-theme
behavior from the internal light_ / dark_ names.
import { TamaguiProvider } from "@tamagui/core";
import config, {
normalizeTamaguiThemeName,
} from "@sudowrite/shared-chat/config";
<TamaguiProvider
config={config}
defaultTheme={normalizeTamaguiThemeName("forest")}
>
{children}
</TamaguiProvider>;The generated web CJS and ESM entries target application bundlers. Importing those generated files directly in bare Node is not a supported package condition.
Both package entries expose:
- Raw
sudokitPrimitivesandsudokitShadows. exactSudowriteThemeNames,sharedChatThemeNames,sudokitThemes, andnormalizeSharedChatTheme, with theExactSudowriteThemeName,SharedChatThemeName, andSudokitThemetypes.- The scheme-aware
normalizeTamaguiThemeNameresolver and its stableResolvedTamaguiThemeNamereturn type. sudowriteTokens,sudokitFonts, andsudowriteChatConfig, with theSudowriteChatConfigtype.
Consumers load the Inter, Quattro, OpenDyslexic, GT Super Text, GT Super Display, IBM Plex Mono, and MedievalSharp assets themselves. The token snapshot bundles no font binaries, background images, scrollbar CSS rules, CSS filters, or other visual artifacts. Its values are a portable snapshot of canonical Sudowrite Express CSS and conventions, not a runtime or build-time cross-repo dependency.
Web usage
npm install @sudowrite/shared-chat tamagui @tamagui/core @tamagui/configWrap chat surfaces with SharedChatProvider, then import presentational components:
import {
SharedChatProvider,
ConversationStarters,
ChatMessageBubble,
} from "@sudowrite/shared-chat";Pass icons={defaultChatIcons} (or individual icon components) for conversation
starters and suggested actions. Paths match the Sudowrite web assets.
import {
ConversationStarters,
defaultChatIcons,
PersonalizationIcon,
RewriteIcon,
} from "@sudowrite/shared-chat";React Native usage
Install peer dependencies in the mobile app:
npm install @sudowrite/shared-chat tamagui @tamagui/core react-native-svgImport from the package using Metro's react-native export resolution:
import {
SharedChatProvider,
ConversationStarters,
defaultChatIcons,
} from "@sudowrite/shared-chat";Configure @tamagui/babel-plugin in the mobile app's babel.config.js with
components: ["@sudowrite/shared-chat", "tamagui"].
Native builds resolve dist/jsx/index.native.js (react-native-svg icons).
Web builds resolve the ESM/CJS entries (inline SVG via ChatIcons.web.tsx).
Storybook
Shared stories live in src/stories/ and ship in the npm tarball (files
includes src), so consuming apps run them in their own Storybook setups:
- Web (Sudowrite client): globs
node_modules/@sudowrite/shared-chat/src/stories/**— runnpm run storybookinclient/and open the SharedChat/ stories. - React Native (mobile app):
bun run storybook:generatethenbun run storybook:ios/storybook:androidfrommobile/app.
Render previews
render.yaml defines a static Storybook site (npm run build-storybook →
storybook-static) with automatic PR previews. After the Blueprint is
linked in the Sudowrite Render workspace, each PR gets its own Storybook URL.
Components
ConversationStarters/ConversationStartersContainerSuggestedActionCardChatMessageBubble/ChatPanel/ChatMessagesList/ChatComposerShelllayout shellsChatComposerShellwitheditor/footerslotsChatComposerModeSwitcherChatComposerSendStopButtonComposerAttachmentStripWriteModeBadge- Icons:
defaultChatIcons,PencilIcon,ChatIcon,SendIcon,StopIcon,CloseIcon,LightningIcon,RewriteIcon,DocumentIcon,PersonalizationIcon - Helpers:
resolveDefaultConversationStarters,resolveImportConversationStarters
Pressable starter/action shells use Tamagui XStack/YStack (not unstyled
Button) so they keep layout defaults on React Native, including inside
absolutely positioned empty states.
Platform-specific concerns (TipTap composer, Zustand store, analytics, InlineSVG) remain in the consuming apps and wrap these shared primitives.
ChatPanel intentionally excludes a header slot so mobile/web can keep their
own platform-specific headers. Shared shells cover the chat body: message
viewport, floating overlay lane, and composer region.
Commits
Commit messages follow Conventional Commits
(feat:, fix:, chore:, docs:, …) — they drive the version bump and the
changelog. A husky commit-msg hook lints messages locally, and CI lints both
PR commits and the PR title (the title becomes the squash-merge commit on main).
Releasing & publishing
Releases are automated with release-please:
- Merge conventional commits to
main. - release-please maintains a release PR that accumulates changes, updating
CHANGELOG.mdand the semver version (feat:→ minor,fix:→ patch,feat!:/BREAKING CHANGE:→ major). - Merging the release PR tags the release and publishes to npm using the
NPM_TOKENrepo secret.
If a publish fails (or a release is cut by hand), the Publish to npm
workflow can be re-run from the Actions tab.