@firna/ui

中文文档
5.1.0发布于 2026/11/08MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 3758

Shared React Native and web UI primitives for Firna apps.

原始使用文档
文档目录12 节
  1. Key Features
  2. User-Facing Interface
  3. Installation
  4. Theming
  5. Focus indicators
  6. Web focus CSS and server rendering
  7. Chart colors
  8. Developer Get Started
  9. Package Releases
  10. Storybook Deployments
  11. Key Code Jumping Points
  12. Related Repositories

ui

Shared UI component library for Firna React Native and web surfaces. The first consumers are the accounting app and the Juno app.

Key Features

  • Shared dropdown menu, selector, combobox, drag-select, segmented control, radio card, switch, spinner, loaders (six indeterminate shapes plus determinate progress bar and ring), button, labelled input/textarea, data table, editable data grid (Airtable/Notion-style), a from-scratch interactive chart family (bar, line, area, sparkline, stat tile, donut, gauge, bullet, funnel, matrix heatmap, scatter, histogram, waterfall, small multiples) on a colourblind-validated palette, cross-platform block rich-text editor with canonical markdown and a collaboration layer (live carets, tracked changes, comment threads), modal, toast provider/controller, avatar, status badge, animated comet-trail border, calendar heatmap, full event-calendar (month/week/day/agenda, recurring events, drag-to-create), branching workflow-builder step-graph primitives, a multi-track editing timeline with pro clip edits, and the video-editor panels that surround it (program monitor, transport, level meter, media bin, property inspector, effects rack, keyframe editor, export dialog).
  • A shared xs / sm / md / lg size scale (ControlSize) across the interactive controls — buttons, inputs, dropdown selectors, date fields, segmented controls, switches, and list rows. xs is the dense 26px size.
  • Touch surfaces: inside a TouchSurface, the controls and list rows give each target at least 44 by 44px, whatever their size. An optional compact text scale serves dense surfaces.
  • App shell parts: link buttons and link tabs with current-page state, neutral and urgent notices, page and panel empty states, menus drawn open in place with a phone menu sheet, and a controlled panel resize handle.
  • Themeable visual tokens so consumers can use their own brand primary color, with four shipped presets — the accounting default and Juno, each in a light and a dark variant. Every component reads its colors from the tokens, so dark mode is a preset swap rather than a per-component opt-in.
  • A shared, calm focus glow across every control. On web the DOM backend paints it from CSS :focus-visible, so server-rendered and static HTML keeps the same keyboard affordance before hydration — or with no JavaScript at all. Native keeps its platform focus behavior. One focusIndicator setting — on the theme for every control, or per instance — picks the glow (ring), the browser outline on the control's visible box (outline), or no focus styling at all (none) for a control embedded in a surface that shows focus itself.
  • Portaled, anchored web date/dropdown/popover overlays, each placed by its own measured size so it flips above its trigger rather than being clipped, with content-sized selector menus and z-index escape hatches, plus touch-friendly native date sheets.
  • Stacked web dialogs with focus control for the top dialog, ordered focus return, a page scroll lock, and live toast feedback, plus native dialogs and bottom sheets.
  • Platform files shared by Expo, React Native, and the library's own DOM backend on web.
  • Focused unit tests, browser interaction tests, and package export checks.
  • Storybook previews for visual review on same-repository non-release PRs.
  • Release-please release PRs and npm trusted publishing for @firna/ui.

User-Facing Interface

