ColorPicker.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React from "react";
  2. import { Popover } from "./Popover";
  3. import "./ColorPicker.css";
  4. // This is a narrow reimplementation of the awesome react-color Twitter component
  5. // https://github.com/casesandberg/react-color/blob/master/src/components/twitter/Twitter.js
  6. const Picker = function({
  7. colors,
  8. color,
  9. onChange
  10. }: {
  11. colors: string[];
  12. color: string | undefined;
  13. onChange: (color: string) => void;
  14. }) {
  15. const [innerValue, setInnerValue] = React.useState(color);
  16. React.useEffect(() => {
  17. setInnerValue(color);
  18. }, [color]);
  19. return (
  20. <div className="color-picker">
  21. <div className="color-picker-triangle-shadow"></div>
  22. <div className="color-picker-triangle"></div>
  23. <div className="color-picker-content">
  24. {colors.map(color => (
  25. <div
  26. className="color-picker-swatch"
  27. onClick={() => {
  28. onChange(color);
  29. }}
  30. title={color}
  31. tabIndex={0}
  32. style={{ backgroundColor: color }}
  33. key={color}
  34. >
  35. {color === "transparent" ? (
  36. <div className="color-picker-transparent"></div>
  37. ) : (
  38. undefined
  39. )}
  40. </div>
  41. ))}
  42. <div className="color-picker-hash">#</div>
  43. <div style={{ position: "relative" }}>
  44. <input
  45. spellCheck={false}
  46. className="color-picker-input"
  47. onChange={e => {
  48. const value = e.target.value;
  49. if (value.match(/^([0-9a-f]{3}|[0-9a-f]{6}|transparent)$/)) {
  50. onChange(value === "transparent" ? "transparent" : "#" + value);
  51. }
  52. setInnerValue(value);
  53. }}
  54. value={(innerValue || "").replace(/^#/, "")}
  55. />
  56. </div>
  57. <div style={{ clear: "both" }}></div>
  58. </div>
  59. </div>
  60. );
  61. };
  62. export function ColorPicker({
  63. type,
  64. color,
  65. onChange
  66. }: {
  67. type: "canvasBackground" | "elementBackground" | "elementStroke";
  68. color: string | null;
  69. onChange: (color: string) => void;
  70. }) {
  71. const [isActive, setActive] = React.useState(false);
  72. return (
  73. <div>
  74. <button
  75. className="color-picker-label-swatch"
  76. style={color ? { backgroundColor: color } : undefined}
  77. onClick={() => setActive(!isActive)}
  78. />
  79. <React.Suspense fallback="">
  80. {isActive ? (
  81. <Popover onCloseRequest={() => setActive(false)}>
  82. <Picker
  83. colors={colors[type]}
  84. color={color || undefined}
  85. onChange={changedColor => {
  86. onChange(changedColor);
  87. }}
  88. />
  89. </Popover>
  90. ) : null}
  91. </React.Suspense>
  92. <input
  93. type="text"
  94. className="color-picker-swatch-input"
  95. value={color || ""}
  96. onPaste={e => onChange(e.clipboardData.getData("text"))}
  97. onChange={e => onChange(e.target.value)}
  98. />
  99. </div>
  100. );
  101. }
  102. // https://yeun.github.io/open-color/
  103. const colors = {
  104. // Shade 0
  105. canvasBackground: [
  106. "#FFFFFF",
  107. "#F8F9FA",
  108. "#F1F3F5",
  109. "#FFF5F5",
  110. "#FFF0F6",
  111. "#F8F0FC",
  112. "#F3F0FF",
  113. "#EDF2FF",
  114. "#E7F5FF",
  115. "#E3FAFC",
  116. "#E6FCF5",
  117. "#EBFBEE",
  118. "#F4FCE3",
  119. "#FFF9DB",
  120. "#FFF4E6"
  121. ],
  122. // Shade 6
  123. elementBackground: [
  124. "transparent",
  125. "#CED4DA",
  126. "#868E96",
  127. "#FA5252",
  128. "#E64980",
  129. "#BE4BDB",
  130. "#7950F2",
  131. "#4C6EF5",
  132. "#228BE6",
  133. "#15AABF",
  134. "#12B886",
  135. "#40C057",
  136. "#82C91E",
  137. "#FAB005",
  138. "#FD7E14"
  139. ],
  140. // Shade 9
  141. elementStroke: [
  142. "#000000",
  143. "#343A40",
  144. "#495057",
  145. "#C92A2A",
  146. "#A61E4D",
  147. "#862E9C",
  148. "#5F3DC4",
  149. "#364FC7",
  150. "#1864AB",
  151. "#0B7285",
  152. "#087F5B",
  153. "#2B8A3E",
  154. "#5C940D",
  155. "#E67700",
  156. "#D9480F"
  157. ]
  158. };