index.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import React, { ReactNode } from 'react';
  2. import { HsvaColor, RgbaColor } from '@douyinfe/semi-foundation/colorPicker/types';
  3. import Input from "../../input";
  4. import InputGroup from "../../input/inputGroup";
  5. import InputNumber from "../../inputNumber";
  6. import Select from "../../select";
  7. import Button from "../../button";
  8. import split from "@douyinfe/semi-foundation/colorPicker/utils/split";
  9. import ColorPickerFoundation, { ColorPickerProps } from '@douyinfe/semi-foundation/colorPicker/foundation';
  10. import { isEqual } from 'lodash';
  11. import { IconEyedropper } from '@douyinfe/semi-icons';
  12. import { cssClasses } from '@douyinfe/semi-foundation/colorPicker/constants';
  13. type Value = ColorPickerProps['value']
  14. interface DataPartProps {
  15. currentColor: Value;
  16. defaultFormat: 'hex'|'rgba'|'hsva';
  17. width: number;
  18. alpha?: boolean;
  19. foundation: ColorPickerFoundation
  20. }
  21. interface DataPartState{
  22. format: 'hex'|'rgba'|'hsva';
  23. inputValue: string
  24. }
  25. class DataPart extends React.Component<DataPartProps, DataPartState> {
  26. constructor(props: DataPartProps) {
  27. super(props);
  28. this.state = {
  29. format: this.props.defaultFormat,
  30. inputValue: ''
  31. };
  32. }
  33. componentDidMount() {
  34. this.setState({ inputValue: this.getInputValue() });
  35. }
  36. componentDidUpdate(prevProps: Readonly<DataPartProps>, prevState: Readonly<DataPartState>, snapshot?: any) {
  37. if (!isEqual(prevProps.currentColor, this.props.currentColor)|| prevState.format !== this.state.format) {
  38. this.setState({ inputValue: this.getInputValue() });
  39. }
  40. }
  41. getInputValue = ()=>{
  42. const rgba = this.props.currentColor.rgba;
  43. const hsva = this.props.currentColor.hsva;
  44. const hex = this.props.currentColor.hex;
  45. if (this.state.format === 'rgba') {
  46. return `${rgba.r},${rgba.g},${rgba.b}`;
  47. } else if (this.state.format === 'hsva') {
  48. return `${hsva.h},${hsva.s},${hsva.v}`;
  49. } else {
  50. return hex.slice(0, 7);
  51. }
  52. }
  53. handleChange = (newColor: RgbaColor|HsvaColor|string)=>{
  54. this.props.foundation.handleChange(newColor, this.state.format);
  55. }
  56. getValueByInputValue = (value: string)=>{
  57. if (this.state.format==='rgba') {
  58. const result = split(value, this.state.format);
  59. if (result) {
  60. return result as RgbaColor;
  61. }
  62. } else if (this.state.format==='hsva') {
  63. const result = split(value, this.state.format);
  64. if (result) {
  65. return result as HsvaColor;
  66. }
  67. } else if (this.state.format==='hex') {
  68. if (!value.startsWith('#')) {
  69. value = '#'+value;
  70. }
  71. if (/#[\d\w]{6,8}/.test(value)) {
  72. return value;
  73. }
  74. }
  75. return false;
  76. }
  77. handlePickValueWithStraw = async ()=>{
  78. if (!window['EyeDropper']) {
  79. return;
  80. }
  81. //@ts-ignore
  82. const eyeDropper = new EyeDropper();
  83. try {
  84. const result = await eyeDropper.open();
  85. const color = result['sRGBHex'];
  86. if (color.startsWith("#")) {
  87. this.props.foundation.handleChange(color, 'hex');
  88. } else if (color.startsWith('rgba')) {
  89. const rgba = ColorPickerFoundation.rgbaStringToRgba(color);
  90. rgba.a = 1;
  91. this.props.foundation.handleChange(rgba, 'rgba');
  92. }
  93. } catch (e) {
  94. }
  95. }
  96. render() {
  97. const rgba = this.props.currentColor.rgba;
  98. return <div className={`${cssClasses.PREFIX}-dataPart`} style={{ width: this.props.width }}>
  99. <div className={`${cssClasses.PREFIX}-colorDemoBlock`} style={{ minWidth: 20, minHeight: 20, backgroundColor:
  100. `rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})` }}>
  101. </div>
  102. <InputGroup size={'small'} className={`${cssClasses.PREFIX}-inputGroup`} >
  103. <Input className={`${cssClasses.PREFIX}-colorPickerInput`}
  104. value={this.state.inputValue}
  105. onChange={(v)=>{
  106. const value = this.getValueByInputValue(v);
  107. if (value) {
  108. this.handleChange(value);
  109. }
  110. this.setState({ inputValue: v });
  111. }}
  112. />
  113. {
  114. this.props.alpha && <InputNumber
  115. min={0}
  116. max={100}
  117. className={`${cssClasses.PREFIX}-colorPickerInputNumber`}
  118. value={Number(Math.round(this.props.currentColor.rgba.a*100))}
  119. onNumberChange={v=>{
  120. if (this.state.format==='rgba') {
  121. this.handleChange({ ...this.props.currentColor.rgba, a: Number((v/100).toFixed(2)) });
  122. } else if (this.state.format==='hex') {
  123. const rgba = { ...this.props.currentColor.rgba, a: Number((v/100).toFixed(2)) };
  124. const hex = ColorPickerFoundation.rgbaToHex(rgba);
  125. this.handleChange(hex);
  126. } else if (this.state.format==='hsva') {
  127. const rgba = { ...this.props.currentColor.hsva, a: Number((v/100).toFixed(2)) };
  128. this.handleChange(rgba);
  129. }
  130. }}
  131. suffix={<span className={`${cssClasses.PREFIX}-inputNumberSuffix`}>%</span>} hideButtons={true} />
  132. }
  133. <Select className={`${cssClasses.PREFIX}-formatSelect`}
  134. size={'small'}
  135. value={this.state.format}
  136. onSelect={v=>this.setState({ format: v as DataPartState['format'] })}
  137. optionList={['hex', 'rgba', 'hsva'].map(type=>({ label: type, value: type }))}/>
  138. </InputGroup>
  139. <Button type={'tertiary'} theme={"light"} size={'small'} onClick={this.handlePickValueWithStraw} icon={<IconEyedropper />}/>
  140. </div>;
  141. }
  142. }
  143. export default DataPart;