npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@avament-pub/color-picker

v0.2.0

Published

Shared HEX color picker for Avament React apps

Readme

@avament-pub/color-picker

Portable HEX color picker for React apps — panel, popover trigger, or sync field. No i18n or app APIs inside; pass labels and handle onSave / onChange in the host.

| | | |---|---| | Package | @avament-pub/color-picker | | React | ≥ 18 (peer) | | Dependencies | react-colorful, lucide-react | | License | MIT |


Table of contents

  1. Install
  2. What you get
  3. Minimal usage
  4. Popover with custom trigger
  5. Embed the panel
  6. Props API
  7. Utilities
  8. Exports
  9. Localization
  10. Use inside Select
  11. Troubleshooting

1. Install

npm install @avament-pub/color-picker
yarn add @avament-pub/color-picker
pnpm add @avament-pub/color-picker

Requirements

  • React 18+ / React DOM 18+
  • Client component in Next.js App Router ("use client")

The package is self-contained (inline styles + CSS variables). No host Tailwind, no surface-theme / border-theme required.

Optional Next.js:

transpilePackages: ["@avament-pub/color-picker"];

2. What you get

| Component | Role | |---|---| | ColorPickerPopover | Trigger + popover; draft until Save / Cancel | | ColorPickerField | Like popover, but onChange is sync (local draft / forms) | | ColorPickerPanel | Controlled panel only (embed in your dialog/popover) | | ColorSwatch | Small color chip for lists / labels | | useColorPicker | Draft / save / cancel state hook |

Normalized save value is #rrggbb (lowercase).


3. Minimal usage

Popover (persist on Save)

"use client";

import { useState } from "react";
import { ColorPickerPopover } from "@avament-pub/color-picker";

export function CategoryColor({ initial }: { initial: string }) {
  const [color, setColor] = useState(initial);

  return (
    <ColorPickerPopover
      color={color}
      onSave={async (next) => {
        await fetch(`/api/color`, {
          method: "PATCH",
          body: JSON.stringify({ color: next }),
        });
        setColor(next);
      }}
    />
  );
}

Field (immediate / form draft)

"use client";

import { ColorPickerField } from "@avament-pub/color-picker";

export function ColorField({
  value,
  onChange,
}: {
  value: string;
  onChange: (color: string) => void;
}) {
  return <ColorPickerField value={value} onChange={onChange} />;
}

Swatch only

import { ColorSwatch } from "@avament-pub/color-picker";

<ColorSwatch color="#2b60e6" />

4. Popover with custom trigger

<ColorPickerPopover
  color={color}
  onSave={setColor}
  renderTrigger={({ open, color, togglePicker, labels }) => (
    <button type="button" onClick={togglePicker} aria-label={labels.editAriaLabel}>
      <span
        style={{
          display: "inline-block",
          width: 16,
          height: 16,
          borderRadius: 4,
          background: color,
        }}
      />
      {open ? "Close" : "Pick color"}
    </button>
  )}
/>

5. Embed the panel

"use client";

import { useState } from "react";
import { ColorPickerPanel, useColorPicker } from "@avament-pub/color-picker";

export function InlinePicker({
  color,
  onSave,
  onClose,
}: {
  color: string;
  onSave: (c: string) => Promise<void>;
  onClose: () => void;
}) {
  const {
    draft,
    draftValid,
    pending,
    handleDraftChange,
    handleCancel,
    handleSave,
  } = useColorPicker({
    color,
    open: true,
    onSave,
    onClose,
  });

  return (
    <ColorPickerPanel
      color={draft}
      onChange={handleDraftChange}
      onCancel={handleCancel}
      onSave={handleSave}
      saving={pending}
      disabled={!draftValid}
    />
  );
}

6. Props API

ColorPickerPopover

| Prop | Type | Description | |---|---|---| | color | string | Current saved color | | onSave | (color: string) => void \| Promise<void> | Called with #rrggbb on Save | | disabled | boolean | | | renderTrigger | (props) => ReactNode | Custom trigger | | labels | ColorPickerLabels | Button / a11y strings | | onOpenChange | (open: boolean) => void | Notify host (e.g. keep Select open) | | side | "top" \| "right" \| "bottom" \| "left" | Popover placement (default "left") | | align | "start" \| "center" \| "end" | | | zIndexClassName | string | Default z-[200] | | className / triggerClassName | string | |

Dismiss: Save, Cancel, outside click, or Escape (discards unsaved draft).

ColorPickerField

Same placement / trigger / labels props as popover, but:

| Prop | Type | |---|---| | value | string | | onChange | (color: string) => void | Sync when user saves in the field flow |

ColorPickerPanel

| Prop | Type | |---|---| | color | string | Draft hex | | onChange | (color: string) => void | | onCancel / onSave | () => void \| Promise<void> | | disabled / saving | boolean | | labels | ColorPickerLabels |

ColorPickerLabels

| Key | Default idea | |---|---| | editAriaLabel | Change color | | pickerAriaLabel | Pick a color | | hexLabel | HEX | | cancelLabel | Cancel | | saveLabel | Save |


7. Utilities

import {
  COLOR_PICKER_DEFAULT_HEX,
  ensureHexPrefix,
  hexColorForPicker,
  isValidHexColor,
  normalizeHexColor,
} from "@avament-pub/color-picker";

normalizeHexColor("#ABC");     // "#aabbcc" or null
isValidHexColor("#2b60e6");  // true
ensureHexPrefix("2b60e6");   // "#2b60e6"

8. Exports

import {
  ColorPickerPopover,
  ColorPickerField,
  ColorPickerPanel,
  ColorSwatch,
  useColorPicker,
  normalizeHexColor,
  isValidHexColor,
  ensureHexPrefix,
  hexColorForPicker,
  COLOR_PICKER_DEFAULT_HEX,
} from "@avament-pub/color-picker";

9. Localization

<ColorPickerPopover
  color={color}
  onSave={onSave}
  labels={{
    editAriaLabel: "Farbe ändern",
    cancelLabel: "Abbrechen",
    saveLabel: "Speichern",
    hexLabel: "HEX",
  }}
/>

10. Use inside Select

When the picker opens from a Select row action, keep the Select open:

<ColorPickerPopover
  color={optionColor}
  onSave={saveColor}
  onOpenChange={(open) => {
    // host: prevent Select from closing while open === true
  }}
/>

11. Troubleshooting

| Issue | Fix | |---|---| | Trigger looks wrong | Override --ava-cp-* CSS vars, or use renderTrigger | | Invalid save | Only valid hex enables Save; use normalizeHexColor | | Popover behind modal | Raise zIndex (e.g. 400) | | Select closes when picking | Wire onOpenChange and ignore outside-click while open | | Next.js SSR | "use client" on the consumer |


Versioning & publish

Bump package.json version before republishing README-only updates.