Design system.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

103 satır
2.6 KiB

  1. import * as React from 'react';
  2. import clsx from 'clsx';
  3. import Color from 'color';
  4. import * as convert from 'color-convert';
  5. /**
  6. * Derived HTML element of the {@link Swatch} component.
  7. */
  8. export type SwatchDerivedElement = HTMLInputElement;
  9. type ColorValue = ConstructorParameters<typeof Color>[0];
  10. type ColorMode = keyof typeof convert;
  11. /**
  12. * Props of the {@link Swatch} component.
  13. */
  14. export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
  15. color: NonNullable<ColorValue>;
  16. mode?: ColorMode;
  17. }
  18. export const useSwatchControls = () => {
  19. const id = React.useId();
  20. const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => {
  21. const { value } = e.currentTarget;
  22. await window.navigator.clipboard.writeText(value);
  23. }, []);
  24. return React.useMemo(() => ({
  25. id,
  26. copyColor,
  27. }), [id, copyColor]);
  28. };
  29. /**
  30. * Component for displaying a color.
  31. */
  32. export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
  33. // todo unify color and mode into one "value" attribute
  34. color,
  35. mode = 'rgb',
  36. className,
  37. style,
  38. ...etcProps
  39. }, forwardedRef) => {
  40. const { id, copyColor } = useSwatchControls();
  41. const colorInternal = React.useMemo(() => new Color(color, mode), [color, mode]);
  42. const colorValue = colorInternal.hex();
  43. return (
  44. <span
  45. className={clsx(
  46. 'inline-block align-middle',
  47. className,
  48. )}
  49. style={style}
  50. >
  51. <input
  52. {...etcProps}
  53. ref={forwardedRef}
  54. type="text"
  55. value={colorInternal.toString()}
  56. className="sr-only select-all peer"
  57. readOnly
  58. id={id}
  59. onSelect={copyColor}
  60. />
  61. <label
  62. className={clsx(
  63. 'relative rounded ring-secondary/50 whitespace-nowrap inline-block align-top leading-none cursor-pointer', // todo eyedropper cursor
  64. 'peer-focus:outline-0 peer-focus:ring-4',
  65. 'peer-active:ring-tertiary/50',
  66. 'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed',
  67. )}
  68. title={colorValue}
  69. htmlFor={id}
  70. >
  71. {/* todo border primary */}
  72. <span
  73. className="inline-block w-5 h-5 align-middle border border-[#ffffff]"
  74. >
  75. <span
  76. className="block w-full h-full border border-[#000000]"
  77. style={{
  78. backgroundColor: colorInternal.hex(),
  79. }}
  80. />
  81. </span>
  82. <span className="tabular-nums text-xs sr-only">
  83. {colorInternal.toString()}
  84. </span>
  85. </label>
  86. </span>
  87. );
  88. });
  89. Swatch.displayName = 'Swatch';
  90. Swatch.defaultProps = {
  91. mode: 'rgb',
  92. };