jg-personal-react-ui

中文文档
0.4.0发布于 2026/11/04MITTypeScriptES Module构建来源已验证

JG-branded React components and styles, sharing Moldea-derived APIs with the unbranded jg-react-ui implementation.

原始使用文档
文档目录12 节
  1. Install
  2. Usage
  3. Preferences, theme, and notifications
  4. Controls, forms, and plain text
  5. Dialogs, drawers, and layout
  6. Routing and query recovery
  7. File uploads and audio input
  8. Markdown and code
  9. Markdown editors
  10. Documentation
  11. License
  12. Source comparisons

jg-personal-react-ui

JG-branded React components backed by the shared jg-react-ui implementation.

Install

pnpm add jg-personal-react-ui

Usage

import { createElement } from 'react';
import { Button } from 'jg-personal-react-ui/components/button';
const saveAction = createElement(Button, { size: 'touch' }, 'Save changes');

Import Tailwind once, then jg-personal-react-ui/styles.css.

Button, Badge, IconTile, Alert, their composition slots, variants, and public contracts are direct re-exports of jg-react-ui. JgMark is the decorative JG mark, with className for layout and the same fixed artwork as Astro. Import it from the root or jg-personal-react-ui/components/jg-mark; pair it with visible text when identifying a brand link.

ErrorFeedbackProvider scopes application-owned error copy and access-loss classification to a React tree. Pass a resolver from createErrorFeedback in jg-exception; useErrorFeedbackResolver reads the nearest policy. Without a provider, unknown diagnostics and codes remain private behind generic copy. Cancellation stays recognizable, and a throwing application policy falls back safely.

Preferences, theme, and notifications

Compose UiPreferencesProvider, ThemeProvider, and one Toastr host in that order. ThemeToggleButton retains the source Button props and request callback. The document theme and Sonner notification channel are document-wide; keep one theme owner and one notification host per document even when independent preference roots are mounted.

Sonner injects its base notification CSS when its browser module loads. Package theme styles remain explicit imports. All JavaScript entries remain importable without browser globals on the server.

The preference provider supports explicit local, read-only, and remote modes. Local mode reads and writes best-effort browser storage and follows matching cross-tab events. Read-only mode exposes a snapshot and denies updates. Remote mode requires complete initialPreferences and an async persistPreferences adapter: updates are optimistic, saves run sequentially and coalesce newer snapshots, and a rejected save rolls back to the latest authoritative props. The application owns network requests and cache invalidation. Pending requests cannot update storage or show notifications after unmount.

Optional storageId defaults to jg-ui-preferences. It must be non-empty and contain only ASCII letters, digits, underscores, and hyphens. getUiPreferencesStorageKey returns its raw jg-storage: key. IDs are captured for the provider lifetime; use a keyed remount to change namespaces. Invalid IDs fail before storage access or initialization-script creation.

Render ThemeInitializationScript in the document head before application JavaScript, using the same storageId as the provider and your CSP nonce when required. Server snapshots use initial props or defaults, then storage synchronizes after hydration. See the recipes for composition and the shared owned error contracts.

Controls, forms, and plain text

The forms, menus, tabs, tooltips, copy commands, progress, empty states, typography, tables, links, and inline code are direct exports of jg-react-ui. Their refs, native attributes, slots, event aliases, and cancellation behavior share the same implementation and contexts. JG styles bind field, code, menu, and inverse dark-theme roles; set font-sans bg-background text-foreground on the application root. Keep compact choice glyphs inside associated label rows of at least 44px, and give overflowing tables a labelled, focusable region with visible focus. See the recipes for compositions.

Dialogs, drawers, and layout

Dialog, AlertDialog, Drawer, ConfirmationDialog, and page/layout primitives retain the pinned compound APIs. DialogContent requires a size and direct DialogHeader, DialogBody, and optional DialogFooter children; asChild accepts one panel element containing those regions. Use an element that permits the dialog role, such as a div; place a form inside the body and associate fixed submit actions with its form ID. Drawer requires a side, its content requires a size, and its direct regions are ordered header, body, optional footer. AlertDialogContent requires a direct header and footer. Invalid composition and invalid slotted children retain native Error guards.

