| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- import React, { useMemo } from 'react';
- import {
- parseStops,
- buildFilamentBackground,
- type FilamentEffect,
- type SwatchType,
- } from './filamentSwatchHelpers';
- /** Shared filament-colour swatch. See `filamentSwatchHelpers.ts` for the
- * pure helpers + constants this component composes. */
- export interface FilamentSwatchProps {
- /** RRGGBBAA hex without `#` (Bambu/AMS canonical). Falls back to grey when null. */
- rgba?: string | null;
- /** Comma-separated 6/8-char hex tokens (no `#`). Empty/undefined → solid. */
- extraColors?: string | null;
- /** Visual effect overlay. */
- effectType?: FilamentEffect | string | null;
- /** When `Multicolor`, a conic gradient is used instead of linear. */
- subtype?: string | null;
- /** Tailwind size token applied to width/height (e.g. `w-5 h-5`). Default: `w-5 h-5`. */
- className?: string;
- /** Override the rounded shape — defaults to `rounded-full` (circular). */
- shape?: 'circle' | 'pill' | 'square';
- /** Optional inline style overrides (e.g. height of a card banner). */
- style?: React.CSSProperties;
- /** Native title attribute for hover tooltip. */
- title?: string;
- /** Tune effect appearance based on target div size. */
- effectSize: SwatchType;
- }
- export function FilamentSwatch({
- rgba,
- extraColors,
- effectType,
- subtype,
- className = 'w-5 h-5',
- shape = 'circle',
- style,
- title,
- effectSize,
- }: FilamentSwatchProps) {
- const stops = useMemo(() => parseStops(extraColors), [extraColors]);
- const filamentBackground = useMemo(
- () => buildFilamentBackground({ effectSize, rgba, extraColors, effectType, subtype }),
- [effectSize, rgba, extraColors, effectType, subtype]
- );
- const backgroundImage = filamentBackground.backgroundImage;
- const backgroundSize = filamentBackground.backgroundSize;
- const shapeClass =
- shape === 'circle' ? 'rounded-full' : shape === 'pill' ? 'rounded-full' : 'rounded';
- // Compute a sensible title fallback — solid hex or gradient summary.
- // Show the full 8-char rgba when alpha < FF so the tooltip on a Clear /
- // translucent spool reflects what's actually painted (#1545).
- const titleHex = (() => {
- if (!rgba) return undefined;
- const clean = rgba.replace(/^#/, '');
- if (clean.length >= 8 && clean.substring(6, 8).toLowerCase() !== 'ff') {
- return `#${clean.substring(0, 8)}`;
- }
- return `#${clean.substring(0, 6)}`;
- })();
- const computedTitle =
- title ??
- (stops.length > 0
- ? stops.join(', ')
- : titleHex);
- return (
- <span
- data-testid="filament-swatch"
- className={`${className} ${shapeClass} border border-black/20 inline-block flex-shrink-0`}
- style={{ backgroundImage, backgroundSize, ...style }}
- title={computedTitle}
- />
- );
- }
- export default FilamentSwatch;
|