|
- import * as React from 'react';
- import Color from 'color';
- import * as convert from 'color-convert';
- import { tailwind } from '@tesseract-design/web-base';
-
- const { tw } = tailwind;
-
- const SwatchDerivedElementComponent = 'input' as const;
-
- /**
- * Derived HTML element of the {@link Swatch} component.
- */
- export type SwatchDerivedElement = HTMLElementTagNameMap[
- typeof SwatchDerivedElementComponent
- ];
-
- type ColorValue = ConstructorParameters<typeof Color>[0];
-
- type ColorMode = keyof typeof convert;
-
- /**
- * Props of the {@link Swatch} component.
- */
- export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
- color: NonNullable<ColorValue>;
- mode?: ColorMode;
- }
-
- export const useSwatchControls = () => {
- const id = React.useId();
- const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => {
- const { value } = e.currentTarget;
- await window.navigator.clipboard.writeText(value);
- }, []);
- return React.useMemo(() => ({
- id,
- copyColor,
- }), [id, copyColor]);
- };
-
- /**
- * Component for displaying a color.
- */
- export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
- // todo unify color and mode into one "value" attribute
- color,
- mode = 'rgb',
- className,
- style,
- ...etcProps
- }, forwardedRef) => {
- const { id, copyColor } = useSwatchControls();
- const colorInternal = React.useMemo(() => new Color(color, mode), [color, mode]);
-
- const colorValue = colorInternal.hex();
-
- return (
- <span
- className={tw(
- 'inline-block align-middle',
- className,
- )}
- style={style}
- >
- <SwatchDerivedElementComponent
- {...etcProps}
- ref={forwardedRef}
- type="text"
- value={colorInternal.toString()}
- className="sr-only select-all peer"
- readOnly
- id={id}
- onSelect={copyColor}
- />
- <label
- className={tw(
- 'relative rounded ring-secondary/50 whitespace-nowrap inline-block align-top leading-none cursor-pointer', // todo eyedropper cursor
- 'peer-focus:outline-0 peer-focus:ring-4',
- 'peer-active:ring-tertiary/50',
- 'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed',
- )}
- title={colorValue}
- htmlFor={id}
- >
- {/* todo border primary */}
- <span
- className="inline-block w-5 h-5 align-middle border border-[#ffffff]"
- >
- <span
- className="block w-full h-full border border-[#000000]"
- style={{
- backgroundColor: colorInternal.hex(),
- }}
- />
- </span>
- <span className="tabular-nums text-xs sr-only">
- {colorInternal.toString()}
- </span>
- </label>
- </span>
- );
- });
-
- Swatch.displayName = 'Swatch';
-
- Swatch.defaultProps = {
- mode: 'rgb',
- };
|