Medium and large dialogs become full-screen pages on phones, with generated Back and desktop close controls. Body regions own scrolling, while headers and actions stay fixed. Compact modal close controls retain their fine-pointer appearance and have actual 44px targets under a coarse pointer. The default initial focus skips unusable controls; initialFocus and generated control icons/labels remain configurable. Overlay dismissal stays disabled by default for dialogs. isDismissalDisabled blocks on-page dismissal; committed navigation still cancels obsolete dialogs.

DialogNavigationProvider, DialogNavigationObserver, and useDialogNavigationDismissal directly reuse jg-react-router's implementations and context. Place the observer inside the router, with persistent dialog hosts under the same provider. Navigation dismissal does not create history entries. The host application owns route history and its navigation UI; drawers close on route actions through an explicit DrawerClose composition or application state.

Mount one ConfirmationDialog per document and use useConfirmationDialogStore.getState().openConfirmationDialog(options). This imperative store retains the source's document-wide session API; do not mutate it while server rendering. Completion resets the session before calling the application callback, which receives true on confirmation and undefined on cancellation. The application owns async work and callback errors. Controlled dialog children remain immutable through closing transitions, then release at completion. Mobile return snapshots ignore stale callbacks and are skipped for reduced motion or unsupported browsers.

PageShell, PageHeader, PageHeaderRow, PageHeaderTitleGroup, PageHeaderMetadata, PageTitle, PageDescription, Stack, Inline, and Surface preserve the native semantic props and shared geometry. JG binds the generic surface shadow role to the shared foundation. The stylesheet supplies source page-gutter spacing and the drawer gutter hooks; it does not reset the document's palette or typography.

Routing and query recovery

RouterRoot retains the source data-router outlet, pending progress, and shared dialog observer. It requires React Router's data router and the shared router peer. Route progress respects the top safe-area inset. It does not add history entries or change page focus/scroll policy; compose jg-react-router's PageOutlet when the host wants that behavior. GlobalErrorBoundary reads the thrown route error, focuses its labelled recovery main, preserves native refs, and cancels obsolete dialog sessions; GlobalErrorBoundaryView accepts an explicit error without router context. Recovery defaults to jg-sw's updateApp, with an optional onRefreshClick. Unknown errors and recovery failures use scoped safe feedback. Pending refresh and retry actions ignore overlapping clicks.

QueryBoundary, QueryLoader, LoadMoreButton, QueryErrorAlert, and QueryErrorToastr retain the structural query APIs. The boundary delegates initial resolution to jg-tanstack-query's shared hook: stale unapproved data waits, current data survives background failures, a new resolutionKey starts over, and access loss hides data immediately. After access loss, caller approval cannot restore data until every query settles successfully with current data. The nearest ErrorFeedbackProvider owns access-loss classification and visible copy; no application registry ships with these packages.

The default error slot is an inline blocking/retained alert. Custom renderers can use a persistent QueryErrorToastr for retained content. Supply a unique stable toastId per active failure owner and one Toastr host per document. Toast publication follows commit effects so a later-mounted host receives initial failures, and stale queued feedback is cancelled. Retry reads the latest committed queries and policy, ignores active fetches/overlapping retries, and keeps failures actionable until recovery; unmount cleanup preserves a same-ID replacement. Retry settles every failed query, including rejected or synchronously throwing adapters. Cancelled errors produce no outage alert or toast. Load-more click callbacks run first and may cancel the request with preventDefault.

Default compact pagination and recovery actions preserve their fine-pointer geometry and have at least 44px targets under a coarse pointer. JG's global recovery surface uses the foundation's inverse palette in both themes. Generic consumers set --jg-ui-inverse-color-scheme to match their recovery surface (dark or light); selection and focus use its primary roles. Query clients, network adapters, pagination limits, application code maps, and routing history remain host-owned.

