Design system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

132 regels
3.4 KiB

  1. import * as React from 'react';
  2. import { tailwind } from '@tesseract-design/web-base';
  3. const { tw } = tailwind;
  4. const ColorPickerDerivedElementComponent = 'input' as const;
  5. /**
  6. * Derived HTML element of the {@link ColorPicker} component.
  7. */
  8. export type ColorPickerDerivedElement = HTMLElementTagNameMap[
  9. typeof ColorPickerDerivedElementComponent
  10. ];
  11. /**
  12. * Props of the {@link ColorPicker} component.
  13. */
  14. export interface ColorPickerProps extends Omit<React.HTMLProps<ColorPickerDerivedElement>, 'size' | 'type' | 'label'> {
  15. square?: boolean;
  16. size?: 'small' | 'medium' | 'large';
  17. }
  18. export const colorPickerPlugin: tailwind.PluginCreator = ({ addComponents }) => {
  19. addComponents({
  20. '.color-picker': {
  21. '&::-webkit-color-swatch-wrapper': {
  22. 'padding': '0',
  23. },
  24. '&::-webkit-color-swatch': {
  25. 'border': '0',
  26. },
  27. '&::-moz-color-swatch': {
  28. 'border': '0',
  29. },
  30. },
  31. });
  32. };
  33. /**
  34. * Component for picking a color.
  35. */
  36. export const ColorPicker = React.forwardRef<
  37. ColorPickerDerivedElement,
  38. ColorPickerProps
  39. >((
  40. {
  41. className,
  42. id: idProp,
  43. style,
  44. square = false as const,
  45. size = 'medium' as const,
  46. ...etcProps
  47. },
  48. forwardedRef,
  49. ) => (
  50. <div
  51. className={tw(
  52. 'inline-block align-center relative ring-secondary/50 rounded overflow-hidden box-border group has-[:disabled]:opacity-50',
  53. 'rounded focus-within:ring-4 active:ring-tertiary/50',
  54. {
  55. 'w-8': square && size === 'small',
  56. 'w-12': square && size === 'medium',
  57. 'w-16': square && size === 'large',
  58. },
  59. {
  60. 'w-16': !square && size === 'small',
  61. 'w-24': !square && size === 'medium',
  62. 'w-32': !square && size === 'large',
  63. },
  64. className,
  65. )}
  66. style={style}
  67. >
  68. <span
  69. className={tw(
  70. 'block w-full',
  71. {
  72. 'p-[25%]': square,
  73. 'p-[12.5%]': !square,
  74. },
  75. )}
  76. >
  77. <ColorPickerDerivedElementComponent
  78. {...etcProps}
  79. className={tw(
  80. 'color-picker absolute top-0 left-0 w-full h-full overflow-hidden cursor-pointer disabled:cursor-not-allowed',
  81. 'focus:outline-0',
  82. )}
  83. ref={forwardedRef}
  84. id={idProp}
  85. type="color"
  86. />
  87. </span>
  88. <span
  89. className={tw(
  90. 'border-y-4 border-l-4 border-r-2 absolute top-0 left-0 h-full pointer-events-none border-[#000000]',
  91. {
  92. 'w-1/2': square,
  93. 'w-3/4': !square,
  94. },
  95. )}
  96. />
  97. <span
  98. className={tw(
  99. 'absolute flex items-center justify-center top-0 right-0 h-full pointer-events-none bg-negative text-primary group-has-[:disabled]:text-primary group-active:text-tertiary group-focus-within:text-secondary',
  100. {
  101. 'w-1/2': square,
  102. 'w-1/4': !square,
  103. },
  104. )}
  105. >
  106. <svg
  107. className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round"
  108. viewBox="0 0 24 24"
  109. role="presentation"
  110. >
  111. <polyline points="6 9 12 15 18 9" />
  112. </svg>
  113. </span>
  114. <span
  115. className="border-2 absolute top-0 left-0 w-full h-full pointer-events-none border-primary group-active:border-tertiary group-has-[:disabled]:border-primary group-focus-within:border-secondary"
  116. />
  117. </div>
  118. ));
  119. ColorPicker.displayName = 'ColorPicker';
  120. ColorPicker.defaultProps = {
  121. square: false as const,
  122. size: 'medium' as const,
  123. };