Chroma Panel

搜索文档

查找页面或章节

EN

App Router 和 Pages Router 都能直接配置,无需动态导入。

安装 chroma-panel,导入一次样式表,就可以在 Next.js 的任意一种路由中渲染它。服务端组件可以直接导入选择器。只有当你自己的组件用到状态或传入事件处理函数时,才需要加 "use client"

安装

npm install chroma-panel

不需要再装其他包。dependencies 是空的,reactreact-dom 是 peer 依赖,所以用的就是你应用里已有的那一份。

样式表

面板在 effect 中注入自己的样式表。这意味着在水合完成之前,服务端渲染出的标记是没有样式的。要避免这种闪烁,可以自己导入样式表,并关闭自动注入:

<ColorInput injectStyles={false} />

导入写在哪里取决于你用的路由,下面各节分别给出了写法。injectStyles={false} 只是不再写入 <style> 标签,无论哪种方式,CSS 都会进入你的包。如果你使用 Tailwind,请改为在 CSS 文件中导入样式表,并声明层级顺序,具体见使用 Tailwind 样式

配置页面

App Router

在根布局中导入一次样式表。布局仍然是服务端组件。

// app/layout.tsx
import "chroma-panel/style.css";
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

只要传入的每个 prop 都可以序列化,服务端组件就能直接渲染选择器:

// app/brand/page.tsx
import { ColorInput } from "chroma-panel";
 
export default function BrandPage() {
  return (
    <main>
      <h2>Brand color</h2>
      <ColorInput defaultValue="#3366cc" injectStyles={false} />
    </main>
  );
}

一旦由你自己保存颜色,这个文件就得是客户端组件。useStateonChange 处理函数都只能在客户端使用,所以要把它们放在你自己的 "use client" 文件里:

// app/brand/brand-picker.tsx
"use client";
 
import { useState } from "react";
import { ColorInput, type ColorChangeResult } from "chroma-panel";
 
export function BrandPicker() {
  const [color, setColor] = useState<string>("#3366cc");
 
  const handleChange = (result: ColorChangeResult): void => {
    setColor(result.hex);
  };
 
  return (
    <>
      <ColorInput value={color} onChange={handleChange} injectStyles={false} />
      <p style={{ color }}>{color}</p>
    </>
  );
}

这个文件之所以是客户端组件,是因为你的状态,而不是因为 chroma-panel。哪些 prop 由你管理、哪些由面板自己保存,见受控与非受控

Pages Router

Pages Router 没有服务端组件,所以任何地方都用不到 "use client"。Next.js 只允许在 pages/_app.tsx 中导入全局样式表,CSS 就放在这里:

// pages/_app.tsx
import type { AppProps } from "next/app";
 
import "chroma-panel/style.css";
 
export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

页面本身就是一个普通的 React 组件:

// pages/brand.tsx
import { useState } from "react";
import { ColorInput, type ColorChangeResult } from "chroma-panel";
 
export default function BrandPage() {
  const [color, setColor] = useState<string>("#3366cc");
 
  const handleChange = (result: ColorChangeResult): void => {
    setColor(result.hex);
  };
 
  return (
    <main>
      <ColorInput value={color} onChange={handleChange} injectStyles={false} />
    </main>
  );
}

哪里需要 "use client"

文件是否需要 "use client"
渲染选择器的服务端组件
useState 保存颜色的文件
传入 onChange 的文件
pages/ 下的任何文件不适用

这条规则针对的是你自己的代码。服务端组件无法跨越边界传递函数,所以只要有处理函数,就必须是客户端组件。

无需动态导入

你不需要 next/dynamic,也不需要 ssr: false。这个包在模块加载时不会读取 window。在服务端会跳过样式注入,但选中的颜色依然会以 CSS 自定义属性的形式写入标记。

你不需要 ssr: false

ssr: false 的动态导入包裹选择器,只会让它晚一个往返才出现。它原样就能在服务端正确渲染。

服务端渲染针对 Remix 和其他 SSR 方案讲了同样的内容;如果你想要比默认导入更小的包,入口列出了所有子路径。