The package name is @firna/ui. Public exports are available from:

  • @firna/ui for all public components and helpers.
  • @firna/ui/animated-border for the animated comet-trail border that traces a rounded-rectangle perimeter to highlight an element, in a single color or a two-color brand gradient.
  • @firna/ui/avatar for the themed initials avatar (circle or rounded square).
  • @firna/ui/badge for the themed status badge pill with tone, variant, and size variants.
  • @firna/ui/button for the themed button with tone, size, and block variants, and a role that re-points it at another single-activation role (checkbox, menuitem, radio, switch, tab) with the state that role must carry — so a tab or checkbox keeps the shared focus glow instead of being hand-rolled.
  • @firna/ui/calendar for the full event calendar (month, week, day, and agenda views, recurring events, and drag-to-create).
  • @firna/ui/chart for the interactive chart family — bar, line, area, sparkline, stat tile, donut, gauge, bullet, funnel, matrix heatmap, scatter, bubble, histogram, waterfall and small multiples — built from this library's own primitives and react-native-svg, with no charting dependency. Every chart ships a keyboard-navigable hit layer, a hover/scrub readout and an accessible data-table twin.
  • @firna/ui/data-grid for the editable Airtable/Notion-style data grid (cell-range selection, keyboard nav, virtualized infinite scroll, typed editable cells, column menus, and a responsive card stack).
  • @firna/ui/date for single-date and date-range fields.
  • @firna/ui/drag-select for rubber-band selection of rows and tiles: a provider that can wrap one list or every page of an app shell, the useDragSelectableOptions page hook, target and state hooks, controlled (selectedIds) or uncontrolled selection, a selection scope per page, configurable start rules and an ignore marker, edge auto-scroll, a custom box through renderMarquee, and geometry helpers. The gesture runs on web; native keeps the selection state.
  • @firna/ui/dropdown for dropdown menu, selector, combobox, layer helpers, and selector trigger refs for imperative focus after async form hydration.
  • @firna/ui/empty-state for page and panel empty states with a heading level supplied by the caller.
  • @firna/ui/heatmap for the calendar contribution heatmap and its pure layout and color-scale helpers.
  • @firna/ui/input for the labelled text input, textarea, and bare input frame.
  • @firna/ui/kanban for the horizontally scrolling status board that groups records into columns by a single-select field.
  • @firna/ui/link for link buttons and link tabs with destinations and current-page state.
  • @firna/ui/list for the vertical list with between-item separators, optional clickable items, link navigation rows, and the ListItem row.
  • @firna/ui/loader for the loading indicator family: Loader with six interchangeable indeterminate shapes (ring, dot-grid, dots, bars, blades, pulse), plus ProgressBar and ProgressRing for work whose total is known.
  • @firna/ui/modal for the shared dialog frame with automatic web stacking and native modal presentation, plus the public portal, model, and layer helpers.
  • @firna/ui/notice for neutral and urgent notices with body and action slots.
  • @firna/ui/panel-resize for the controlled panel resize handle.
  • @firna/ui/popover for anchored popovers, in-place menus, and phone menu sheets.
  • @firna/ui/radio for themed titled radio-option cards.
  • @firna/ui/rich-text for the Notion-style block editor with markdown in/out, inline formatting, lists/checklists, native keyboard toolbars, and the collaboration layer (live carets, tracked changes, comment threads) with its RichTextPresenceBar and RichTextCollabRail surfaces.
  • @firna/ui/segmented for themed single-select segmented controls.
  • @firna/ui/sheet for the modal bottom sheet that hosts a form, a menu list, or a picker behind one controlled API.
  • @firna/ui/skeleton for content-shaped loading placeholders: a shimmering bar and circle, a row and column group, and the pulse provider that sweeps a whole skeleton off one animation.
  • @firna/ui/sortable-list for the drag-and-drop sortable list (pointer + keyboard reordering, an optional start/end grab handle, and vertical or horizontal flow), plus the SortableGroups coordinator that lets several lists exchange items — stacked as sections or laid out as a board — reporting each move with its source and destination group.
  • @firna/ui/spinner for the themed indeterminate spinning loading indicator.
  • @firna/ui/status-dot for the small themed status dot that signals state beside a label and can pulse while the state is live.
  • @firna/ui/switch for themed binary on/off switches.
  • @firna/ui/table for the data table with optional headers and clickable rows.
  • @firna/ui/theme for SharedUiThemeProvider, default accounting-style tokens, the Juno token preset, the darkSharedUiTheme and junoDarkSharedUiTheme dark presets, the SharedUiScheme type, createSharedUiTheme(overrides, base), and the theme-wide focusIndicator (SharedUiThemeProvider theme={{ focusIndicator: "outline" }} swaps every control's focus glow for the browser outline at once). See Theming for the dark-mode contract and Focus indicators for the focus modes.
  • @firna/ui/focusRing for useFocusRing, focusRingStyleFor, focusRingCssVariablesFor, and focusRingDomPropsFor. See the focus indicators guide for custom controls.
  • @firna/ui/timeline for the multi-track editing timeline: the ruler, lanes, clips, and playhead of a video or audio editor.
  • @firna/ui/toast for the toast provider, the useToast hook, the toastController method API, and transient notification toasts including card and solid variants with optional custom leading icons.
  • @firna/ui/touch-surface for TouchSurface and useTouchSurface, which mark and read surfaces with 44px control targets.
  • @firna/ui/typography for text roles, TextScaleProvider, useTextScale, and the per-text scale override.
  • @firna/ui/video-editor for the video-editor panels around the timeline: program monitor, transport, level meter, media bin, property inspector, effects rack, keyframe editor, and export dialog.
  • @firna/ui/workflow for the branching workflow builder — a step-graph canvas (color-coded nodes, tinted edge labels, forks, legend, add-step) for constructing automation workflows.

Installation

npm install @firna/ui

All platform packages are optional peer dependencies; install the set for your target:

  • Web only (Vite, Next.js, any DOM bundler): react, react-dom, and lucide-react — that is the whole web peer set. No react-native and no react-native-web install, and no bundler alias is needed: the import condition resolves to dist/node, where every primitive renders through the library's own DOM backend. That holds for types too — the web build's declarations are self-contained, so even a strict TypeScript consumer installs nothing extra.
  • Expo / React Native (iOS, Android, and Expo web): react, react-dom, react-native, react-native-svg, lucide-react-native, and lucide-react. Metro's react-native condition resolves dist/**, where platform files pick native or web implementations per file. An Expo web app keeps whatever react-native-web its own React Native code needs; the library's .web files resolve to the DOM backend there too and never reach for it.
  • Optional on native: @gorhom/bottom-sheet, react-native-gesture-handler, and react-native-reanimated power the native bottom sheet.

Every component reaches the platform through src/primitives, a small set of modules with a native file and a .web sibling: React Native primitives (react-native on native; the library's own DOM backend on web), SVG (react-native-svg on native, DOM <svg> on web), and icons (lucide-react-native on native, lucide-react on web). Icon props accept IconComponent, a type both Lucide packages' icons satisfy, so a consumer passes whichever matches their platform.

Theming

See the theming guide.

Focus indicators

See the focus indicators guide.

Web focus CSS and server rendering

See the focus indicators guide.

Chart colors

See the theming guide.

Developer Get Started

npm ci
npm test
npm run typecheck
npm run typecheck:web
npm run build
npm run test:dist
npm run test:package
npm run storybook
npm run storybook:build
npm run test:browser

The development guide explains each check, the complete cargo xtask check gate, the AI review wrapper, the mockup catalogue, the browser and snapshot suites, and the package export map.

Package Releases

See the releases and deployments guide.

Storybook Deployments

See the releases and deployments guide.

Key Code Jumping Points

  • Accounting consumer/source components: /Users/calummoore/projects/futex/accounting
  • Juno consumer: /Users/calummoore/projects/futex/juno

版本与发布记录

@firna/ui 共发布 38 个版本,首次发布于 2026/06/15;过去 12 个月发布了 38 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
5.1.0latest2026/11/086 天前
5.0.02026/11/087 天前
4.0.02026/10/011 个月前
3.1.12026/09/271 个月前
3.1.02026/09/181 个月前
3.0.02026/09/052 个月前

关于 @firna/ui 的常见问题

@firna/ui 是什么?

Shared React Native and web UI primitives for Firna apps.

如何安装 @firna/ui?

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

@firna/ui 支持 TypeScript 吗?

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

@firna/ui 支持 ESM 还是 CommonJS?

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

@firna/ui 可以商用吗?

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

@firna/ui 的下载量有多少?

根据 npm 官方下载统计,@firna/ui 在 2026/10/15 – 2026/11/13 这 30 天内被下载 3,758 次,日均约 125 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@firna/ui 还在维护吗?

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