@nuttawoot_donut/react-ripple
v2.0.8
Published
Ripple effects with automatic dark/light theme detection (based on material-ripple-effects)
Maintainers
Readme
@nuttawoot_donut/react-ripple
Material-style ripple ที่ตรวจจับโหมด Dark/Light อัตโนมัติ และรองรับการ กำหนดสี/ความโปร่งใสเอง ใช้ได้กับ React/Next.js (Client Component) และเว็บทั่วไป
npm i @nuttawoot_donut/react-rippleคุณสมบัติ
- โหมด อัตโนมัติ เลือกสี ripple ตามธีมระบบ: Dark จะเป็นขาวโปร่ง, Light จะเป็นดำโปร่ง
- Override ได้: บังคับโหมด
"dark"|"light"หรือกำหนดcolorเองแบบ#hex/rgba() - เคารพ
prefers-reduced-motionลดแอนิเมชันสำหรับผู้ใช้ที่ตั้งค่าลดการเคลื่อนไหว - ไม่ต้องพึ่ง CSS ภายนอก สร้าง
<span>และลบหลังจบแอนิเมชันอัตโนมัติ
ติดตั้ง
npm i @nuttawoot_donut/react-ripple
# หรือ
pnpm add @nuttawoot_donut/react-rippleการใช้งาน (JavaScript)
ใช้ใน Client Component เท่านั้น
import React from "react";
import Ripple from "@nuttawoot_donut/react-ripple";
export default function DemoButtons() {
const ripple = new Ripple();
return (
<div style={{ display: "flex", gap: 12 }}>
{/* โหมดอัตโนมัติ (auto) ตามธีม */}
<button onPointerDown={(e) => ripple.create(e)}>
Auto Ripple
</button>
{/* บังคับโหมด */}
<button onPointerDown={(e) => ripple.create(e, "light")}>
Light Ripple
</button>
<button onPointerDown={(e) => ripple.create(e, "dark")}>
Dark Ripple
</button>
{/* ระบุสีเอง + alpha */}
<button
onPointerDown={(e) =>
ripple.create(e, { color: "#046838", alpha: 0.18 })
}
>
Custom Color
</button>
</div>
);
}หมายเหตุ: ถ้า host element เป็น
position: staticไลบรารีจะตั้งเป็นposition: relativeให้เองเพื่อวาด ripple ให้เต็มกรอบ
การใช้งานกับ TypeScript
แพ็กเกจนี้มีไฟล์ประกาศประเภท (index.d.ts) มาให้แล้ว
import Ripple, { RippleOptions } from "@nuttawoot_donut/react-ripple";
const ripple = new Ripple();
function Btn() {
const opts: RippleOptions = { color: "#046838", alpha: 0.18 };
return (
<button
onPointerDown={(e) => ripple.create(e, opts)}
onKeyDown={(e) => ripple.create(e, "dark")}
>
Click
</button>
);
}API
new Ripple()
สร้างอินสแตนซ์สำหรับใช้ซ้ำในหลายองค์ประกอบ
ripple.create(event, opts?)
สร้าง ripple จากอีเวนต์ของเมาส์ ทัช หรือคีย์บอร์ด
- event: อีเวนต์จาก React เช่น
onPointerDown,onClick,onTouchStart, หรือonKeyDown - opts:
"dark"|"light"บังคับโหมดแบบสั้น{ mode?: "dark"|"light", alpha?: number, color?: string }modeบังคับโหมดalphaความโปร่งใส 0..1 (ถ้าไม่กำหนดใช้ค่าจาก CONFIG)colorกำหนดสีทันที รองรับ#hex,#rrggbbaa,rgb(),rgba()
ตัวอย่าง:
ripple.create(e); // auto (ดูจากธีม)
ripple.create(e, "dark"); // บังคับ dark
ripple.create(e, { alpha: 0.28 }); // auto + ปรับความโปร่งใส
ripple.create(e, { color: "rgba(4,104,56,0.18)" }); // กำหนดสีเองการตั้งค่าแบบ Global (Static CONFIG)
ตั้งค่าเริ่มต้นให้ ripple ทั้งแอปด้วย Ripple.CONFIG ก่อนสร้างอินสแตนซ์
import Ripple from "@nuttawoot_donut/react-ripple";
Ripple.CONFIG = {
COLOR: "auto", // หรือ "#046838" / "rgba(4,104,56,0.18)"
ALPHA: 0.20, // โปร่งใสเริ่มต้น
VELOCITY: 0.6, // ความเร็วการขยาย
MIN_GROW: 260, // เวลาขยายขั้นต่ำ (ms)
MAX_GROW: 560, // เวลาขยายขั้นสูง (ms)
FADE_OUT: 200, // เวลาเฟดออก (ms)
BLEED_PX: 4 // เผื่อรัศมีออกนอกขอบเล็กน้อย
};
const ripple = new Ripple();ลำดับการเลือกสี:
- มี
opts.color→ ใช้ค่านั้น- ไม่งั้นถ้า
CONFIG.COLORไม่ใช่"auto"→ ใช้ค่านั้น- ไม่งั้นใช้ auto: ขาวโปร่งใน Dark, ดำโปร่งใน Light
การตรวจจับธีม
- ถ้า
document.documentElementมีคลาส"dark"จะถือเป็นโหมดมืด - ถ้า ancestor ใกล้สุดมี
data-theme="dark"จะถือเป็นโหมดมืด - ถ้าไม่พบทั้งสอง จะ fallback ไป
prefers-color-scheme: dark
รูปแบบสีที่รองรับ
คุณสามารถส่ง color ได้หลายแบบ ไม่ได้จำกัดแค่ rgba():
#RGB/#RGBA(เช่น#0a3หรือ#0a3f)#RRGGBB/#RRGGBBAA(เช่น#046838หรือ#0468382Eที่มี alpha ในตัว)rgb()/rgba()(เช่นrgba(4,104,56,0.18))- ชื่อสีที่เบราว์เซอร์รู้จัก (เช่น
green) ก็ใช้ได้ แต่ จะไม่ผสมความโปร่งใสให้เอง
หลักการเลือก alpha:
- ถ้า
colorเป็น#RRGGBBAAจะใช้ alpha จากค่านี้ทันที - ถ้า
colorเป็น#RGB/#RRGGBBให้กำหนดalphaแยกผ่านopts.alpha(ถ้าไม่ใส่จะ fallback ไปที่Ripple.CONFIG.ALPHA) - ถ้าให้
rgba()ก็ใช้ตามนั้นตรงๆ
ตัวอย่าง:
// ใช้ hex + alpha แยก
ripple.create(e, { color: "#046838", alpha: 0.18 });
// ใช้ hex 8 หลักที่มี alpha ในตัว
ripple.create(e, { color: "#0468382E" });
// ใช้ rgba ตรงๆ
ripple.create(e, { color: "rgba(4,104,56,0.18)" });การใช้งานแบบ CDN (Vanilla)
ไฟล์ build มี ripple.js ที่ expose window.Ripple
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="min-h-screen flex items-center justify-center gap-4">
<button class="rounded-lg shadow px-4 py-2 bg-neutral-300 cursor-pointer" id="btn-light">btn-light</button>
<button class="rounded-lg shadow px-4 py-2 bg-neutral-800 cursor-pointer text-white" id="btn-dark">btn-dark</button>
<button class="rounded-lg shadow px-4 py-2 bg-emerald-500 cursor-pointer text-white" id="btn-green">btn-green</button>
</div>
<script type="module">
import Ripple from "https://unpkg.com/@nuttawoot_donut/react-ripple/ripple.js"
const ripple = new window.Ripple();
const btnLight = document.getElementById("btn-light");
const btnDark = document.getElementById("btn-dark");
const btnGreen = document.getElementById("btn-green");
btnLight.addEventListener("pointerdown", e => ripple.create(e, "light"));
btnDark.addEventListener("pointerdown", e => ripple.create(e, "dark"));
btnGreen.addEventListener("pointerdown", e => ripple.create(e, { color: "#004f3b", alpha: 0.18 }));
</script>เวอร์ชันนี้ใช้การเรียก
create(e, opts)แทน data-attributes
SSR / Next.js
- ไลบรารีเช็ค DOM ก่อนเสมอ จึง no-op บน SSR และทำงานฝั่ง Client เท่านั้น
- ไม่กระทบ hydration เพราะสร้าง/ลบ DOM เพื่อแอนิเมชันเฉพาะฝั่ง client
Accessibility
- รองรับ
keydownบน Space/Enter เพื่อการเข้าถึงด้วยคีย์บอร์ด - เคารพ
prefers-reduced-motionลดแอนิเมชันอัตโนมัติ
ข้อควรทราบ
- ไลบรารีจะสร้าง
<span>ลงใน host แล้วลบทิ้งหลังแอนิเมชันจบ - ถ้าสีเป็นดำโปร่ง จะตั้ง
mix-blend-mode: multiplyเพื่อให้ดูกลืนกับพื้นสว่าง
License
MIT
Credits
ดัดแปลงจาก material-ripple-effects เพิ่ม auto Dark/Light, custom color/alpha และปรับแอนิเมชัน/พฤติกรรมให้เข้ากับแอปยุคปัจจุบัน
