Codync
免費、開源的 1:1 替代方案,取代 Grok Bot 與 Muse。從 iPhone、Mac 或 Linux 桌面將 Claude Code、Codex、Cursor 與 40+ 程式碼代理人作為持續機器人傳訊。群組聊天、主題串…
AI 翻譯
A comprehensive themeable React component library
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A complete, themeable React component library, built with Panda CSS.
Documentation — components with live examples and API reference.
Storybook — browse and interact with all components.
npm install silver-ui
# or
pnpm add silver-ui
# or
yarn add silver-ui
silver-ui requires React 19+ as a peer dependency, and the Temporal API (see Temporal below).
silver-ui's date and time components use the
Temporal API.
silver-ui does not bundle a polyfill: it uses the global Temporal, which is
built into Chrome/Edge (144+) and Firefox (139+). Where it is missing — Safari
(including every browser on iOS), and Node — your app installs
@js-temporal/polyfill
as the global. Rendering a silver-ui component that needs Temporal without one
throws an error pointing here.
1. Add the polyfill:
npm install @js-temporal/polyfill
2. Create a module that installs it only when needed. Browsers with native Temporal skip the download entirely; elsewhere the polyfill loads as a separate chunk.
// src/temporal.ts
if (!('Temporal' in globalThis)) {
const polyfill = await import('@js-temporal/polyfill');
Object.assign(globalThis, {Temporal: polyfill.Temporal});
// Lets Intl.DateTimeFormat#format accept the polyfill's Temporal objects.
Object.assign(Intl, {DateTimeFormat: polyfill.Intl.DateTimeFormat});
}
export {};
3. Import it in the entry file that renders your app:
// src/main.tsx
import './temporal';
import {createRoot} from 'react-dom/client';
import App from './App';
createRoot(document.getElementById('root')!).render(<App />);
How the await makes this safe: a module with a top-level await delays
every module that imports it, so main.tsx's own code — and therefore the
first render — runs only once the polyfill is installed. silver-ui reads
Temporal when components render, never at import time, so nothing else is
needed for silver-ui itself.
Note that sibling imports are not delayed: in the example above, App's
module code may run before the polyfill is installed. If one of your own
modules uses Temporal at its top level (outside any function or component),
add import './temporal'; to that module too.
4. TypeScript: silver-ui's types use the global Temporal types that
ship with TypeScript 6. Add them to lib in your tsconfig.json:
{
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022", "ESNext.Temporal"]
}
}
Leave out ESNext.Intl: its Temporal-aware Intl.DateTimeFormat types
conflict with the polyfill's own declarations unless skipLibCheck is on.
Top-level await needs an ES2022 module target, which Vite and other modern
bundlers support by default. If your package.json declares "sideEffects",
list src/temporal.ts there too, or bundlers will drop the side-effect-only
import './temporal'. Once every browser you support ships Temporal,
delete src/temporal.ts and its imports.
Import the stylesheet once in your app's entry point, then use components:
import 'silver-ui/styles.css';
import {Button, Card, Heading, Text} from 'silver-ui';
function App() {
return (
<Card padding={4}>
<Heading level={2}>Welcome back</Heading>
<Text>Your project is ready to deploy.</Text>
<Button
label="Deploy"
onClick={() => console.log('Deploying…')}
size="md"
variant="primary"
/>
</Card>
);
}
For smaller JS bundles, import component subpaths:
import 'silver-ui/styles.css';
import {Button} from 'silver-ui/Button';
import {SideNav, SideNavItem} from 'silver-ui/SideNav';
The easiest way to theme silver-ui is the <Theme> component. It maps friendly
token names to the underlying CSS variables and applies them app-wide or to a
scoped subtree. Wrap your app (or any branded area) and override the tokens you
care about:
import {Button, Theme} from 'silver-ui';
export function App() {
return (
<Theme
mode="light"
tokens={{
colors: {
primary: 'teal-500',
primaryHover: 'teal-600',
primaryActive: 'teal-700',
},
radii: {componentMd: '0.5rem'},
fonts: {body: 'Inter, system-ui, sans-serif'},
}}>
<Button label="Save" />
</Theme>
);
}
Palette references (teal-500) and custom CSS values (#e11d48, oklch(...),
var(...)) are both supported, and multiple <Theme> regions can coexist on
one page.
Prefer plain CSS? Every component is driven by --silver-* variables, so you
can override them directly. All library styles use CSS @layer, so your
overrides always win without specificity battles.
:root {
--silver-colors-primary: #e11d48;
--silver-colors-primary-hover: #be123c;
--silver-colors-primary-active: #9f1239;
--silver-radii-component-md: 0.5rem;
--silver-fonts-body: Inter, system-ui, sans-serif;
}
Variables can be scoped to containers, dark mode ([data-theme="dark"]), or
individual instances via className/style props.
See THEME.md for the full <Theme> API, variable reference, dark
mode details, scoped theming examples, and per-instance overrides.
The primitives silver-ui's own components are built on are published from
silver-ui/hooks, so you can build custom widgets that behave the same way.
import {
useAnnounce,
useClipboard,
useHotkey,
useListFocus,
useMergeRefs,
useTypeahead,
} from 'silver-ui/hooks';
announce(message, politeness?) functionHome/End, wrapping, RTL)useHotkey(keys, handler, options?) accepts one case-insensitive descriptor
such as f6, shift+k, or mod+k. Separate tokens with +; supported
modifiers are mod, ctrl, alt, and shift, and the special-key vocabulary
matches Kbd: enter, backspace, escape, tab, up, down, left,
right, and plus. mod resolves to Command on Apple platforms and Control
elsewhere.
The listener targets document by default; pass target: 'window' or a React
ref to listen elsewhere. It is enabled by default and does not call
preventDefault() unless hasPreventDefault: true is set. Composition events
are always ignored, and shortcuts do not fire from inputs, selects, textareas,
editable content, or textbox roles unless isEnabledOnFormElements: true is
set. Sequences and priority
arbitration between duplicate registrations are not supported.
Relay EntryPoint-backed controllers for Drawer, Dialog, Popover, and HoverCard
are available from the opt-in silver-ui/relay entry. Relay is an optional peer
dependency, so applications that do not import this entry do not need to
install it.
pnpm add react-relay relay-runtime
import {createJSResourceReference, usePreloadedDrawer} from 'silver-ui/relay';
The controllers own EntryPoint loading, retry, visibility, and reference
lifetime. Use preload(params) for pointer or focus intent, show(params, runtimeProps) to open the surface, and render the returned element alongside
the trigger. The application remains responsible for its Relay environment,
compiler, generated artifacts, and EntryPoint definitions.
usePreloadedDrawer and usePreloadedDialog accept onBeforeHide, which is
called once, synchronously, whenever the user tries to close the surface
(Escape, a backdrop click, or the LayoutHeader close button). Its return
value can veto the hide: return false to keep the surface open, for example
to confirm discarding unsaved changes. hide() and the EntryPoint's close
prop always close without calling it.
const drawer = usePreloadedDrawer(requestEntryPoint, {
label: 'Request credentialing',
onBeforeHide: () =>
!hasUnsavedChanges() || window.confirm('Leave without submitting?'),
});
See CONTRIBUTING.md for setup, development scripts, and component contribution guidelines.
MIT