File uploads and audio input

These components are direct exports of jg-react-ui. FileUpload, FileUploadDialog, ImageUploadField, and AudioInput retain the pinned source props and callbacks. File uploads reuse jg-react's admission, concurrency, progress, cancellation, and retry queue. The caller supplies validation and transport callbacks; no endpoint, authorization policy, storage service, or transcription provider is included. Upload adapters must honor their abort signal. The image field displays the caller's current image and falls back safely when its preview fails; the caller owns object URL creation and revocation.

The upload dialog finalizes successful results through onSubmit, retries finalization without reuploading, and reports abandoned successful items through onDiscard. The caller owns remote cleanup and callback failures. Audio input owns microphone tracks, recorder handlers, waveform contexts, intervals, and deferred commands. Obsolete permission/transcription results cannot update a replacement session or call completion after unmount. Recording reset is immediate; closing retains the source's short visual reset delay.

transcribe receives the captured recording and returns text. Users can send directly or edit the transcription first; a failed send retries the authored text without transcribing again. Provider operations remain caller-owned and should have their own deadline/cancellation policy. Recording/transcription error callbacks receive diagnostic exceptions, while visible feedback uses the nearest scoped resolver. The seven owned audio codes and stable messages are listed in errors/README.md; coded provider exceptions preserve their diagnostic identity. Canceled permission/transcription work stays silent and can be restarted; diagnostic callbacks still run. Optional result callbacks remain optional. Standalone review remains the default. Supply onTranscriptionApply for main-input Transcribe and onTranscriptionResult for the consumer's ordinary Send action. isResultActionVisible={false} keeps a single direct-apply action. The active button alone shows pending progress, and pending work blocks restart and dismissal.

Markdown and code

Markdown retains GFM tables/task lists, heading and prose rendering, uppercase template-variable highlights, image width hints (title="width=560"), renderer/plugin overrides, and standalone YouTube links. Raw HTML is skipped by default. HTTP(S) and relative document links open in secure new tabs by default, with an accessible announcement; fragments and non-web links remain in the current tab. Set shouldOpenLinksInNewTab={false} or supply an anchor renderer for application routing. Applications own the trust policy of custom plugins, URL transforms, and renderers.

Message columns need min-width: 0; grid tracks use minmax(0, 1fr). Markdown and InlineCode wrap long paths and unbroken tokens. InlineCode retains preferred separator breaks without changing copied text. Code blocks and tables contain their own horizontal scrolling; Markdown tables have labelled, keyboard-focusable scroll groups. Unlabelled fences remain preformatted code blocks with exact whitespace.

CodeBlock and CodeFileHeader preserve metadata/status/action slots, aliases, syntax highlighting, literal plain mode, custom copy text, and wrapping controls. Declared prose languages or prose file extensions wrap automatically. prefersWrappedCode takes precedence over shouldWrapContent, then automatic prose wrapping and the scoped saved preference. Explicit overrides and read-only providers hide mutation controls. diff and diff-<language> fences preserve source endings, patch markers and multiline syntax. CodePreferencesControls also exposes split/unified preference menus for source surfaces. Compact actions keep the source fine-pointer geometry and use 44px coarse-pointer targets.

The personal adapter maps syntax and file-status roles to jg-personal-ui's existing theme tokens. Generic syntax uses unbranded One-theme fallbacks; supply --syntax-foreground and --syntax-token-{keyword,string,string-expression,comment,function,constant,parameter,punctuation,link} to override them. Token maps are reused across renders, and unchanged Markdown parser inputs are memoized. Every grammar/style import names its exact JavaScript file, so Node imports need no consumer resolver changes.

parseYouTubeVideoUrl validates supported HTTPS single-video links and returns a branded identifier. YouTubeVideo uses the fixed privacy-enhanced origin, strips authored playback parameters, and enables autoplay only through its explicit prop. URL validation/building reuses jg-utilities, with the retained UI's narrower route policy. A forged invalid identifier throws the dependency's documented INVALID_YOUTUBE_VIDEO_ID contract.

Markdown editors

MarkdownEditor retains the controlled value/onChange, supportedTools, accessibility props, and auto/compact/wide layouts. Auto measures the owning container and selects wide at 640px. CompactMarkdownEditor and WideMarkdownEditor expose the same props without layout. A changed value replaces the document as one edit that keeps the editor's focus, with the caret at the end of the text, and isn't reported back through onChange. The exported all-tools, authoring, and prose policies retain the source command sets; existing documents remain readable when authoring tools are constrained.

ChatMarkdownEditor retains paragraph, H1–H3, bullet/numbered-list, bold/italic, and safe-link formatting. HTML is removed, unsupported blocks become readable prose, and image alternatives remain text. Paste checks bound raw input before parsing and the serialized result before replacing the draft. Rejected paste leaves the draft intact; formatting feedback remains until the next edit.

Supply a positive safe-integer maxLength, which counts the message without the line break its Markdown ends with. maxEditorHeight defaults to 256px, must be positive and finite, and is constrained to 50dvh by the stylesheet. controlsRef exposes getMarkdown(), focus(), and appendLiteralText(text). Literal insertion escapes Markdown and normally returns false before readiness or when the draft is too long. Opt into { allowOverLimit: true } for complete dictation retention before readiness and subsequent editing; read-only editors still reject insertion. Consumers own length and submission guards. Change the editor key with draft identity after success to reset content and undo history. Initial snapshots retain the controlled draft, and focus waits for the initialized editor. Use these controls to compose caller-owned upload and dictation flows.

formattingContainer uses inline placement when omitted, reserves external placement with null, and portals the formatting menu into a supplied HTMLElement. The existing styles.css entry includes Milkdown's common/frame styles before editor overrides. The personal package re-exports the generic implementations directly and supplies the shared JG tokens.

Invalid configuration retains these native Error messages:

  • ChatMarkdownEditor maxLength must be a positive safe integer.
  • ChatMarkdownEditor maxEditorHeight must be a positive finite number.

Documentation

The API reference ships as API.md, and app-side examples ship as RECIPES.md. These personal-use packages are unlisted on the public package website.

License

MIT.

Source comparisons

CodeDiff, CODE_DIFF_LANGUAGES, and their public types are direct re-exports of jg-react-ui/components/code-diff. JG tokens supply colors, typography, and surface styling. The base ships its checked patched viewer and lazy worker chunk, so consumers need no patch configuration. The private gallery's /diff route exercises folding, preferences, revision updates, long paths, and a separate consumer-owned base theme in both color schemes.

版本与发布记录

jg-personal-react-ui 共发布 9 个版本,首次发布于 2026/10/30;过去 12 个月发布了 9 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.0latest2026/11/041 天前
0.3.42026/11/041 天前
0.3.32026/11/032 天前
0.3.22026/11/032 天前
0.3.12026/11/022 天前
0.3.02026/10/314 天前

关于 jg-personal-react-ui 的常见问题

jg-personal-react-ui 是什么?

JG-branded React components and styles, sharing Moldea-derived APIs with the unbranded jg-react-ui implementation.

如何安装 jg-personal-react-ui?

在项目目录运行 npm install jg-personal-react-ui,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^19.2.4)、react-dom(^19.2.4)、tailwindcss(^4.3.3)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

jg-personal-react-ui 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

jg-personal-react-ui 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

jg-personal-react-ui 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.17.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

jg-personal-react-ui 可以商用吗?

jg-personal-react-ui 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

jg-personal-react-ui 还在维护吗?

最新版本 0.4.0 发布于 2026/11/04(1 天前);至今共发布 9 个版本,其中过去 12 个月发布了 9 个;首次发布于 2026/10/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。