solid-color
Advanced tools
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps, onCleanup } from 'solid-js' | ||
| import { HslColor, RgbColor } from '../../types' | ||
| import * as alpha from '../../helpers/alpha' | ||
| import { Checkboard } from './Checkboard' | ||
| export interface AlphaProps { | ||
| rgb: RgbColor | ||
| hsl: HslColor | ||
| renderers?: any | ||
| direction?: string | ||
| a?: number | ||
| radius?: number | ||
| shadow?: string | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| pointer?: <T extends object>(props: T) => JSX.Element | ||
| onChange?: (data: any, e: Event) => void | ||
| } | ||
| export const Alpha = (_props: AlphaProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| direction: 'horizontal', | ||
| styles: {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| let container: HTMLDivElement | ||
| const styles = () => { | ||
| const { rgb } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| alpha: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'border-radius': props.radius, | ||
| }, | ||
| checkboard: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| overflow: 'hidden', | ||
| 'border-radius': props.radius, | ||
| }, | ||
| gradient: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| background: | ||
| props.direction === 'vertical' | ||
| ? `linear-gradient(to bottom, rgba(${rgb.r},${rgb.g},${rgb.b}, 0) 0%, | ||
| rgba(${rgb.r},${rgb.g},${rgb.b}, 1) 100%)` | ||
| : `linear-gradient(to right, rgba(${rgb.r},${rgb.g},${rgb.b}, 0) 0%, | ||
| rgba(${rgb.r},${rgb.g},${rgb.b}, 1) 100%)`, | ||
| 'box-shadow': props.shadow, | ||
| 'border-radius': props.radius, | ||
| }, | ||
| container: { | ||
| position: 'relative', | ||
| height: '100%', | ||
| margin: '0 3px', | ||
| }, | ||
| pointer: { | ||
| position: 'absolute', | ||
| left: props.direction === 'vertical' ? 0 : `${rgb.a && rgb.a * 100}%`, | ||
| top: props.direction === 'vertical' ? `${rgb.a && rgb.a * 100}%` : undefined, | ||
| }, | ||
| slider: { | ||
| width: '4px', | ||
| 'border-radius': '1px', | ||
| height: '8px', | ||
| 'box-shadow': '0 0 2px rgba(0, 0, 0, .6)', | ||
| background: '#fff', | ||
| 'margin-top': '1px', | ||
| transform: 'translateX(-2px)', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| const handleChange = (e: Event) => { | ||
| const change = alpha.calculateChange(e, props.hsl, props.direction, props.a, container) | ||
| change && typeof props.onChange === 'function' && props.onChange(change, e) | ||
| } | ||
| const handleMouseDown = (e: Event) => { | ||
| handleChange(e) | ||
| window.addEventListener('mousemove', handleChange) | ||
| window.addEventListener('mouseup', handleMouseUp) | ||
| } | ||
| const handleMouseUp = () => { | ||
| unbindEventListeners() | ||
| } | ||
| const unbindEventListeners = () => { | ||
| window.removeEventListener('mousemove', handleChange) | ||
| window.removeEventListener('mouseup', handleMouseUp) | ||
| } | ||
| onCleanup(() => unbindEventListeners()) | ||
| return ( | ||
| <div style={styles().alpha}> | ||
| <div style={styles().checkboard}> | ||
| <Checkboard renderers={props.renderers} /> | ||
| </div> | ||
| <div style={styles().gradient} /> | ||
| <div | ||
| style={styles().container} | ||
| ref={container!} | ||
| onMouseDown={handleMouseDown} | ||
| onMouseUp={handleChange} | ||
| onTouchMove={handleChange} | ||
| onTouchStart={handleChange} | ||
| > | ||
| <div style={styles().pointer}> | ||
| {props.pointer ? <props.pointer {...props} /> : <div style={styles().slider} />} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import * as checkboard from '../../helpers/checkboard' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| export type CheckboardProps = { | ||
| size?: number | ||
| white?: string | ||
| grey?: string | ||
| renderers?: any | ||
| borderRadius?: string | number | ||
| boxShadow?: string | ||
| children?: JSX.Element | ||
| } | ||
| export function Checkboard(_props: CheckboardProps) { | ||
| const props = mergeProps( | ||
| { | ||
| white: 'transparent', | ||
| grey: 'rgba(0,0,0,.08)', | ||
| size: 8, | ||
| renderers: {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| const styles = () => { | ||
| const { size, white, grey, borderRadius, boxShadow, renderers } = props | ||
| return { | ||
| grid: { | ||
| 'border-radius': borderRadius, | ||
| 'box-shadow': boxShadow, | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| background: `url(${checkboard.get(white, grey, size, renderers.canvas)}) center left`, | ||
| } as JSX.CSSProperties, | ||
| } | ||
| } | ||
| // return isValidElement(children) ? ( | ||
| // React.cloneElement(children, { | ||
| // ...children.props, | ||
| // style: { ...children.props.style, ...styles.grid }, | ||
| // }) | ||
| // ) : ( | ||
| // <div style={styles.grid} /> | ||
| // ) | ||
| // 判断children是否是一个有效的元素 | ||
| return props.children ? ( | ||
| // clone | ||
| <div style={styles().grid}>{props.children}</div> | ||
| ) : ( | ||
| <div style={styles().grid} /> | ||
| ) | ||
| } |
| import { | ||
| Accessor, | ||
| Context, | ||
| createContext, | ||
| createEffect, | ||
| createMemo, | ||
| createSignal, | ||
| JSX, | ||
| mergeProps, | ||
| useContext, | ||
| } from 'solid-js' | ||
| import { ChangeColor, Color, ColorResult } from '../../types' | ||
| import * as color from '../../helpers/color' | ||
| import { debounce } from 'lodash-es' | ||
| export interface ColorPickerContextType { | ||
| colors: Accessor<ColorResult> | ||
| changeColor: (color: ChangeColor, event?: Event) => void | ||
| onSwatchHover?: (color: ChangeColor, event: Event) => void | ||
| } | ||
| export const ColorPickerContext = createContext<ColorPickerContextType | undefined>(undefined) | ||
| export interface ColorPickerProps { | ||
| children?: JSX.Element | ||
| defaultColor?: Color | ||
| color?: Color | ||
| onChange?: (color: ColorResult, event?: Event) => void | ||
| onChangeComplete?: (color: ColorResult) => void | ||
| onSwatchHover?: (color: ColorResult, event: Event) => void | ||
| } | ||
| export function ColorPickerProvider(_props: ColorPickerProps) { | ||
| const props = mergeProps({ defaultColor: { h: 250, s: 0.5, l: 0.2, a: 1 } }, _props) | ||
| const [colors, setColors] = createSignal<ColorResult>({ | ||
| ...color.toState(props.color ?? props.defaultColor, 0), | ||
| }) | ||
| createEffect(() => { | ||
| if (props.color) { | ||
| setColors({ ...color.toState(props.color, 0) }) | ||
| } | ||
| }) | ||
| const handler = (fn: any, data: any, event: any) => fn(data, event) | ||
| const debouncedChangeHandler = createMemo(() => debounce(handler, 100), []) | ||
| const changeColor = (newColor: ChangeColor, event?: Event) => { | ||
| const isValidColor = color.simpleCheckForValidColor(newColor) | ||
| if (isValidColor) { | ||
| const newColors = color.toState( | ||
| newColor, | ||
| (typeof newColor !== 'string' && 'h' in newColor ? newColor.h : undefined) || | ||
| colors().oldHue, | ||
| ) | ||
| setColors(newColors) | ||
| props.onChangeComplete && debouncedChangeHandler()(props.onChangeComplete, newColors, event) | ||
| props.onChange && props.onChange(newColors, event) | ||
| } | ||
| } | ||
| const handleSwatchHover = (data: ChangeColor, event: Event) => { | ||
| const isValidColor = color.simpleCheckForValidColor(data) | ||
| if (isValidColor) { | ||
| const newColors = color.toState( | ||
| data, | ||
| (typeof data !== 'string' && 'h' in data ? data.h : undefined) || colors().oldHue, | ||
| ) | ||
| props.onSwatchHover && props.onSwatchHover(newColors, event) | ||
| } | ||
| } | ||
| const store = { | ||
| colors, | ||
| changeColor, | ||
| onSwatchHover: props.onSwatchHover ? handleSwatchHover : undefined, | ||
| } | ||
| return <ColorPickerContext.Provider value={store}>{props.children}</ColorPickerContext.Provider> | ||
| } | ||
| export function useColorPicker() { | ||
| return useContext(ColorPickerContext as Context<ColorPickerContextType>) | ||
| } | ||
| export function withColorPicker<T extends object>(Component: (props: T) => JSX.Element) { | ||
| return (props: T & Omit<ColorPickerProps, 'children'>) => ( | ||
| <ColorPickerProvider {...props}> | ||
| <Component {...props} /> | ||
| </ColorPickerProvider> | ||
| ) | ||
| } |
| import { merge } from 'lodash-es' | ||
| import { createEffect, createSignal, JSX, mergeProps, onCleanup, Show } from 'solid-js' | ||
| export interface EditableInputProps { | ||
| styles: Record<string, JSX.CSSProperties> | ||
| value?: string | number | ||
| label?: string | ||
| hideLabel?: boolean | ||
| placeholder?: string | ||
| arrowOffset?: number | ||
| dragLabel?: boolean | ||
| dragMax?: number | ||
| onChange?: (value: any, e: Event) => void | ||
| } | ||
| interface EditableInputState { | ||
| value: string | ||
| blurValue: string | ||
| borderColor?: string | ||
| } | ||
| export function EditableInput(_props: EditableInputProps) { | ||
| const props = mergeProps( | ||
| { | ||
| arrowOffset: 1, | ||
| hideLabel: false, | ||
| }, | ||
| _props, | ||
| ) | ||
| let inputRef: HTMLInputElement | ||
| const inputId = `sc-editable-input-${Math.random().toString().slice(2, 5)}` | ||
| const [state, setState] = createSignal<EditableInputState>({ | ||
| value: String(props.value).toUpperCase(), | ||
| blurValue: String(props.value).toUpperCase(), | ||
| }) | ||
| const DEFAULT_ARROW_OFFSET = 1 | ||
| const UP_KEY_CODE = 38 | ||
| const DOWN_KEY_CODE = 40 | ||
| const VALID_KEY_CODES = [UP_KEY_CODE, DOWN_KEY_CODE] | ||
| const isValidKeyCode = (keyCode: number) => VALID_KEY_CODES.indexOf(keyCode) > -1 | ||
| const getNumberValue = (value: string) => Number(String(value).replace(/%/g, '')) | ||
| const getValueObjectWithLabel = (value: string) => { | ||
| return { | ||
| [props.label!]: value, | ||
| } | ||
| } | ||
| const setUpdatedValue = (value: any, e: Event) => { | ||
| const onChangeValue = props.label ? getValueObjectWithLabel(value) : value | ||
| props.onChange && props.onChange(onChangeValue, e) | ||
| setState({ value, blurValue: value }) | ||
| } | ||
| const handleBlur = () => { | ||
| if (state().blurValue) { | ||
| setState({ value: state().blurValue, blurValue: '' }) | ||
| } | ||
| } | ||
| const handleChange = (e: Event) => { | ||
| setUpdatedValue((e.target as HTMLInputElement).value, e) | ||
| } | ||
| const handleDrag = (e: MouseEvent) => { | ||
| if (props.dragLabel) { | ||
| const newValue = Math.round(+props.value! + e.movementX) | ||
| if (newValue >= 0 && newValue <= props.dragMax!) { | ||
| props.onChange && props.onChange(getValueObjectWithLabel(String(newValue)), e) | ||
| } | ||
| } | ||
| } | ||
| const unbindEventListeners = () => { | ||
| window.removeEventListener('mousemove', handleDrag) | ||
| window.removeEventListener('mouseup', handleMouseUp) | ||
| } | ||
| const handleMouseUp = () => { | ||
| unbindEventListeners() | ||
| } | ||
| const handleMouseDown = (e: MouseEvent) => { | ||
| if (props.dragLabel) { | ||
| e.preventDefault() | ||
| handleDrag(e) | ||
| window.addEventListener('mousemove', handleDrag) | ||
| window.addEventListener('mouseup', handleMouseUp) | ||
| } | ||
| } | ||
| const handleKeyDown = (e: KeyboardEvent) => { | ||
| const value = getNumberValue((e.target as HTMLInputElement).value) | ||
| if (!isNaN(value) && isValidKeyCode(e.keyCode)) { | ||
| const offset = props.arrowOffset || DEFAULT_ARROW_OFFSET | ||
| const updatedValue = e.keyCode === UP_KEY_CODE ? value + offset : value - offset | ||
| setUpdatedValue(updatedValue, e) | ||
| } | ||
| } | ||
| createEffect(() => { | ||
| setState({ | ||
| value: String(props.value).toUpperCase(), | ||
| blurValue: '', | ||
| }) | ||
| }) | ||
| const styles = () => { | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| wrap: { | ||
| position: 'relative', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| onCleanup(() => unbindEventListeners()) | ||
| return ( | ||
| <div style={styles().wrap}> | ||
| <input | ||
| id={inputId} | ||
| ref={inputRef!} | ||
| style={styles().input} | ||
| spellcheck={false} | ||
| value={state().value} | ||
| placeholder={props.placeholder} | ||
| onBlur={handleBlur} | ||
| onChange={handleChange} | ||
| onKeyDown={handleKeyDown} | ||
| onInput={handleChange} | ||
| /> | ||
| <Show when={props.label && !props.hideLabel}> | ||
| <label style={styles().label} onMouseDown={handleMouseDown}> | ||
| {props.label} | ||
| </label> | ||
| </Show> | ||
| </div> | ||
| ) | ||
| } |
| import { JSX, mergeProps, onCleanup } from 'solid-js' | ||
| import { calculateChange } from '../../helpers/hue' | ||
| import { HslColor } from '../../types' | ||
| interface HueProps { | ||
| children?: JSX.Element | ||
| direction?: string | ||
| radius?: number | string | ||
| shadow?: string | ||
| hsl: HslColor | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| pointer?: <T extends object>(props: T) => JSX.Element | ||
| onChange?: (data: HslColor, e: MouseEvent) => void | ||
| } | ||
| export function Hue(_props: HueProps) { | ||
| const props = mergeProps( | ||
| { | ||
| direction: 'horizontal', | ||
| }, | ||
| _props, | ||
| ) | ||
| let container: HTMLDivElement | ||
| const styles = () => { | ||
| return { | ||
| hue: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'border-radius': typeof props.radius === 'string' ? props.radius : `${props.radius}px`, | ||
| 'box-shadow': props.shadow, | ||
| }, | ||
| container: { | ||
| padding: '0 2px', | ||
| position: 'relative', | ||
| height: '100%', | ||
| 'border-radius': typeof props.radius === 'string' ? props.radius : `${props.radius}px`, | ||
| }, | ||
| pointer: { | ||
| position: 'absolute', | ||
| left: props.direction === 'vertical' ? '0px' : `${(props.hsl.h * 100) / 360}%`, | ||
| top: props.direction === 'vertical' ? `${-((props.hsl.h * 100) / 360) + 100}%` : undefined, | ||
| }, | ||
| slider: { | ||
| 'margin-top': '1px', | ||
| width: '4px', | ||
| 'border-radius': '1px', | ||
| height: '8px', | ||
| 'box-shadow': '0 0 2px rgba(0, 0, 0, .6)', | ||
| background: '#fff', | ||
| transform: 'translateX(-2px)', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| const handleChange = (e: MouseEvent) => { | ||
| const change = calculateChange(e, props.direction, props.hsl, container) | ||
| change && typeof props.onChange === 'function' && props.onChange(change, e) | ||
| } | ||
| const unbindEventListeners = () => { | ||
| window.removeEventListener('mousemove', handleChange) | ||
| window.removeEventListener('mouseup', handleMouseUp) | ||
| } | ||
| const handleMouseUp = () => { | ||
| unbindEventListeners() | ||
| } | ||
| const handleMouseDown = (e: MouseEvent) => { | ||
| handleChange(e) | ||
| window.addEventListener('mousemove', handleChange) | ||
| window.addEventListener('mouseup', handleMouseUp) | ||
| } | ||
| onCleanup(() => unbindEventListeners()) | ||
| return ( | ||
| <div style={styles().hue}> | ||
| <div | ||
| ref={container!} | ||
| class={`hue-${props.direction}`} | ||
| style={styles().container} | ||
| onMouseDown={handleMouseDown} | ||
| > | ||
| <style>{` | ||
| .hue-horizontal { | ||
| background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 | ||
| 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); | ||
| background: -webkit-linear-gradient(to right, #f00 0%, #ff0 | ||
| 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); | ||
| } | ||
| .hue-vertical { | ||
| background: linear-gradient(to top, #f00 0%, #ff0 17%, #0f0 33%, | ||
| #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); | ||
| background: -webkit-linear-gradient(to top, #f00 0%, #ff0 17%, | ||
| #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); | ||
| } | ||
| `}</style> | ||
| <div style={styles().pointer}> | ||
| {props.pointer ? <props.pointer {...props} /> : <div style={styles().slider} />} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import { mergeProps } from 'solid-js' | ||
| interface IconProps { | ||
| width?: number | string | ||
| height?: number | string | ||
| fill?: string | ||
| stroke?: string | ||
| onMouseOver?: (e: MouseEvent) => void | ||
| onMouseEnter?: (e: MouseEvent) => void | ||
| onMouseOut?: (e: MouseEvent) => void | ||
| } | ||
| export function CheckIcon(_props: IconProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 24, | ||
| height: 24, | ||
| fill: 'white', | ||
| stroke: 'white', | ||
| }, | ||
| _props, | ||
| ) | ||
| return ( | ||
| <svg | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| viewBox="0 0 24 24" | ||
| width={`${props.width}px`} | ||
| height={`${props.height}px`} | ||
| fill={props.fill} | ||
| stroke={props.stroke} | ||
| stroke-width="0.5" | ||
| > | ||
| <path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" /> | ||
| </svg> | ||
| ) | ||
| } | ||
| export function UnfoldMoreHorizontalIcon(_props: IconProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 24, | ||
| height: 24, | ||
| }, | ||
| _props, | ||
| ) | ||
| return ( | ||
| <svg | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| viewBox="0 0 24 24" | ||
| width={`${props.width}px`} | ||
| height={`${props.height}px`} | ||
| stroke-width="0.5" | ||
| style={{ 'border-radius': '5px' }} | ||
| onMouseOver={props.onMouseOver} | ||
| onMouseEnter={props.onMouseEnter} | ||
| onMouseOut={props.onMouseOut} | ||
| > | ||
| <path d="M12,18.17L8.83,15L7.42,16.41L12,21L16.59,16.41L15.17,15M12,5.83L15.17,9L16.58,7.59L12,3L7.41,7.59L8.83,9L12,5.83Z" /> | ||
| </svg> | ||
| ) | ||
| } |
| export * from './Alpha' | ||
| export * from './EditableInput' | ||
| export * from './Raised' | ||
| export * from './Hue' | ||
| export * from './ColorPicker' | ||
| export * from './Checkboard' | ||
| export * from './Swatch' | ||
| export * from './Saturation' | ||
| export * from './Icons' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| export interface RaisedProps { | ||
| background?: string | ||
| zDepth?: 0 | 1 | 2 | 3 | 4 | 5 | ||
| radius?: number | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| children?: JSX.Element | ||
| } | ||
| export function Raised(_props: RaisedProps) { | ||
| const props = mergeProps( | ||
| { | ||
| zDepth: 1, | ||
| radius: 2, | ||
| background: '#fff', | ||
| styles: {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| const styles = merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| wrap: { | ||
| position: 'relative', | ||
| display: 'inline-block', | ||
| }, | ||
| content: { | ||
| position: 'relative', | ||
| }, | ||
| bg: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'box-shadow': | ||
| props.zDepth === 1 | ||
| ? '0 2px 10px rgba(0,0,0,.12), 0 2px 5px rgba(0,0,0,.16)' | ||
| : `0 ${props.zDepth}px ${props.zDepth * 4}px rgba(0,0,0,.24)`, | ||
| 'border-radius': props.radius, | ||
| background: props.background, | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| return ( | ||
| <div style={styles.wrap}> | ||
| <div style={styles.bg} /> | ||
| <div style={styles.content}>{props.children}</div> | ||
| </div> | ||
| ) | ||
| } |
| import { merge } from 'lodash-es' | ||
| import { createEffect, JSX, mergeProps } from 'solid-js' | ||
| import { calculateChange } from '../../helpers/saturation' | ||
| import { ChangeColor, HslColor, HsvColor } from '../../types' | ||
| export type SaturationProps = { | ||
| hsl: HslColor | ||
| hsv: HsvColor | ||
| pointer?: JSX.Element | ||
| onChange?: (color: ChangeColor, event?: Event) => void | ||
| shadow?: JSX.CSSProperties['box-shadow'] | ||
| radius?: JSX.CSSProperties['border-radius'] | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| } | ||
| export function Saturation(_props: SaturationProps) { | ||
| const props = mergeProps({ styles: {} }, _props) | ||
| let container: HTMLDivElement | ||
| createEffect(() => { | ||
| return () => { | ||
| unbindEventListeners() | ||
| } | ||
| }, []) | ||
| function handleChange(event: MouseEvent | TouchEvent) { | ||
| if (props.onChange) { | ||
| props.onChange(calculateChange(event, props.hsl, container), event as any) | ||
| } | ||
| } | ||
| function handleMouseDown(event: MouseEvent) { | ||
| handleChange(event) | ||
| if (container) { | ||
| container.addEventListener('mousemove', handleChange) | ||
| container.addEventListener('mouseup', handleMouseUp) | ||
| } | ||
| } | ||
| function handleMouseUp() { | ||
| unbindEventListeners() | ||
| } | ||
| function unbindEventListeners() { | ||
| if (container) { | ||
| container.removeEventListener('mousemove', handleChange) | ||
| container.removeEventListener('mouseup', handleMouseUp) | ||
| } | ||
| } | ||
| const styles = () => { | ||
| const { hsv, hsl, shadow, radius, styles } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| color: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| background: `hsl(${hsl.h},100%, 50%)`, | ||
| 'border-radius': radius, | ||
| }, | ||
| white: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'border-radius': radius, | ||
| }, | ||
| black: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| boxShadow: shadow, | ||
| 'border-radius': radius, | ||
| }, | ||
| pointer: { | ||
| position: 'absolute', | ||
| top: `${-(hsv.v * 100) + 100}%`, | ||
| left: `${hsv.s * 100}%`, | ||
| cursor: 'default', | ||
| }, | ||
| circle: { | ||
| width: '4px', | ||
| height: '4px', | ||
| 'box-shadow': `0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0,0,0,.3), | ||
| 0 0 1px 2px rgba(0,0,0,.4)`, | ||
| 'border-radius': '50%', | ||
| cursor: 'hand', | ||
| transform: 'translate(-2px, -2px)', | ||
| }, | ||
| }, | ||
| styles, | ||
| ) | ||
| } | ||
| return ( | ||
| <div | ||
| style={styles().color} | ||
| ref={container!} | ||
| onMouseDown={handleMouseDown} | ||
| onTouchMove={handleChange} | ||
| onTouchStart={handleChange} | ||
| > | ||
| <style>{` | ||
| .saturation-white { | ||
| background: -webkit-linear-gradient(to right, #fff, rgba(255,255,255,0)); | ||
| background: linear-gradient(to right, #fff, rgba(255,255,255,0)); | ||
| } | ||
| .saturation-black { | ||
| background: -webkit-linear-gradient(to top, #000, rgba(0,0,0,0)); | ||
| background: linear-gradient(to top, #000, rgba(0,0,0,0)); | ||
| } | ||
| `}</style> | ||
| <div style={styles().white} class="saturation-white"> | ||
| <div style={styles().black} class="saturation-black" /> | ||
| <div style={styles().pointer}> | ||
| {props.pointer ? props.pointer : <div style={styles().circle} />} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import { createSignal, JSX, mergeProps } from 'solid-js' | ||
| import { Checkboard } from './Checkboard' | ||
| import { useColorPicker } from './ColorPicker' | ||
| const ENTER = 13 | ||
| export type SwatchProps = { | ||
| color: string | ||
| styles?: JSX.CSSProperties | ||
| onClick: any | ||
| title?: string | ||
| children?: JSX.Element | ||
| focused?: boolean | ||
| focusStyle?: JSX.CSSProperties | ||
| } | ||
| export function Swatch(_props: SwatchProps) { | ||
| const props = mergeProps( | ||
| { | ||
| onClick: () => {}, | ||
| title: _props.color, | ||
| focusStyle: {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| const { onSwatchHover } = useColorPicker() | ||
| const transparent = props.color === 'transparent' | ||
| const [focused, setFocused] = createSignal(false) | ||
| const handleFocus = () => setFocused(true) | ||
| const handleBlur = () => setFocused(false) | ||
| const handleClick = (e: Event) => { | ||
| props.onClick(props.color, e) | ||
| handleFocus() | ||
| } | ||
| const handleKeyDown = (e: KeyboardEvent) => e.keyCode === ENTER && props.onClick(props.color, e) | ||
| const styles = () => { | ||
| return { | ||
| swatch: { | ||
| background: props.color, | ||
| height: '100%', | ||
| width: '100%', | ||
| cursor: 'pointer', | ||
| position: 'relative', | ||
| outline: 'none', | ||
| ...props.styles, | ||
| ...(focused() ? props.focusStyle : {}), | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div | ||
| style={styles().swatch} | ||
| onClick={handleClick} | ||
| title={props.title} | ||
| tabIndex={0} | ||
| onKeyDown={handleKeyDown} | ||
| onBlur={handleBlur} | ||
| onMouseOver={(event) => { | ||
| onSwatchHover && onSwatchHover(props.color, event) | ||
| }} | ||
| > | ||
| {props.children} | ||
| {transparent && ( | ||
| <Checkboard | ||
| borderRadius={styles().swatch.borderRadius} | ||
| boxShadow="inset 0 0 0 1px rgba(0,0,0,0.1)" | ||
| /> | ||
| )} | ||
| </div> | ||
| ) | ||
| } | ||
| export default Swatch |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { Alpha, useColorPicker, withColorPicker } from '../_common' | ||
| import AlphaPointer from './AlphaPointer' | ||
| export type AlphaPickerProps = { | ||
| width?: string | number | ||
| height?: string | number | ||
| direction?: string | ||
| pointer?: <T extends object>(props: T) => JSX.Element | ||
| renderers?: any | ||
| className?: string | ||
| style?: Record<string, JSX.CSSProperties> | ||
| } | ||
| export function AlphaPicker(_props: AlphaPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: '316px', | ||
| height: '16px', | ||
| direction: 'horizontal', | ||
| pointer: AlphaPointer, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| picker: { | ||
| position: 'relative', | ||
| width: props.width, | ||
| height: props.height, | ||
| }, | ||
| alpha: { | ||
| borderRadius: '2px', | ||
| ...props.style, | ||
| }, | ||
| } | ||
| return ( | ||
| <div style={styles.picker} class={`alpha-picker ${props.className}`}> | ||
| <Alpha | ||
| {...styles.alpha} | ||
| rgb={currentColors().rgb} | ||
| hsl={currentColors().hsl} | ||
| pointer={props.pointer} | ||
| renderers={props.renderers} | ||
| onChange={changeColor} | ||
| direction={props.direction} | ||
| /> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(AlphaPicker) |
| import { JSX, mergeProps } from 'solid-js' | ||
| interface Props { | ||
| direction?: string | ||
| } | ||
| export default function AlphaPointer(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| picker: { | ||
| width: '18px', | ||
| height: '18px', | ||
| 'border-radius': '50%', | ||
| transform: props.direction === 'vertical' ? 'translate(-3px, -9px)' : 'translate(-9px, -1px)', | ||
| 'background-color': 'rgb(248, 248, 248)', | ||
| 'box-shadow': '0 1px 4px 0 rgba(0, 0, 0, 0.37)', | ||
| }, | ||
| } | ||
| return <div style={styles.picker} /> | ||
| } |
| export { default as AlphaPicker } from './Alpha' | ||
| export type { AlphaPickerProps } from './Alpha' |
| import * as color from '../../helpers/color' | ||
| import { HexColor } from '../../types' | ||
| import { Checkboard, EditableInput, useColorPicker, withColorPicker } from '../_common' | ||
| import BlockSwatches from './BlockSwatches' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { merge } from 'lodash-es' | ||
| export type BlockPickerProps = { | ||
| width?: string | number | ||
| colors?: string[] | ||
| triangle?: 'top' | 'hide' | ||
| className?: string | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| } | ||
| export const Block = (_props: BlockPickerProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| colors: [ | ||
| '#D9E3F0', | ||
| '#F47373', | ||
| '#697689', | ||
| '#37D67A', | ||
| '#2CCCE4', | ||
| '#555555', | ||
| '#dce775', | ||
| '#ff8a65', | ||
| '#ba68c8', | ||
| ], | ||
| width: 170, | ||
| triangle: 'top', | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const transparent = currentColors().hex === 'transparent' | ||
| const handleChange = (hexCode: HexColor, e: Event) => { | ||
| color.isValidHex(hexCode) && | ||
| changeColor( | ||
| { | ||
| hex: hexCode, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| const { triangle, styles } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| card: { | ||
| width, | ||
| background: '#fff', | ||
| 'box-shadow': '0 1px rgba(0,0,0,.1)', | ||
| 'border-radius': '6px', | ||
| position: 'relative', | ||
| }, | ||
| head: { | ||
| height: '110px', | ||
| background: currentColors().hex, | ||
| 'border-radius': '6px 6px 0 0', | ||
| display: 'flex', | ||
| 'align-items': 'center', | ||
| 'justify-content': 'center', | ||
| position: 'relative', | ||
| }, | ||
| body: { | ||
| padding: '10px', | ||
| }, | ||
| label: { | ||
| 'font-size': '18px', | ||
| color: color.getContrastingColor(currentColors().hex), | ||
| position: 'relative', | ||
| }, | ||
| triangle: { | ||
| width: '0px', | ||
| height: '0px', | ||
| 'border-style': 'solid', | ||
| 'border-width': '0 10px 10px 10px', | ||
| 'border-color': `transparent transparent ${currentColors().hex} transparent`, | ||
| position: 'absolute', | ||
| top: '-10px', | ||
| left: '50%', | ||
| 'margin-left': '-10px', | ||
| display: triangle === 'hide' ? 'none' : undefined, | ||
| }, | ||
| input: { | ||
| width: '100%', | ||
| 'font-size': '12px', | ||
| color: '#666', | ||
| border: '0px', | ||
| outline: 'none', | ||
| height: '22px', | ||
| 'box-shadow': 'inset 0 0 0 1px #ddd', | ||
| 'border-radius': '4px', | ||
| padding: '0 7px', | ||
| 'box-sizing': 'border-box', | ||
| }, | ||
| }, | ||
| styles, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().card} class={`block-picker ${props.className}`}> | ||
| <div style={styles().triangle} /> | ||
| <div style={styles().head}> | ||
| {transparent && <Checkboard borderRadius="6px 6px 0 0" />} | ||
| <div style={styles().label}>{currentColors().hex}</div> | ||
| </div> | ||
| <div style={styles().body}> | ||
| <BlockSwatches colors={props.colors} onClick={handleChange} /> | ||
| <EditableInput | ||
| styles={{ input: styles().input }} | ||
| value={currentColors().hex} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Block) |
| import { HexColor } from '../../types' | ||
| import { Swatch } from '../_common' | ||
| import { JSX, For } from 'solid-js' | ||
| interface Props { | ||
| colors: string[] | ||
| onClick: (hexCode: HexColor, e: Event) => void | ||
| } | ||
| export const BlockSwatches = ({ colors, onClick }: Props) => { | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| swatches: { | ||
| 'margin-right': '-10px', | ||
| }, | ||
| swatch: { | ||
| width: '22px', | ||
| height: '22px', | ||
| float: 'left', | ||
| 'margin-right': '10px', | ||
| 'margin-bottom': '10px', | ||
| 'border-radius': '4px', | ||
| }, | ||
| clear: { | ||
| clear: 'both', | ||
| }, | ||
| } | ||
| return ( | ||
| <div style={styles.swatches}> | ||
| <For each={colors}> | ||
| {(c) => ( | ||
| <Swatch | ||
| color={c} | ||
| styles={styles.swatch} | ||
| onClick={onClick} | ||
| focusStyle={{ | ||
| 'box-shadow': `0 0 4px ${c}`, | ||
| }} | ||
| /> | ||
| )} | ||
| </For> | ||
| <div style={styles.clear} /> | ||
| </div> | ||
| ) | ||
| } | ||
| export default BlockSwatches |
| export { default as BlockPicker } from './Block' | ||
| export type { BlockPickerProps } from './Block' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { Alpha, Checkboard, Hue, Saturation, useColorPicker, withColorPicker } from '../_common' | ||
| import ChromeFields from './ChromeFields' | ||
| import ChromePointer from './ChromePointer' | ||
| import ChromePointerCircle from './ChromePointerCircle' | ||
| export interface ChromePickerProps { | ||
| width?: string | number | ||
| disableAlpha?: boolean | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| renderers?: any | ||
| className?: string | ||
| defaultView?: 'hex' | 'rgb' | 'hsl' | ||
| } | ||
| export const Chrome = (_props: ChromePickerProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| width: 225, | ||
| disableAlpha: false, | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| width, | ||
| background: '#fff', | ||
| 'border-radius': '2px', | ||
| 'box-shadow': '0 0 2px rgba(0,0,0,.3), 0 4px 8px rgba(0,0,0,.3)', | ||
| 'box-sizing': 'initial', | ||
| 'font-family': 'Menlo', | ||
| }, | ||
| saturation: { | ||
| width: '100%', | ||
| 'padding-bottom': '55%', | ||
| position: 'relative', | ||
| 'border-radius': '2px 2px 0 0', | ||
| overflow: 'hidden', | ||
| }, | ||
| Saturation: { | ||
| 'border-radius': '2px 2px 0 0', | ||
| }, | ||
| body: { | ||
| padding: '16px 16px 12px', | ||
| }, | ||
| controls: { | ||
| display: 'flex', | ||
| }, | ||
| color: { | ||
| width: props.disableAlpha ? '22px' : '32px', | ||
| }, | ||
| swatch: { | ||
| 'margin-top': props.disableAlpha ? '0px' : '6px', | ||
| width: props.disableAlpha ? '10px' : '16px', | ||
| height: props.disableAlpha ? '10px' : '16px', | ||
| 'border-radius': '8px', | ||
| position: 'relative', | ||
| overflow: 'hidden', | ||
| }, | ||
| active: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'border-radius': '8px', | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.1)', | ||
| background: `rgba(${colors().rgb.r}, ${colors().rgb.g}, ${colors().rgb.b}, ${ | ||
| colors().rgb.a | ||
| })`, | ||
| 'z-index': 2, | ||
| }, | ||
| toggles: { | ||
| flex: '1', | ||
| }, | ||
| hue: { | ||
| height: '10px', | ||
| position: 'relative', | ||
| 'margin-bottom': props.disableAlpha ? '0px' : '8px', | ||
| }, | ||
| Hue: { | ||
| 'border-radius': '2px', | ||
| }, | ||
| alpha: { | ||
| height: '10px', | ||
| position: 'relative', | ||
| display: props.disableAlpha ? 'none' : undefined, | ||
| }, | ||
| Alpha: { | ||
| 'border-radius': '2px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().picker} class={`chrome-picker ${props.className}`}> | ||
| <div style={styles().saturation}> | ||
| <Saturation | ||
| styles={styles().Saturation} | ||
| hsl={colors().hsl} | ||
| hsv={colors().hsv} | ||
| pointer={<ChromePointerCircle />} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles().body}> | ||
| <div style={styles().controls} class="flexbox-fix"> | ||
| <div style={styles().color}> | ||
| <div style={styles().swatch}> | ||
| <div style={styles().active} /> | ||
| <Checkboard renderers={props.renderers} /> | ||
| </div> | ||
| </div> | ||
| <div style={styles().toggles}> | ||
| <div style={styles().hue}> | ||
| <Hue | ||
| styles={styles().Hue} | ||
| hsl={colors().hsl} | ||
| pointer={ChromePointer} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles().alpha}> | ||
| <Alpha | ||
| direction="horizontal" | ||
| styles={styles().Alpha} | ||
| rgb={colors().rgb} | ||
| hsl={colors().hsl} | ||
| pointer={ChromePointer} | ||
| renderers={props.renderers} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <ChromeFields | ||
| rgb={colors().rgb} | ||
| hsl={colors().hsl} | ||
| hex={colors().hex} | ||
| view={props.defaultView} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Chrome) |
| import { createEffect, createSignal, JSX, mergeProps, Show } from 'solid-js' | ||
| import { ChangeColor, HexColor, HslColor, RgbColor } from '../../types' | ||
| import * as color from '../../helpers/color' | ||
| import { EditableInput, UnfoldMoreHorizontalIcon } from '../_common' | ||
| interface Props { | ||
| view?: 'hex' | 'rgb' | 'hsl' | ||
| onChange: (data: ChangeColor, event: Event) => void | ||
| rgb: RgbColor | ||
| hsl: HslColor | ||
| hex: HexColor | ||
| disableAlpha?: boolean | ||
| } | ||
| export default function ChromeFields(_props: Props) { | ||
| const props = mergeProps({ view: 'hex' }, _props) | ||
| const [view, setView] = createSignal(props.view) | ||
| createEffect(() => { | ||
| if (props.hsl.a !== 1 && view() === 'hex') { | ||
| setView('rgb') | ||
| } | ||
| }, []) | ||
| createEffect(() => { | ||
| if (props.hsl.a !== 1 && view() === 'hex') { | ||
| setView('rgb') | ||
| } | ||
| }, [props]) | ||
| function toggleViews() { | ||
| if (view() === 'hex') { | ||
| setView('rgb') | ||
| } else if (view() === 'rgb') { | ||
| setView('hsl') | ||
| } else if (view() === 'hsl') { | ||
| if (props.hsl.a === 1) { | ||
| setView('hex') | ||
| } else { | ||
| setView('rgb') | ||
| } | ||
| } | ||
| } | ||
| function handleChange(data: any, e: Event) { | ||
| if (data.hex) { | ||
| color.isValidHex(data.hex) && | ||
| props.onChange( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.r || data.g || data.b) { | ||
| props.onChange( | ||
| { | ||
| r: data.r || props.rgb.r, | ||
| g: data.g || props.rgb.g, | ||
| b: data.b || props.rgb.b, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.a) { | ||
| if (data.a < 0) { | ||
| data.a = 0 | ||
| } else if (data.a > 1) { | ||
| data.a = 1 | ||
| } | ||
| props.onChange( | ||
| { | ||
| h: props.hsl.h, | ||
| s: props.hsl.s, | ||
| l: props.hsl.l, | ||
| a: Math.round(data.a * 100) / 100, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.h || data.s || data.l) { | ||
| // Remove any occurances of '%'. | ||
| if (typeof data.s === 'string' && data.s.includes('%')) { | ||
| data.s = data.s.replace('%', '') | ||
| } | ||
| if (typeof data.l === 'string' && data.l.includes('%')) { | ||
| data.l = data.l.replace('%', '') | ||
| } | ||
| // We store HSL as a unit interval so we need to override the 1 input to 0.01 | ||
| if (data.s == 1) { | ||
| data.s = 0.01 | ||
| } else if (data.l == 1) { | ||
| data.l = 0.01 | ||
| } | ||
| props.onChange( | ||
| { | ||
| h: data.h || props.hsl.h, | ||
| s: Number(data.s !== undefined ? data.s : props.hsl.s), | ||
| l: Number(data.l !== undefined ? data.l : props.hsl.l), | ||
| source: 'hsl', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| function showHighlight(e: MouseEvent) { | ||
| ;(e.currentTarget as HTMLDivElement).style.backgroundColor = '#eee' | ||
| } | ||
| function hideHighlight(e: MouseEvent) { | ||
| ;(e.currentTarget as HTMLDivElement).style.backgroundColor = 'transparent' | ||
| } | ||
| const styles = () => { | ||
| return { | ||
| wrap: { | ||
| 'padding-top': '16px', | ||
| display: 'flex', | ||
| }, | ||
| fields: { | ||
| flex: '1', | ||
| display: 'flex', | ||
| 'margin-left': '-6px', | ||
| }, | ||
| field: { | ||
| 'padding-left': '6px', | ||
| width: '100%', | ||
| }, | ||
| alpha: { | ||
| 'padding-left': '6px', | ||
| width: '100%', | ||
| display: props.disableAlpha ? 'none' : undefined, | ||
| }, | ||
| toggle: { | ||
| width: '32px', | ||
| 'text-align': 'right', | ||
| position: 'relative', | ||
| }, | ||
| icon: { | ||
| 'margin-right': '-4px', | ||
| 'margin-top': '12px', | ||
| cursor: 'pointer', | ||
| position: 'relative', | ||
| }, | ||
| iconHighlight: { | ||
| position: 'absolute', | ||
| width: '24px', | ||
| height: '28px', | ||
| background: '#eee', | ||
| 'border-radius': '4px', | ||
| top: '10px', | ||
| left: '12px', | ||
| display: 'none', | ||
| }, | ||
| input: { | ||
| 'font-size': '11px', | ||
| color: '#333', | ||
| width: '100%', | ||
| 'border-radius': '2px', | ||
| border: 'none', | ||
| 'box-shadow': 'inset 0 0 0 1px #dadada', | ||
| height: '21px', | ||
| 'text-align': 'center', | ||
| }, | ||
| label: { | ||
| 'text-transform': 'uppercase', | ||
| 'font-size': '11px', | ||
| 'line-height': '11px', | ||
| color: '#969696', | ||
| 'text-align': 'center', | ||
| display: 'block', | ||
| 'margin-top': '12px', | ||
| }, | ||
| svg: { | ||
| fill: '#333', | ||
| width: '24px', | ||
| height: '24px', | ||
| border: '1px transparent solid', | ||
| 'border-radius': '5px', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div style={styles().wrap} class="flexbox-fix"> | ||
| <Show when={view() == 'hex'}> | ||
| <div style={styles().fields} class="flexbox-fix"> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="hex" | ||
| value={props.hex} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </Show> | ||
| <Show when={view() == 'rgb'}> | ||
| <div style={styles().fields} class="flexbox-fix"> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="r" | ||
| value={props.rgb.r} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="g" | ||
| value={props.rgb.g} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="b" | ||
| value={props.rgb.b} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().alpha}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="a" | ||
| value={props.rgb.a} | ||
| arrowOffset={0.01} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </Show> | ||
| <Show when={view() == 'hsl'}> | ||
| <div style={styles().fields} class="flexbox-fix"> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="h" | ||
| value={Math.round(props.hsl.h)} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="s" | ||
| value={`${Math.round(props.hsl.s * 100)}%`} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().field}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="l" | ||
| value={`${Math.round(props.hsl.l * 100)}%`} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().alpha}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="a" | ||
| value={props.hsl.a} | ||
| arrowOffset={0.01} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </Show> | ||
| <div style={styles().toggle}> | ||
| <div style={styles().icon} onClick={toggleViews}> | ||
| <UnfoldMoreHorizontalIcon | ||
| width="24" | ||
| height="24" | ||
| onMouseOver={showHighlight} | ||
| onMouseEnter={showHighlight} | ||
| onMouseOut={hideHighlight} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| export default function ChromePointer() { | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '12px', | ||
| height: '12px', | ||
| 'border-radius': '6px', | ||
| transform: 'translate(-6px, -1px)', | ||
| 'background-color': 'rgb(248, 248, 248)', | ||
| 'box-shadow': '0 1px 4px 0 rgba(0, 0, 0, 0.37)', | ||
| }} | ||
| /> | ||
| ) | ||
| } |
| export default function ChromePointerCircle() { | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '12px', | ||
| height: '12px', | ||
| 'border-radius': '6px', | ||
| 'box-shadow': 'inset 0 0 0 1px #fff', | ||
| transform: 'translate(-6px, -6px)', | ||
| }} | ||
| /> | ||
| ) | ||
| } |
| export { default as ChromePicker } from './Chrome' | ||
| export type { ChromePickerProps } from './Chrome' |
| import { merge } from 'lodash-es' | ||
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import { HexColor } from '../../types' | ||
| import { useColorPicker, withColorPicker } from '../_common' | ||
| import CircleSwatch from './CircleSwatch' | ||
| export type CirclePickerProps = { | ||
| width?: string | number | ||
| circleSize?: number | ||
| circleSpacing?: number | ||
| className?: string | ||
| colors?: string[] | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| } | ||
| export function Circle(_props: CirclePickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 252, | ||
| colors: [ | ||
| '#F44336', | ||
| '#E91E63', | ||
| '#9C27B0', | ||
| '#673AB7', | ||
| '#3F51B5', | ||
| '#2196F3', | ||
| '#03A9F4', | ||
| '#00BCD4', | ||
| '#009688', | ||
| '#4CAF50', | ||
| '#8BC34A', | ||
| '#CDDC39', | ||
| '#FFEB3B', | ||
| '#FFC107', | ||
| '#FF9800', | ||
| '#FF5722', | ||
| '#795548', | ||
| '#607D8B', | ||
| ], | ||
| circleSize: 28, | ||
| styles: {}, | ||
| circleSpacing: 14, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const { width, circleSpacing, styles } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| card: { | ||
| width: `${width}px`, | ||
| display: 'flex', | ||
| 'flex-wrap': 'wrap', | ||
| 'margin-right': `${-circleSpacing}px`, | ||
| 'margin-bottom': `${-circleSpacing}px`, | ||
| }, | ||
| }, | ||
| styles, | ||
| ) | ||
| } | ||
| const handleChange = (hexCode: HexColor, e: Event) => | ||
| changeColor({ hex: hexCode, source: 'hex' }, e) | ||
| return ( | ||
| <div style={styles().card} class={`circle-picker ${props.className}`}> | ||
| <For each={props.colors}> | ||
| {(c) => ( | ||
| <CircleSwatch | ||
| color={c} | ||
| onClick={handleChange} | ||
| active={currentColors().hex === c.toLowerCase()} | ||
| circleSize={props.circleSize} | ||
| circleSpacing={props.circleSpacing} | ||
| /> | ||
| )} | ||
| </For> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Circle) |
| import { createSignal, JSX, mergeProps } from 'solid-js' | ||
| import { HexColor } from '../../types' | ||
| import { Swatch } from '../_common' | ||
| interface Props { | ||
| circleSize?: number | ||
| circleSpacing?: number | ||
| className?: string | ||
| color: string | ||
| active?: boolean | ||
| onClick: (hexCode: HexColor, e: Event) => void | ||
| } | ||
| export const CircleSwatch = (_props: Props) => { | ||
| const props = mergeProps( | ||
| { | ||
| circleSize: 28, | ||
| circleSpacing: 14, | ||
| }, | ||
| _props, | ||
| ) | ||
| const [hover, setHover] = createSignal(false) | ||
| const styles = () => { | ||
| const { circleSize, circleSpacing, color, active } = props | ||
| return { | ||
| swatch: { | ||
| width: `${circleSize}px`, | ||
| height: `${circleSize}px`, | ||
| 'margin-right': `${circleSpacing}px`, | ||
| 'margin-bottom': `${circleSpacing}px`, | ||
| transform: 'scale(1)', | ||
| transition: '100ms transform ease', | ||
| }, | ||
| Swatch: { | ||
| 'border-radius': '50%', | ||
| background: 'transparent', | ||
| 'box-shadow': active | ||
| ? `inset 0 0 0 3px ${color}` | ||
| : `inset 0 0 0 ${circleSize / 2 + 1}px ${color}`, | ||
| transition: '100ms box-shadow ease', | ||
| transform: hover() ? 'scale(1.2)' : undefined, | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div onMouseOver={() => setHover(true)} onMouseOut={() => setHover(false)}> | ||
| <div style={styles().swatch}> | ||
| <Swatch | ||
| styles={styles().Swatch} | ||
| color={props.color} | ||
| onClick={props.onClick} | ||
| focusStyle={{ | ||
| 'box-shadow': `${styles().Swatch.boxShadow}, 0 0 5px ${props.color}`, | ||
| }} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default CircleSwatch |
| export { default as CirclePicker } from './Circle' | ||
| export type { CirclePickerProps } from './Circle' |
| import { merge } from 'lodash-es' | ||
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import * as color from '../../helpers/color' | ||
| import { Raised, useColorPicker, withColorPicker } from '../_common' | ||
| import CompactColor from './CompactColor' | ||
| import CompactFields from './CompactFields' | ||
| export type CompactPickerProps = { | ||
| colors?: string[] | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| } | ||
| export function Compact(_props: CompactPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| colors: [ | ||
| '#4D4D4D', | ||
| '#999999', | ||
| '#FFFFFF', | ||
| '#F44E3B', | ||
| '#FE9200', | ||
| '#FCDC00', | ||
| '#DBDF00', | ||
| '#A4DD00', | ||
| '#68CCCA', | ||
| '#73D8FF', | ||
| '#AEA1FF', | ||
| '#FDA1FF', | ||
| '#333333', | ||
| '#808080', | ||
| '#cccccc', | ||
| '#D33115', | ||
| '#E27300', | ||
| '#FCC400', | ||
| '#B0BC00', | ||
| '#68BC00', | ||
| '#16A5A5', | ||
| '#009CE0', | ||
| '#7B64FF', | ||
| '#FA28FF', | ||
| '#000000', | ||
| '#666666', | ||
| '#B3B3B3', | ||
| '#9F0500', | ||
| '#C45100', | ||
| '#FB9E00', | ||
| '#808900', | ||
| '#194D33', | ||
| '#0C797D', | ||
| '#0062B1', | ||
| '#653294', | ||
| '#AB149E', | ||
| ], | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const styles = merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| Compact: { | ||
| background: '#f6f6f6', | ||
| 'border-radius': '4px', | ||
| }, | ||
| compact: { | ||
| 'padding-top': '5px', | ||
| 'padding-left': '5px', | ||
| 'box-sizing': 'initial', | ||
| width: '240px', | ||
| }, | ||
| clear: { | ||
| clear: 'both', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| const handleChange = (data: any, e: Event) => { | ||
| if (data.hex) { | ||
| color.isValidHex(data.hex) && | ||
| changeColor( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else { | ||
| changeColor(data, e) | ||
| } | ||
| } | ||
| return ( | ||
| <Raised styles={props.styles}> | ||
| <div style={styles.compact} class={`compact-picker ${props.className}`}> | ||
| <div> | ||
| <For each={props.colors}> | ||
| {(c) => ( | ||
| <CompactColor | ||
| color={c} | ||
| active={c.toLowerCase() === currentColors().hex} | ||
| onClick={handleChange} | ||
| /> | ||
| )} | ||
| </For> | ||
| <div style={styles.clear} /> | ||
| </div> | ||
| <CompactFields | ||
| hex={currentColors().hex} | ||
| rgb={currentColors().rgb} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </Raised> | ||
| ) | ||
| } | ||
| export default withColorPicker(Compact) |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { getContrastingColor } from '../../helpers/color' | ||
| import { Swatch } from '../_common' | ||
| interface Props { | ||
| color: string | ||
| active: boolean | ||
| onClick: any | ||
| } | ||
| export default function CompactColor(_props: Props) { | ||
| const props = mergeProps({ onClick: () => {} }, _props) | ||
| const styles = () => { | ||
| const { color, active } = props | ||
| return { | ||
| color: { | ||
| background: color, | ||
| width: '15px', | ||
| height: '15px', | ||
| float: 'left', | ||
| 'margin-right': '5px', | ||
| 'margin-bottom': '5px', | ||
| position: 'relative', | ||
| cursor: 'pointer', | ||
| 'box-shadow': color === '#FFFFFF' ? 'inset 0 0 0 1px #ddd' : undefined, | ||
| }, | ||
| dot: { | ||
| position: 'absolute', | ||
| inset: '5px', | ||
| background: | ||
| color === '#FFFFFF' | ||
| ? '#000' | ||
| : color === 'transparent' | ||
| ? '#000' | ||
| : getContrastingColor(color), | ||
| 'border-radius': '50%', | ||
| opacity: active ? 1 : 0, | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <Swatch | ||
| styles={styles().color} | ||
| color={props.color} | ||
| onClick={props.onClick} | ||
| focusStyle={{ 'box-shadow': `0 0 4px ${props.color}` }} | ||
| > | ||
| <div style={styles().dot} /> | ||
| </Swatch> | ||
| ) | ||
| } |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { HexColor, RgbColor } from '../../types' | ||
| import { EditableInput } from '../_common' | ||
| interface Props { | ||
| hex: HexColor | ||
| rgb: RgbColor | ||
| onChange: any | ||
| } | ||
| export default function CompactFields(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles = () => { | ||
| const hex = props.hex | ||
| return { | ||
| fields: { | ||
| display: 'flex', | ||
| 'padding-bottom': '6px', | ||
| 'padding-right': '5px', | ||
| position: 'relative', | ||
| }, | ||
| active: { | ||
| position: 'absolute', | ||
| top: '6px', | ||
| left: '5px', | ||
| height: '9px', | ||
| width: '9px', | ||
| background: hex, | ||
| }, | ||
| hexWrap: { | ||
| flex: '6', | ||
| position: 'relative', | ||
| }, | ||
| hexInput: { | ||
| width: '80%', | ||
| padding: '0px', | ||
| 'padding-left': '20%', | ||
| border: 'none', | ||
| outline: 'none', | ||
| background: 'none', | ||
| 'font-size': '12px', | ||
| color: '#333', | ||
| height: '16px', | ||
| }, | ||
| hexLabel: { | ||
| display: 'none', | ||
| }, | ||
| rgbWrap: { | ||
| flex: '3', | ||
| position: 'relative', | ||
| }, | ||
| rgbInput: { | ||
| width: '70%', | ||
| padding: '0px', | ||
| 'padding-left': '30%', | ||
| border: 'none', | ||
| outline: 'none', | ||
| background: 'none', | ||
| 'font-size': '12px', | ||
| color: '#333', | ||
| height: '16px', | ||
| }, | ||
| rgbLabel: { | ||
| position: 'absolute', | ||
| top: '3px', | ||
| left: '0px', | ||
| 'line-height': '16px', | ||
| 'text-transform': 'uppercase', | ||
| 'font-size': '12px', | ||
| color: '#999', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| const handleChange = (data: any, e: Event) => { | ||
| if (data.r || data.g || data.b) { | ||
| props.onChange( | ||
| { | ||
| r: data.r || props.rgb.r, | ||
| g: data.g || props.rgb.g, | ||
| b: data.b || props.rgb.b, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else { | ||
| props.onChange( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| return ( | ||
| <div style={styles().fields} class="flexbox-fix"> | ||
| <div style={styles().active} /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().hexWrap, | ||
| input: styles().hexInput, | ||
| label: styles().hexLabel, | ||
| }} | ||
| label="hex" | ||
| value={props.hex} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="r" | ||
| value={props.rgb.r} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="g" | ||
| value={props.rgb.g} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="b" | ||
| value={props.rgb.b} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| ) | ||
| } |
| export { default as CompactPicker } from './Compact' | ||
| export type { CompactPickerProps } from './Compact' |
| import { merge } from 'lodash-es' | ||
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import { HexColor } from '../../types' | ||
| import { useColorPicker, withColorPicker } from '../_common' | ||
| import GithubSwatch from './GithubSwatch' | ||
| export type GithubPickerProps = { | ||
| width?: string | number | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| triangle?: 'hide' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | ||
| colors?: string[] | ||
| } | ||
| export function Github(_props: GithubPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 200, | ||
| colors: [ | ||
| '#B80000', | ||
| '#DB3E00', | ||
| '#FCCB00', | ||
| '#008B02', | ||
| '#006B76', | ||
| '#1273DE', | ||
| '#004DCF', | ||
| '#5300EB', | ||
| '#EB9694', | ||
| '#FAD0C3', | ||
| '#FEF3BD', | ||
| '#C1E1C5', | ||
| '#BEDADC', | ||
| '#C4DEF6', | ||
| '#BED3F3', | ||
| '#D4C4FB', | ||
| ], | ||
| triangle: 'top-left', | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| const { triangle } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| card: { | ||
| width, | ||
| background: '#fff', | ||
| border: '1px solid rgba(0,0,0,0.2)', | ||
| 'box-shadow': '0 3px 12px rgba(0,0,0,0.15)', | ||
| 'border-radius': '4px', | ||
| position: 'relative', | ||
| padding: '5px', | ||
| display: 'flex', | ||
| 'flex-wrap': 'wrap', | ||
| }, | ||
| triangle: { | ||
| position: 'absolute', | ||
| border: '7px solid transparent', | ||
| 'border-bottom-color': '#fff', | ||
| display: triangle === 'hide' ? 'none' : undefined, | ||
| top: triangle === 'top-left' || triangle === 'top-right' ? '-14px' : '37px', | ||
| left: triangle === 'top-left' || triangle === 'bottom-left' ? '10px' : undefined, | ||
| right: triangle === 'top-right' || triangle === 'bottom-right' ? '10px' : undefined, | ||
| transform: | ||
| triangle === 'bottom-left' || triangle === 'bottom-right' | ||
| ? 'rotate(180deg)' | ||
| : undefined, | ||
| }, | ||
| triangleShadow: { | ||
| position: 'absolute', | ||
| border: '8px solid transparent', | ||
| 'border-bottom-color': 'rgba(0,0,0,0.15)', | ||
| display: triangle === 'hide' ? 'none' : undefined, | ||
| top: triangle === 'top-left' || triangle === 'top-right' ? '-16px' : '35px', | ||
| left: triangle === 'top-left' || triangle === 'bottom-left' ? '9px' : undefined, | ||
| right: triangle === 'top-right' || triangle === 'bottom-right' ? '9px' : undefined, | ||
| transform: | ||
| triangle === 'bottom-left' || triangle === 'bottom-right' | ||
| ? 'rotate(180deg)' | ||
| : undefined, | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| const handleChange = (hex: HexColor, e: Event) => changeColor({ hex, source: 'hex' }, e) | ||
| return ( | ||
| <div style={styles().card} class={`github-picker ${props.className}`}> | ||
| <div style={styles().triangleShadow} /> | ||
| <div style={styles().triangle} /> | ||
| <For each={props.colors}>{(c) => <GithubSwatch color={c} onClick={handleChange} />}</For> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Github) |
| import { createSignal, JSX, mergeProps } from 'solid-js' | ||
| import { HexColor } from '../../types' | ||
| import { Swatch } from '../_common' | ||
| interface Props { | ||
| hover?: boolean | ||
| color: string | ||
| onClick?: (newColor: HexColor, event: Event) => void | ||
| } | ||
| export function GithubSwatch(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const hoverSwatch: JSX.CSSProperties = { | ||
| position: 'relative', | ||
| 'z-index': 2, | ||
| outline: '2px solid #fff', | ||
| 'box-shadow': '0 0 5px 2px rgba(0,0,0,0.25)', | ||
| } | ||
| const [hover, setHover] = createSignal(false) | ||
| const styles = () => { | ||
| return { | ||
| swatch: { | ||
| width: '25px', | ||
| height: '25px', | ||
| 'font-size': '0', | ||
| ...(hover() ? hoverSwatch : {}), | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div onMouseOver={() => setHover(true)} onMouseOut={() => setHover(false)}> | ||
| <div style={styles().swatch}> | ||
| <Swatch color={props.color} onClick={props.onClick} focusStyle={hoverSwatch} /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default GithubSwatch |
| export { default as GithubPicker } from './Github' | ||
| export type { GithubPickerProps } from './Github' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { Hue, Saturation, useColorPicker, withColorPicker } from '../_common' | ||
| import GoogleFields from './GoogleFields' | ||
| import GooglePointer from './GooglePointer' | ||
| import GooglePointerCircle from './GooglePointerCircle' | ||
| export type GooglePickerProps = { | ||
| width?: string | number | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| header?: string | ||
| className?: string | ||
| } | ||
| export function Google(_props: GooglePickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 652, | ||
| header: 'Color picker', | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| width, | ||
| background: '#fff', | ||
| border: '1px solid #dfe1e5', | ||
| 'box-sizing': 'initial', | ||
| display: 'flex', | ||
| 'flex-wrap': 'wrap', | ||
| 'border-radius': '8px 8px 0px 0px', | ||
| }, | ||
| head: { | ||
| height: '57px', | ||
| width: '100%', | ||
| 'padding-top': '16px', | ||
| 'padding-bottom': '16px', | ||
| 'padding-left': '16px', | ||
| 'font-size': '20px', | ||
| 'box-sizing': 'border-box', | ||
| 'font-family': 'Roboto-Regular,HelveticaNeue,Arial,sans-serif', | ||
| }, | ||
| saturation: { | ||
| width: '70%', | ||
| padding: '0px', | ||
| position: 'relative', | ||
| overflow: 'hidden', | ||
| }, | ||
| swatch: { | ||
| width: '30%', | ||
| height: '228px', | ||
| padding: '0px', | ||
| background: `rgba(${colors().rgb.r}, ${colors().rgb.g}, ${colors().rgb.b}, 1)`, | ||
| position: 'relative', | ||
| overflow: 'hidden', | ||
| }, | ||
| body: { | ||
| margin: 'auto', | ||
| width: '95%', | ||
| }, | ||
| controls: { | ||
| display: 'flex', | ||
| 'box-sizing': 'border-box', | ||
| height: '52px', | ||
| 'padding-top': '22px', | ||
| }, | ||
| color: { | ||
| width: '32px', | ||
| }, | ||
| hue: { | ||
| height: '8px', | ||
| position: 'relative', | ||
| margin: '0px 16px 0px 16px', | ||
| width: '100%', | ||
| }, | ||
| Hue: { | ||
| 'border-radius': '2px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().picker} class={`google-picker ${props.className}`}> | ||
| <div style={styles().head}>{props.header}</div> | ||
| <div style={styles().swatch} /> | ||
| <div style={styles().saturation}> | ||
| <Saturation | ||
| hsl={colors().hsl} | ||
| hsv={colors().hsv} | ||
| pointer={<GooglePointerCircle hsl={colors().hsl} />} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles().body}> | ||
| <div style={styles().controls} class="flexbox-fix"> | ||
| <div style={styles().hue}> | ||
| <Hue | ||
| styles={styles().Hue} | ||
| hsl={colors().hsl} | ||
| radius="4px" | ||
| pointer={GooglePointer} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| </div> | ||
| <GoogleFields | ||
| rgb={colors().rgb} | ||
| hsl={colors().hsl} | ||
| hex={colors().hex} | ||
| hsv={colors().hsv} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Google) |
| import { createEffect, createSignal, JSX, mergeProps } from 'solid-js' | ||
| import * as color from '../../helpers/color' | ||
| import { ChangeColor, HexColor, HslColor, HsvColor, RgbColor } from '../../types' | ||
| import { EditableInput } from '../_common' | ||
| interface Props { | ||
| rgb: RgbColor | ||
| hsl: HslColor | ||
| hex: HexColor | ||
| hsv: HsvColor | ||
| onChange: (color: ChangeColor, event: Event) => void | ||
| } | ||
| export default function GoogleFields(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const [rgbValue, setRgbValue] = createSignal('') | ||
| const [hslValue, setHslValue] = createSignal('') | ||
| const [hsvValue, setHsvValue] = createSignal('') | ||
| createEffect(() => { | ||
| setRgbValue(`${props.rgb.r}, ${props.rgb.g}, ${props.rgb.b}`) | ||
| setHslValue( | ||
| `${Math.round(props.hsl.h)}°, ${Math.round(props.hsl.s * 100)}%, ${Math.round( | ||
| props.hsl.l * 100, | ||
| )}%`, | ||
| ) | ||
| setHsvValue( | ||
| `${Math.round(props.hsv.h)}°, ${Math.round(props.hsv.s * 100)}%, ${Math.round( | ||
| props.hsv.v * 100, | ||
| )}%`, | ||
| ) | ||
| }, [props.rgb, props.hsl, props.hsv]) | ||
| const handleChange = (data: any, e: Event) => { | ||
| if (data.hex) { | ||
| color.isValidHex(data.hex) && | ||
| props.onChange( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.rgb) { | ||
| const values = data.rgb.split(',') | ||
| color.isvalidColorString(data.rgb, 'rgb') && | ||
| props.onChange( | ||
| { | ||
| r: values[0], | ||
| g: values[1], | ||
| b: values[2], | ||
| a: 1, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.hsv) { | ||
| const values = data.hsv.split(',') | ||
| if (color.isvalidColorString(data.hsv, 'hsv')) { | ||
| values[2] = values[2].replace('%', '') | ||
| values[1] = values[1].replace('%', '') | ||
| values[0] = values[0].replace('°', '') | ||
| if (values[1] == 1) { | ||
| values[1] = 0.01 | ||
| } else if (values[2] == 1) { | ||
| values[2] = 0.01 | ||
| } | ||
| props.onChange( | ||
| { | ||
| h: Number(values[0]), | ||
| s: Number(values[1]), | ||
| v: Number(values[2]), | ||
| source: 'hsv', | ||
| } as ChangeColor, | ||
| e, | ||
| ) | ||
| } | ||
| } else if (data.hsl) { | ||
| const values = data.hsl.split(',') | ||
| if (color.isvalidColorString(data.hsl, 'hsl')) { | ||
| values[2] = values[2].replace('%', '') | ||
| values[1] = values[1].replace('%', '') | ||
| values[0] = values[0].replace('°', '') | ||
| // @ts-ignore | ||
| if (props.hsvValue[1] == 1) { | ||
| // @ts-ignore | ||
| hsvValue[1] = 0.01 | ||
| // @ts-ignore | ||
| } else if (hsvValue[2] == 1) { | ||
| // @ts-ignore | ||
| hsvValue[2] = 0.01 | ||
| } | ||
| props.onChange( | ||
| { | ||
| h: Number(values[0]), | ||
| s: Number(values[1]), | ||
| v: Number(values[2]), | ||
| source: 'hsl', | ||
| } as ChangeColor, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| wrap: { | ||
| display: 'flex', | ||
| height: '100px', | ||
| 'margin-top': '4px', | ||
| }, | ||
| fields: { | ||
| width: '100%', | ||
| }, | ||
| column: { | ||
| 'padding-top': '10px', | ||
| display: 'flex', | ||
| 'justify-content': 'space-between', | ||
| }, | ||
| double: { | ||
| padding: '0px 4.4px', | ||
| 'box-sizing': 'border-box', | ||
| }, | ||
| input: { | ||
| width: '100%', | ||
| height: '38px', | ||
| 'box-sizing': 'border-box', | ||
| padding: '4px 10% 3px', | ||
| 'text-align': 'center', | ||
| border: '1px solid #dadce0', | ||
| 'font-size': '11px', | ||
| 'text-transform': 'lowercase', | ||
| 'border-radius': '5px', | ||
| outline: 'none', | ||
| 'font-family': 'Roboto,Arial,sans-serif', | ||
| }, | ||
| input2: { | ||
| height: '38px', | ||
| width: '100%', | ||
| border: '1px solid #dadce0', | ||
| 'box-sizing': 'border-box', | ||
| 'font-size': '11px', | ||
| 'text-transform': 'lowercase', | ||
| 'border-radius': '5px', | ||
| outline: 'none', | ||
| 'padding-left': '10px', | ||
| 'font-family': 'Roboto,Arial,sans-serif', | ||
| }, | ||
| label: { | ||
| 'text-align': 'center', | ||
| 'font-size': '12px', | ||
| background: '#fff', | ||
| position: 'absolute', | ||
| 'text-transform': 'uppercase', | ||
| color: '#3c4043', | ||
| width: '35px', | ||
| top: '-6px', | ||
| left: '0', | ||
| right: '0', | ||
| 'margin-left': 'auto', | ||
| 'margin-right': 'auto', | ||
| 'font-family': 'Roboto,Arial,sans-serif', | ||
| }, | ||
| label2: { | ||
| left: '10px', | ||
| 'text-align': 'center', | ||
| 'font-size': '12px', | ||
| background: '#fff', | ||
| position: 'absolute', | ||
| 'text-transform': 'uppercase', | ||
| color: '#3c4043', | ||
| width: '32px', | ||
| top: '-6px', | ||
| 'font-family': 'Roboto,Arial,sans-serif', | ||
| }, | ||
| single: { | ||
| 'flex-grow': 1, | ||
| margin: '0px 4.4px', | ||
| }, | ||
| } | ||
| return ( | ||
| <div style={styles.wrap} class="flexbox-fix"> | ||
| <div style={styles.fields}> | ||
| <div style={styles.double}> | ||
| <EditableInput | ||
| styles={{ input: styles.input, label: styles.label }} | ||
| label="hex" | ||
| value={props.hex} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles.column}> | ||
| <div style={styles.single}> | ||
| <EditableInput | ||
| styles={{ input: styles.input2, label: styles.label2 }} | ||
| label="rgb" | ||
| value={rgbValue()} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles.single}> | ||
| <EditableInput | ||
| styles={{ input: styles.input2, label: styles.label2 }} | ||
| label="hsv" | ||
| value={hsvValue()} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles.single}> | ||
| <EditableInput | ||
| styles={{ input: styles.input2, label: styles.label2 }} | ||
| label="hsl" | ||
| value={hslValue()} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import { mergeProps } from 'solid-js' | ||
| import { HslColor } from '../../types' | ||
| interface Props { | ||
| hsl?: HslColor | ||
| } | ||
| export default function GooglePointer(_props: Props) { | ||
| const props = mergeProps({ hsl: { a: 1, h: 249.94, l: 0.2, s: 0.5 } }, _props) | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '20px', | ||
| height: '20px', | ||
| 'border-radius': '22px', | ||
| transform: 'translate(-10px, -7px)', | ||
| background: `hsl(${Math.round(props.hsl.h)}, 100%, 50%)`, | ||
| border: '2px white solid', | ||
| }} | ||
| /> | ||
| ) | ||
| } |
| import { mergeProps } from 'solid-js' | ||
| import { HslColor } from '../../types' | ||
| interface Props { | ||
| hsl?: HslColor | ||
| } | ||
| export default function GooglePointerCircle(_props: Props) { | ||
| const props = mergeProps({ hsl: { a: 1, h: 249.94, l: 0.2, s: 0.5 } }, _props) | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '20px', | ||
| height: '20px', | ||
| 'border-radius': '22px', | ||
| border: '2px #fff solid', | ||
| transform: 'translate(-12px, -13px)', | ||
| background: `hsl(${Math.round(props.hsl.h)}, ${Math.round( | ||
| props.hsl.s * 100, | ||
| )}%, ${Math.round(props.hsl.l * 100)}%)`, | ||
| }} | ||
| /> | ||
| ) | ||
| } |
| export { default as GooglePicker } from './Google' | ||
| export type { GooglePickerProps } from './Google' |
| import { useColorPicker, withColorPicker } from '../_common/ColorPicker' | ||
| import { ChangeColor } from '../../types' | ||
| import { Hue } from '../_common' | ||
| import HuePointer from './HuePointer' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { merge } from 'lodash-es' | ||
| export type HuePickerProps = { | ||
| width?: string | number | ||
| height?: string | number | ||
| direction?: string | ||
| pointer?: typeof HuePointer | ||
| className?: string | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| } | ||
| export function HuePicker(_props: HuePickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: '316px', | ||
| height: '16px', | ||
| direction: 'horizontal', | ||
| pointer: HuePointer, | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| position: 'relative', | ||
| width: props.width, | ||
| height: props.height, | ||
| }, | ||
| hue: { | ||
| 'border-radius': '2px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| // Overwrite to provide pure hue color | ||
| const handleChange = (data: ChangeColor) => | ||
| changeColor({ | ||
| a: 1, | ||
| h: typeof data !== 'string' && 'h' in data ? data.h : 0, | ||
| l: 0.5, | ||
| s: 1, | ||
| }) | ||
| return ( | ||
| <div style={styles.picker} class={`hue-picker ${props.className}`}> | ||
| <Hue | ||
| {...styles.hue} | ||
| hsl={colors().hsl} | ||
| pointer={props.pointer} | ||
| direction={props.direction} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(HuePicker) |
| import { JSX } from 'solid-js' | ||
| interface Props { | ||
| direction?: string | ||
| } | ||
| export default function SliderPointer({ direction }: Props) { | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| picker: { | ||
| width: '18px', | ||
| height: '18px', | ||
| 'border-radius': '50%', | ||
| transform: direction === 'vertical' ? 'translate(-3px, -9px)' : 'translate(-9px, -1px)', | ||
| 'background-color': 'rgb(248, 248, 248)', | ||
| 'box-shadow': '0 1px 4px 0 rgba(0, 0, 0, 0.37)', | ||
| }, | ||
| } | ||
| return <div style={styles.picker} /> | ||
| } |
| export { default as HuePicker } from './Hue' | ||
| export type { HuePickerProps } from './Hue' |
| export { default as MaterialPicker } from './Material' | ||
| export type { MaterialPickerProps } from './Material' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { ChangeColor, RgbColor } from '../../types' | ||
| import { EditableInput, Raised } from '../_common' | ||
| import { useColorPicker, withColorPicker } from '../_common/ColorPicker' | ||
| import { isValidHex } from '../../helpers/color' | ||
| export type MaterialPickerProps = { | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| } | ||
| export function Material(_props: MaterialPickerProps) { | ||
| const props = mergeProps({ styles: {}, className: '' }, _props) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| material: { | ||
| width: '98px', | ||
| height: '98px', | ||
| padding: '16px', | ||
| 'font-family': 'Roboto', | ||
| }, | ||
| hexWrap: { | ||
| position: 'relative', | ||
| }, | ||
| hexInput: { | ||
| width: '100%', | ||
| 'margin-top': '12px', | ||
| 'font-size': '15px', | ||
| color: '#333', | ||
| padding: '0px', | ||
| border: '0px', | ||
| 'border-bottom': `2px solid ${colors().hex}`, | ||
| outline: 'none', | ||
| height: '30px', | ||
| }, | ||
| hexLabel: { | ||
| position: 'absolute', | ||
| top: '0px', | ||
| left: '0px', | ||
| 'font-size': '11px', | ||
| color: '#999999', | ||
| 'text-transform': 'capitalize', | ||
| }, | ||
| hex: {}, | ||
| rgbWrap: { | ||
| position: 'relative', | ||
| }, | ||
| rgbInput: { | ||
| width: '100%', | ||
| 'margin-top': '12px', | ||
| 'font-size': '15px', | ||
| color: '#333', | ||
| padding: '0px', | ||
| border: '0px', | ||
| 'border-bottom': '1px solid #eee', | ||
| outline: 'none', | ||
| height: '30px', | ||
| }, | ||
| rgbLabel: { | ||
| position: 'absolute', | ||
| top: '0px', | ||
| left: '0px', | ||
| 'font-size': '11px', | ||
| color: '#999999', | ||
| 'text-transform': 'capitalize', | ||
| }, | ||
| split: { | ||
| display: 'flex', | ||
| 'margin-right': '-10px', | ||
| 'padding-top': '11px', | ||
| }, | ||
| third: { | ||
| flex: '1', | ||
| 'padding-right': '10px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| const handleChange = (data: ChangeColor, e: Event) => { | ||
| if (typeof data !== 'string' && 'hex' in data) { | ||
| isValidHex(data.hex) && | ||
| changeColor( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (typeof data !== 'string' && ('r' in data || 'g' in data || 'b' in data)) { | ||
| data = data as unknown as RgbColor | ||
| changeColor( | ||
| { | ||
| r: data.r || colors().rgb.r, | ||
| g: data.g || colors().rgb.g, | ||
| b: data.b || colors().rgb.b, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| return ( | ||
| <Raised styles={props.styles}> | ||
| <div style={styles().material} class={`material-picker ${props.className}`}> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().hexWrap, | ||
| input: styles().hexInput, | ||
| label: styles().hexLabel, | ||
| }} | ||
| label="hex" | ||
| value={colors().hex} | ||
| onChange={handleChange} | ||
| /> | ||
| <div style={styles().split} class="flexbox-fix"> | ||
| <div style={styles().third}> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="r" | ||
| value={colors().rgb.r} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().third}> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="g" | ||
| value={colors().rgb.g} | ||
| /> | ||
| </div> | ||
| <div style={styles().third}> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles().rgbWrap, | ||
| input: styles().rgbInput, | ||
| label: styles().rgbLabel, | ||
| }} | ||
| label="b" | ||
| value={colors().rgb.b} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </Raised> | ||
| ) | ||
| } | ||
| export default withColorPicker(Material) |
| export { default as PhotoshopPicker } from './Photoshop' | ||
| export type { PhotoshopPickerProps } from './Photoshop' |
| import { merge } from 'lodash-es' | ||
| import { createSignal, JSX, mergeProps } from 'solid-js' | ||
| import { Hue, Saturation, useColorPicker, withColorPicker } from '../_common' | ||
| import PhotoshopButton from './PhotoshopButton' | ||
| import PhotoshopFields from './PhotoshopFields' | ||
| import PhotoshopPointer from './PhotoshopPointer' | ||
| import PhotoshopPointerCircle from './PhotoshopPointerCircle' | ||
| import PhotoshopPreviews from './PhotoshopPreviews' | ||
| export type PhotoshopPickerProps = { | ||
| header?: string | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| onAccept?: () => void | ||
| onCancel?: () => void | ||
| } | ||
| function Photoshop(_props: PhotoshopPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| header: 'Color Picker', | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const [currentColor, setCurrentColor] = createSignal(colors().hex) | ||
| const styles = merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| background: '#DCDCDC', | ||
| 'border-radius': '4px', | ||
| 'box-shadow': '0 0 0 1px rgba(0,0,0,.25), 0 8px 16px rgba(0,0,0,.15)', | ||
| 'box-sizing': 'initial', | ||
| width: '513px', | ||
| }, | ||
| head: { | ||
| 'background-image': 'linear-gradient(-180deg, #F0F0F0 0%, #D4D4D4 100%)', | ||
| 'border-bottom': '1px solid #B1B1B1', | ||
| 'box-shadow': 'inset 0 1px 0 0 rgba(255,255,255,.2), inset 0 -1px 0 0 rgba(0,0,0,.02)', | ||
| height: '23px', | ||
| 'line-height': '24px', | ||
| 'border-radius': '4px 4px 0 0', | ||
| 'font-size': '13px', | ||
| color: '#4D4D4D', | ||
| 'text-align': 'center', | ||
| }, | ||
| body: { | ||
| padding: '15px 15px 0', | ||
| display: 'flex', | ||
| }, | ||
| saturation: { | ||
| width: '256px', | ||
| height: '256px', | ||
| position: 'relative', | ||
| border: '2px solid #B3B3B3', | ||
| 'border-bottom': '2px solid #F0F0F0', | ||
| overflow: 'hidden', | ||
| }, | ||
| hue: { | ||
| position: 'relative', | ||
| height: '256px', | ||
| width: '19px', | ||
| 'margin-left': '10px', | ||
| border: '2px solid #B3B3B3', | ||
| 'border-bottom': '2px solid #F0F0F0', | ||
| }, | ||
| controls: { | ||
| width: '180px', | ||
| 'margin-left': '10px', | ||
| }, | ||
| top: { | ||
| display: 'flex', | ||
| }, | ||
| previews: { | ||
| width: '60px', | ||
| }, | ||
| actions: { | ||
| flex: '1', | ||
| 'margin-left': '20px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| function handleAccept() { | ||
| props.onAccept && props.onAccept() | ||
| setCurrentColor(colors().hex) | ||
| } | ||
| return ( | ||
| <div style={styles.picker} class={`photoshop-picker ${props.className}`}> | ||
| <div style={styles.head}>{props.header}</div> | ||
| <div style={styles.body} class="flexbox-fix"> | ||
| <div style={styles.saturation}> | ||
| <Saturation | ||
| hsl={colors().hsl} | ||
| hsv={colors().hsv} | ||
| pointer={<PhotoshopPointerCircle hsl={colors().hsl} />} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles.hue}> | ||
| <Hue | ||
| direction="vertical" | ||
| hsl={colors().hsl} | ||
| pointer={PhotoshopPointer} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles.controls}> | ||
| <div style={styles.top} class="flexbox-fix"> | ||
| <div style={styles.previews}> | ||
| <PhotoshopPreviews rgb={colors().rgb} currentColor={currentColor()} /> | ||
| </div> | ||
| <div style={styles.actions}> | ||
| <PhotoshopButton label="OK" onClick={handleAccept} active /> | ||
| <PhotoshopButton label="Cancel" onClick={props.onCancel} /> | ||
| <PhotoshopFields | ||
| onChange={changeColor} | ||
| rgb={colors().rgb} | ||
| hsv={colors().hsv} | ||
| hex={colors().hex} | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Photoshop) |
| import { JSX, mergeProps } from 'solid-js' | ||
| interface Props { | ||
| onClick?: () => void | ||
| label?: string | ||
| children?: JSX.Element | ||
| active?: boolean | ||
| } | ||
| export default function PhotoshopButton(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles = () => { | ||
| return { | ||
| button: { | ||
| 'background-image': 'linear-gradient(-180deg, #FFFFFF 0%, #E6E6E6 100%)', | ||
| border: '1px solid #878787', | ||
| 'border-radius': '2px', | ||
| height: '20px', | ||
| 'box-shadow': props.active ? '0 0 0 1px #878787' : '0 1px 0 0 #EAEAEA', | ||
| 'font-size': '14px', | ||
| color: '#000', | ||
| 'line-height': '20px', | ||
| 'text-align': 'center', | ||
| 'margin-bottom': '10px', | ||
| cursor: 'pointer', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div style={styles().button} onClick={props.onClick}> | ||
| {props.label || props.children} | ||
| </div> | ||
| ) | ||
| } |
| import { JSX, mergeProps } from 'solid-js' | ||
| import * as color from '../../helpers/color' | ||
| import { HexColor, HsvColor, RgbColor } from '../../types' | ||
| import { EditableInput } from '../_common' | ||
| interface Props { | ||
| rgb: RgbColor | ||
| hsv: HsvColor | ||
| hex: HexColor | ||
| onChange: (data: any, event: Event) => void | ||
| } | ||
| export default function PhotoshopPicker(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| fields: { | ||
| 'padding-top': '5px', | ||
| 'padding-bottom': '9px', | ||
| width: '80px', | ||
| position: 'relative', | ||
| }, | ||
| divider: { | ||
| height: '5px', | ||
| }, | ||
| rgbWrap: { | ||
| position: 'relative', | ||
| }, | ||
| rgbInput: { | ||
| 'margin-left': '40%', | ||
| width: '40%', | ||
| height: '18px', | ||
| border: '1px solid #888888', | ||
| 'box-shadow': 'inset 0 1px 1px rgba(0,0,0,.1), 0 1px 0 0 #ECECEC', | ||
| 'margin-bottom': '5px', | ||
| 'font-size': '13px', | ||
| 'padding-left': '3px', | ||
| 'margin-right': '10px', | ||
| }, | ||
| rgbLabel: { | ||
| left: '0px', | ||
| top: '0px', | ||
| width: '34px', | ||
| 'text-transform': 'uppercase', | ||
| 'font-size': '13px', | ||
| height: '18px', | ||
| 'line-height': '22px', | ||
| position: 'absolute', | ||
| }, | ||
| hexWrap: { | ||
| position: 'relative', | ||
| }, | ||
| hexInput: { | ||
| 'margin-left': '20%', | ||
| width: '80%', | ||
| height: '18px', | ||
| border: '1px solid #888888', | ||
| 'box-shadow': 'inset 0 1px 1px rgba(0,0,0,.1), 0 1px 0 0 #ECECEC', | ||
| 'margin-bottom': '6px', | ||
| 'font-size': '13px', | ||
| 'padding-left': '3px', | ||
| }, | ||
| hexLabel: { | ||
| position: 'absolute', | ||
| top: '0px', | ||
| left: '0px', | ||
| width: '14px', | ||
| 'text-transform': 'uppercase', | ||
| 'font-size': '13px', | ||
| height: '18px', | ||
| 'line-height': '22px', | ||
| }, | ||
| fieldSymbols: { | ||
| position: 'absolute', | ||
| top: '5px', | ||
| right: '-7px', | ||
| 'font-size': '13px', | ||
| }, | ||
| symbol: { | ||
| height: '20px', | ||
| 'line-height': '22px', | ||
| 'padding-bottom': '7px', | ||
| }, | ||
| } | ||
| const handleChange = (data: any, e: Event) => { | ||
| if (data['#']) { | ||
| color.isValidHex(data['#']) && | ||
| props.onChange( | ||
| { | ||
| hex: data['#'], | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.r || data.g || data.b) { | ||
| props.onChange( | ||
| { | ||
| r: data.r || props.rgb.r, | ||
| g: data.g || props.rgb.g, | ||
| b: data.b || props.rgb.b, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (data.h || data.s || data.v) { | ||
| props.onChange( | ||
| { | ||
| h: data.h || props.hsv.h, | ||
| s: data.s || props.hsv.s, | ||
| v: data.v || props.hsv.v, | ||
| source: 'hsv', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| return ( | ||
| <div style={styles.fields}> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="h" | ||
| value={Math.round(props.hsv.h)} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="s" | ||
| value={Math.round(props.hsv.s * 100)} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="v" | ||
| value={Math.round(props.hsv.v * 100)} | ||
| onChange={handleChange} | ||
| /> | ||
| <div style={styles.divider} /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="r" | ||
| value={props.rgb.r} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="g" | ||
| value={props.rgb.g} | ||
| onChange={handleChange} | ||
| /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.rgbWrap, | ||
| input: styles.rgbInput, | ||
| label: styles.rgbLabel, | ||
| }} | ||
| label="b" | ||
| value={props.rgb.b} | ||
| onChange={handleChange} | ||
| /> | ||
| <div style={styles.divider} /> | ||
| <EditableInput | ||
| styles={{ | ||
| wrap: styles.hexWrap, | ||
| input: styles.hexInput, | ||
| label: styles.hexLabel, | ||
| }} | ||
| label="#" | ||
| value={props.hex.replace('#', '')} | ||
| onChange={handleChange} | ||
| /> | ||
| <div style={styles.fieldSymbols}> | ||
| <div style={styles.symbol}>°</div> | ||
| <div style={styles.symbol}>%</div> | ||
| <div style={styles.symbol}>%</div> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import { JSX } from 'solid-js' | ||
| export default function PhotoshopPointerCircle() { | ||
| const triangleStyles: JSX.CSSProperties = { | ||
| width: 0, | ||
| height: 0, | ||
| 'border-style': 'solid', | ||
| 'border-width': '4px 0 4px 6px', | ||
| 'border-color': 'transparent transparent transparent #fff', | ||
| position: 'absolute', | ||
| top: '1px', | ||
| left: '1px', | ||
| } | ||
| const triangleBorderStyles: JSX.CSSProperties = { | ||
| width: 0, | ||
| height: 0, | ||
| 'border-style': 'solid', | ||
| 'border-width': '5px 0 5px 8px', | ||
| 'border-color': 'transparent transparent transparent #555', | ||
| } | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| left: { | ||
| ...triangleBorderStyles, | ||
| transform: 'translate(-13px, -4px)', | ||
| }, | ||
| leftInside: { | ||
| ...triangleStyles, | ||
| transform: 'translate(-8px, -5px)', | ||
| }, | ||
| right: { | ||
| ...triangleBorderStyles, | ||
| transform: 'translate(20px, -14px) rotate(180deg)', | ||
| }, | ||
| rightInside: { | ||
| ...triangleStyles, | ||
| transform: 'translate(-8px, -5px)', | ||
| }, | ||
| } | ||
| return ( | ||
| <div style={styles.pointer}> | ||
| <div style={styles.left}> | ||
| <div style={styles.leftInside} /> | ||
| </div> | ||
| <div style={styles.right}> | ||
| <div style={styles.rightInside} /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } |
| import { mergeProps } from 'solid-js' | ||
| import { HslColor } from '../../types' | ||
| interface Props { | ||
| hsl: HslColor | ||
| } | ||
| export default function PhotoshopPointerCircle(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| return ( | ||
| <div | ||
| style={{ | ||
| width: '12px', | ||
| height: '12px', | ||
| borderRadius: '6px', | ||
| boxShadow: props.hsl.l > 0.5 ? 'inset 0 0 0 1px #000' : 'inset 0 0 0 1px #fff', | ||
| transform: 'translate(-6px, -6px)', | ||
| }} | ||
| /> | ||
| ) | ||
| } |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { RgbColor } from '../../types' | ||
| interface Props { | ||
| rgb: RgbColor | ||
| currentColor: string | ||
| } | ||
| export default function PhotoshopPreviews(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles = () => { | ||
| const { rgb, currentColor } = props | ||
| return { | ||
| swatches: { | ||
| border: '1px solid #B3B3B3', | ||
| 'border-bottom': '1px solid #F0F0F0', | ||
| 'margin-bottom': '2px', | ||
| 'margin-top': '1px', | ||
| }, | ||
| new: { | ||
| height: '34px', | ||
| background: `rgb(${rgb.r},${rgb.g}, ${rgb.b})`, | ||
| 'box-shadow': 'inset 1px 0 0 #000, inset -1px 0 0 #000, inset 0 1px 0 #000', | ||
| }, | ||
| current: { | ||
| height: '34px', | ||
| background: currentColor, | ||
| 'box-shadow': 'inset 1px 0 0 #000, inset -1px 0 0 #000, inset 0 -1px 0 #000', | ||
| }, | ||
| label: { | ||
| 'font-size': '14px', | ||
| color: '#000', | ||
| 'text-align': 'center', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <div> | ||
| <div style={styles().label}>new</div> | ||
| <div style={styles().swatches}> | ||
| <div style={styles().new} /> | ||
| <div style={styles().current} /> | ||
| </div> | ||
| <div style={styles().label}>current</div> | ||
| </div> | ||
| ) | ||
| } |
| export { default as SketchPicker } from './Sketch' | ||
| export type { SketchPickerProps } from './Sketch' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { Alpha, Checkboard, Hue, Saturation, useColorPicker, withColorPicker } from '../_common' | ||
| import SketchFields from './SketchFields' | ||
| import SketchPresetColors from './SketchPresetColors' | ||
| export type SketchPickerProps = { | ||
| disableAlpha?: boolean | ||
| width?: string | number | ||
| className?: string | ||
| presetColors?: string[] | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| renderers?: any | ||
| } | ||
| export function Sketch(_props: SketchPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 200, | ||
| disableAlpha: false, | ||
| presetColors: [ | ||
| '#D0021B', | ||
| '#F5A623', | ||
| '#F8E71C', | ||
| '#8B572A', | ||
| '#7ED321', | ||
| '#417505', | ||
| '#BD10E0', | ||
| '#9013FE', | ||
| '#4A90E2', | ||
| '#50E3C2', | ||
| '#B8E986', | ||
| '#000000', | ||
| '#4A4A4A', | ||
| '#9B9B9B', | ||
| '#FFFFFF', | ||
| ], | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| const rgb = colors().rgb | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| width, | ||
| padding: '10px 10px 0', | ||
| 'box-sizing': 'initial', | ||
| background: '#fff', | ||
| 'border-radius': '4px', | ||
| 'box-shadow': '0 0 0 1px rgba(0,0,0,.15), 0 8px 16px rgba(0,0,0,.15)', | ||
| }, | ||
| saturation: { | ||
| width: '100%', | ||
| 'padding-bottom': '75%', | ||
| position: 'relative', | ||
| overflow: 'hidden', | ||
| }, | ||
| Saturation: { | ||
| 'border-radius': '3px', | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25)', | ||
| }, | ||
| controls: { | ||
| display: 'flex', | ||
| }, | ||
| sliders: { | ||
| padding: '4px 0', | ||
| flex: '1', | ||
| }, | ||
| color: { | ||
| width: '24px', | ||
| height: props.disableAlpha ? '10px' : '24px', | ||
| position: 'relative', | ||
| 'margin-top': '4px', | ||
| 'margin-left': '4px', | ||
| 'border-radius': '3px', | ||
| }, | ||
| activeColor: { | ||
| position: 'absolute', | ||
| inset: '0px', | ||
| 'border-radius': '2px', | ||
| background: `rgba(${rgb.r},${rgb.g},${rgb.b},${rgb.a})`, | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25)', | ||
| }, | ||
| hue: { | ||
| position: 'relative', | ||
| height: '10px', | ||
| overflow: 'hidden', | ||
| }, | ||
| Hue: { | ||
| 'border-radius': '2px', | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25)', | ||
| }, | ||
| alpha: { | ||
| position: 'relative', | ||
| height: '10px', | ||
| 'margin-top': '4px', | ||
| overflow: 'hidden', | ||
| display: props.disableAlpha ? 'none' : undefined, | ||
| }, | ||
| Alpha: { | ||
| 'border-radius': '2px', | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25)', | ||
| }, | ||
| ...props.styles, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().picker} class={`sketch-picker ${props.className}`}> | ||
| <div style={styles().saturation}> | ||
| <Saturation | ||
| styles={styles().Saturation} | ||
| hsl={colors().hsl} | ||
| hsv={colors().hsv} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| <div style={styles().controls} class="flexbox-fix"> | ||
| <div style={styles().sliders}> | ||
| <div style={styles().hue}> | ||
| <Hue styles={styles().Hue} hsl={colors().hsl} onChange={changeColor} /> | ||
| </div> | ||
| <div style={styles().alpha}> | ||
| <Alpha | ||
| direction="horizontal" | ||
| styles={styles().Alpha} | ||
| rgb={colors().rgb} | ||
| hsl={colors().hsl} | ||
| renderers={props.renderers} | ||
| onChange={changeColor} | ||
| /> | ||
| </div> | ||
| </div> | ||
| <div style={styles().color}> | ||
| <Checkboard /> | ||
| <div style={styles().activeColor} /> | ||
| </div> | ||
| </div> | ||
| <SketchFields | ||
| rgb={colors().rgb} | ||
| hsl={colors().hsl} | ||
| hex={colors().hex} | ||
| onChange={changeColor} | ||
| disableAlpha={props.disableAlpha} | ||
| /> | ||
| <SketchPresetColors colors={props.presetColors} onClick={changeColor} /> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Sketch) |
| import { JSX, mergeProps } from 'solid-js' | ||
| import * as color from '../../helpers/color' | ||
| import { ChangeColor, HexColor, HslColor, RgbColor } from '../../types' | ||
| import { EditableInput } from '../_common' | ||
| export interface SliderPickerProps { | ||
| onChange?: (color: ChangeColor, event: Event) => void | ||
| rgb: RgbColor | ||
| hsl: HslColor | ||
| hex: HexColor | ||
| disableAlpha?: boolean | ||
| } | ||
| export const SketchFields = (_props: SliderPickerProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| onChange: () => {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| const styles = () => { | ||
| return { | ||
| fields: { | ||
| display: 'flex', | ||
| 'padding-top': '4px', | ||
| }, | ||
| single: { | ||
| flex: '1', | ||
| 'padding-left': '6px', | ||
| }, | ||
| alpha: { | ||
| flex: '1', | ||
| 'padding-left': '6px', | ||
| display: props.disableAlpha ? 'none' : undefined, | ||
| }, | ||
| double: { | ||
| flex: '2', | ||
| }, | ||
| input: { | ||
| width: '80%', | ||
| padding: '4px 10% 3px', | ||
| border: 'none', | ||
| 'box-shadow': 'inset 0 0 0 1px #ccc', | ||
| 'font-size': '11px', | ||
| }, | ||
| label: { | ||
| display: 'block', | ||
| 'text-align': 'center', | ||
| 'font-size': '11px', | ||
| color: '#222', | ||
| 'padding-top': '3px', | ||
| 'padding-bottom': '4px', | ||
| 'text-transform': 'capitalize', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| const handleChange = (data: any, e: Event) => { | ||
| if (typeof data !== 'string' && 'hex' in data) { | ||
| color.isValidHex(data.hex) && | ||
| props.onChange( | ||
| { | ||
| hex: data.hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (typeof data !== 'string' && ('r' in data || 'g' in data || 'b' in data)) { | ||
| props.onChange( | ||
| { | ||
| r: data.r || props.rgb.r, | ||
| g: data.g || props.rgb.g, | ||
| b: data.b || props.rgb.b, | ||
| a: props.rgb.a, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } else if (typeof data !== 'string' && data.a) { | ||
| if (data.a < 0) { | ||
| data.a = 0 | ||
| } else if (data.a > 100) { | ||
| data.a = 100 | ||
| } | ||
| data.a /= 100 | ||
| props.onChange( | ||
| { | ||
| h: props.hsl.h, | ||
| s: props.hsl.s, | ||
| l: props.hsl.l, | ||
| a: data.a, | ||
| source: 'rgb', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| } | ||
| return ( | ||
| <div style={styles().fields} class="flexbox-fix"> | ||
| <div style={styles().double}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="hex" | ||
| value={props.hex.replace('#', '')} | ||
| onChange={handleChange} | ||
| /> | ||
| </div> | ||
| <div style={styles().single}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="r" | ||
| value={props.rgb.r} | ||
| onChange={handleChange} | ||
| dragLabel={true} | ||
| dragMax={255} | ||
| /> | ||
| </div> | ||
| <div style={styles().single}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="g" | ||
| value={props.rgb.g} | ||
| onChange={handleChange} | ||
| dragLabel={true} | ||
| dragMax={255} | ||
| /> | ||
| </div> | ||
| <div style={styles().single}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="b" | ||
| value={props.rgb.b} | ||
| onChange={handleChange} | ||
| dragLabel={true} | ||
| dragMax={255} | ||
| /> | ||
| </div> | ||
| <div style={styles().alpha}> | ||
| <EditableInput | ||
| styles={{ input: styles().input, label: styles().label }} | ||
| label="a" | ||
| value={Math.round((props.rgb.a ?? 1) * 100)} | ||
| onChange={handleChange} | ||
| dragLabel={true} | ||
| dragMax={100} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default SketchFields |
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import { ChangeColor } from '../../types' | ||
| import { Swatch } from '../_common' | ||
| interface Props { | ||
| colors: (string | { color: string; title?: string })[] | ||
| onClick?: (newColor: ChangeColor, event: MouseEvent) => void | ||
| } | ||
| export default function SketchPresetColors(_props: Props) { | ||
| const props = mergeProps({ onClick: () => {} }, _props) | ||
| const styles = () => { | ||
| return { | ||
| colors: { | ||
| margin: '0 -10px', | ||
| padding: '10px 0 0 10px', | ||
| 'border-top': '1px solid #eee', | ||
| display: !props.colors || !props.colors.length ? 'none' : 'flex', | ||
| 'flex-wrap': 'wrap', | ||
| position: 'relative', | ||
| }, | ||
| swatchWrap: { | ||
| width: '16px', | ||
| height: '16px', | ||
| margin: '0 10px 10px 0', | ||
| }, | ||
| swatch: { | ||
| 'border-radius': '3px', | ||
| 'box-shadow': 'inset 0 0 0 1px rgba(0,0,0,.15)', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| const handleClick = (hex: string, e: MouseEvent) => { | ||
| props.onClick( | ||
| { | ||
| hex, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().colors} class="flexbox-fix"> | ||
| <For each={props.colors}> | ||
| {(colorObjOrString) => { | ||
| const c = | ||
| typeof colorObjOrString === 'string' ? { color: colorObjOrString } : colorObjOrString | ||
| return ( | ||
| <div style={styles().swatchWrap}> | ||
| <Swatch | ||
| {...c} | ||
| styles={styles().swatch} | ||
| onClick={handleClick} | ||
| focusStyle={{ | ||
| 'box-shadow': `inset 0 0 0 1px rgba(0,0,0,.15), 0 0 4px ${c.color}`, | ||
| }} | ||
| /> | ||
| </div> | ||
| ) | ||
| }} | ||
| </For> | ||
| </div> | ||
| ) | ||
| } |
| export { default as SliderPicker } from './Slider' | ||
| export type { SliderPickerProps } from './Slider' |
| import { merge } from 'lodash-es' | ||
| import { JSX, mergeProps } from 'solid-js' | ||
| import { Hue, useColorPicker, withColorPicker } from '../_common' | ||
| import SliderPointer from './SliderPointer' | ||
| import SliderSwatches from './SliderSwatches' | ||
| export type SliderPickerProps = { | ||
| pointer?: typeof SliderPointer | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| } | ||
| const Slider = (_props: SliderPickerProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| pointer: SliderPointer, | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors, changeColor } = useColorPicker() | ||
| const styles = merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| hue: { | ||
| height: '12px', | ||
| position: 'relative', | ||
| }, | ||
| Hue: { | ||
| 'border-radius': '2px', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| return ( | ||
| <div style={styles.wrap || {}} class={`slider-picker ${props.className}`}> | ||
| <div style={styles.hue}> | ||
| <Hue radius={2} hsl={colors().hsl} pointer={props.pointer} onChange={changeColor} /> | ||
| </div> | ||
| <div style={styles.swatches}> | ||
| <SliderSwatches hsl={colors().hsl} onClick={changeColor} /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Slider) |
| import { JSX } from 'solid-js' | ||
| export default function SliderPointer() { | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| picker: { | ||
| width: '14px', | ||
| height: '14px', | ||
| 'border-radius': '6px', | ||
| transform: 'translate(-7px, -1px)', | ||
| 'background-color': 'rgb(248, 248, 248)', | ||
| 'box-shadow': '0 1px 4px 0 rgba(0, 0, 0, 0.37)', | ||
| }, | ||
| } | ||
| return <div style={styles.picker} /> | ||
| } |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { HslColor } from '../../types' | ||
| interface Props { | ||
| hsl: HslColor | ||
| onClick: any | ||
| offset: number | ||
| active?: boolean | ||
| first?: boolean | ||
| last?: boolean | ||
| } | ||
| export default function SliderSwatch(_props: Props) { | ||
| const props = mergeProps( | ||
| { | ||
| onClick: () => {}, | ||
| }, | ||
| _props, | ||
| ) | ||
| const styles = () => { | ||
| const { hsl, offset, active, first, last } = props | ||
| return { | ||
| swatch: { | ||
| height: '12px', | ||
| background: `hsl(${hsl.h}, 50%, ${offset * 100}%)`, | ||
| cursor: 'pointer', | ||
| 'border-radius': active | ||
| ? '3.6px/2px' | ||
| : first | ||
| ? '2px 0 0 2px' | ||
| : last | ||
| ? '0 2px 2px 0' | ||
| : undefined, | ||
| transform: active ? 'scaleY(1.8)' : undefined, | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| const handleClick = (e: Event) => { | ||
| props.onClick( | ||
| { | ||
| h: props.hsl.h, | ||
| s: 0.5, | ||
| l: props.offset, | ||
| source: 'hsl', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| return <div style={styles().swatch} onClick={handleClick} /> | ||
| } |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { HslColor } from '../../types' | ||
| import SliderSwatch from './SliderSwatch' | ||
| interface Props { | ||
| onClick: any | ||
| hsl: HslColor | ||
| } | ||
| export default function SliderSwatches(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| swatches: { | ||
| 'margin-top': '20px', | ||
| }, | ||
| swatch: { | ||
| 'box-sizing': 'border-box', | ||
| width: '20%', | ||
| 'padding-right': '1px', | ||
| float: 'left', | ||
| }, | ||
| clear: { | ||
| clear: 'both', | ||
| }, | ||
| } | ||
| // Acceptible difference in floating point equality | ||
| const epsilon = 0.1 | ||
| return ( | ||
| <div style={styles.swatches}> | ||
| <div style={styles.swatch}> | ||
| <SliderSwatch | ||
| hsl={props.hsl} | ||
| offset={0.8} | ||
| active={Math.abs(props.hsl.l - 0.8) < epsilon && Math.abs(props.hsl.s - 0.5) < epsilon} | ||
| onClick={props.onClick} | ||
| first | ||
| /> | ||
| </div> | ||
| <div style={styles.swatch}> | ||
| <SliderSwatch | ||
| hsl={props.hsl} | ||
| offset={0.65} | ||
| active={Math.abs(props.hsl.l - 0.65) < epsilon && Math.abs(props.hsl.s - 0.5) < epsilon} | ||
| onClick={props.onClick} | ||
| /> | ||
| </div> | ||
| <div style={styles.swatch}> | ||
| <SliderSwatch | ||
| hsl={props.hsl} | ||
| offset={0.5} | ||
| active={Math.abs(props.hsl.l - 0.5) < epsilon && Math.abs(props.hsl.s - 0.5) < epsilon} | ||
| onClick={props.onClick} | ||
| /> | ||
| </div> | ||
| <div style={styles.swatch}> | ||
| <SliderSwatch | ||
| hsl={props.hsl} | ||
| offset={0.35} | ||
| active={Math.abs(props.hsl.l - 0.35) < epsilon && Math.abs(props.hsl.s - 0.5) < epsilon} | ||
| onClick={props.onClick} | ||
| /> | ||
| </div> | ||
| <div style={styles.swatch}> | ||
| <SliderSwatch | ||
| hsl={props.hsl} | ||
| offset={0.2} | ||
| active={Math.abs(props.hsl.l - 0.2) < epsilon && Math.abs(props.hsl.s - 0.5) < epsilon} | ||
| onClick={props.onClick} | ||
| last | ||
| /> | ||
| </div> | ||
| <div style={styles.clear} /> | ||
| </div> | ||
| ) | ||
| } |
| export { default as SwatchesPicker } from './Swatches' | ||
| export type { SwatchesPickerProps } from './Swatches' |
| import { merge } from 'lodash-es' | ||
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import { Color } from '../../types' | ||
| import { Raised, useColorPicker, withColorPicker } from '../_common' | ||
| import SwatchesGroup from './SwatchesGroup' | ||
| export type SwatchesPickerProps = { | ||
| width?: string | number | ||
| height?: string | number | ||
| className?: string | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| colors?: string[][] | ||
| } | ||
| export function Swatches(_props: SwatchesPickerProps) { | ||
| const props = mergeProps( | ||
| { | ||
| width: 320, | ||
| height: 240, | ||
| colors: [ | ||
| ['#B71C1C', '#D32F2F', '#F44336', '#E57373', '#FFCDD2'], | ||
| ['#880E4F', '#C2185B', '#E91E63', '#F06292', '#F8BBD0'], | ||
| ['#4A148C', '#7B1FA2', '#9C27B0', '#BA68C8', '#E1BEE7'], | ||
| ['#311B92', '#512DA8', '#673AB7', '#9575CD', '#D1C4E9'], | ||
| ['#1A237E', '#303F9F', '#3F51B5', '#7986CB', '#C5CAE9'], | ||
| ['#0D47A1', '#1976D2', '#2196F3', '#64B5F6', '#BBDEFB'], | ||
| ['#01579B', '#0288D1', '#03A9F4', '#4FC3F7', '#B3E5FC'], | ||
| ['#006064', '#0097A7', '#00BCD4', '#4DD0E1', '#B2EBF2'], | ||
| ['#004D40', '#00796B', '#009688', '#4DB6AC', '#B2DFDB'], | ||
| ['#1B5E20', '#388E3C', '#4CAF50', '#81C784', '#C8E6C9'], | ||
| ['#33691E', '#689F38', '#8BC34A', '#AED581', '#DCEDC8'], | ||
| ['#827717', '#AFB42B', '#CDDC39', '#DCE775', '#F0F4C3'], | ||
| ['#F57F17', '#FBC02D', '#FFEB3B', '#FFF176', '#FFF9C4'], | ||
| ['#FF6F00', '#FFA000', '#FFC107', '#FFD54F', '#FFECB3'], | ||
| ['#E65100', '#F57C00', '#FF9800', '#FFB74D', '#FFE0B2'], | ||
| ['#BF360C', '#E64A19', '#FF5722', '#FF8A65', '#FFCCBC'], | ||
| ['#3E2723', '#5D4037', '#795548', '#A1887F', '#D7CCC8'], | ||
| ['#263238', '#455A64', '#607D8B', '#90A4AE', '#CFD8DC'], | ||
| ['#000000', '#525252', '#969696', '#D9D9D9', '#FFFFFF'], | ||
| ], | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| const height = typeof props.height === 'number' ? `${props.height}px` : props.height | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| picker: { | ||
| width, | ||
| height, | ||
| }, | ||
| overflow: { | ||
| height, | ||
| 'overflow-y': 'scroll', | ||
| }, | ||
| body: { | ||
| padding: '16px 0 6px 16px', | ||
| }, | ||
| clear: { | ||
| clear: 'both', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| const handleChange = (data: Color, e: Event) => | ||
| changeColor({ hex: data as string, source: 'hex' }, e) | ||
| return ( | ||
| <div style={styles().picker} class={`swatches-picker ${props.className}`}> | ||
| <Raised> | ||
| <div style={styles().overflow}> | ||
| <div style={styles().body}> | ||
| <For each={props.colors}> | ||
| {(group) => ( | ||
| <SwatchesGroup group={group} active={currentColors().hex} onClick={handleChange} /> | ||
| )} | ||
| </For> | ||
| <div style={styles().clear} /> | ||
| </div> | ||
| </div> | ||
| </Raised> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Swatches) |
| import { JSX, mergeProps } from 'solid-js' | ||
| import { getContrastingColor } from '../../helpers/color' | ||
| import { Color } from '../../types' | ||
| import { Swatch } from '../_common' | ||
| import { CheckIcon } from '../_common' | ||
| interface Props { | ||
| color: string | ||
| onClick: (color: Color, event: Event) => void | ||
| first: boolean | ||
| last: boolean | ||
| active: boolean | ||
| } | ||
| export default function SwatchesColor(_props: Props) { | ||
| const props = mergeProps({ onClick: () => {} }, _props) | ||
| const styles = () => { | ||
| const { color, active, first, last } = props | ||
| return { | ||
| color: { | ||
| width: '40px', | ||
| height: '24px', | ||
| cursor: 'pointer', | ||
| background: color, | ||
| 'margin-bottom': '1px', | ||
| overflow: first || last ? 'hidden' : undefined, | ||
| 'border-radius': first ? '2px 2px 0 0' : last ? '0 0 2px 2px' : undefined, | ||
| 'box-shadow': color === '#FFFFFF' ? 'inset 0 0 0 1px #ddd' : undefined, | ||
| }, | ||
| check: { | ||
| color: color === '#FFFFFF' || color === 'transparent' ? '#333' : getContrastingColor(color), | ||
| 'margin-left': '8px', | ||
| display: active ? 'block' : 'none', | ||
| margin: '0 auto', | ||
| }, | ||
| } as Record<string, JSX.CSSProperties> | ||
| } | ||
| return ( | ||
| <Swatch | ||
| color={props.color} | ||
| styles={styles().color} | ||
| onClick={props.onClick} | ||
| focusStyle={{ 'box-shadow': `0 0 4px ${props.color}` }} | ||
| > | ||
| <div style={styles().check}> | ||
| <CheckIcon width="24" height="24" fill="white" stroke="white" /> | ||
| </div> | ||
| </Swatch> | ||
| ) | ||
| } |
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import { Color, HexColor } from '../../types' | ||
| import SwatchesColor from './SwatchesColor' | ||
| type Props = { | ||
| onClick: (color: Color, event: Event) => void | ||
| active: HexColor | ||
| group: string[] | ||
| } | ||
| export default function SwatchesGroup(_props: Props) { | ||
| const props = mergeProps({}, _props) | ||
| const styles: Record<string, JSX.CSSProperties> = { | ||
| group: { | ||
| 'padding-bottom': '10px', | ||
| width: '40px', | ||
| float: 'left', | ||
| 'margin-right': '10px', | ||
| }, | ||
| } | ||
| return ( | ||
| <div style={styles.group}> | ||
| <For each={props.group}> | ||
| {(color, i) => ( | ||
| <SwatchesColor | ||
| color={color} | ||
| active={color.toLowerCase() === props.active} | ||
| first={i() === 0} | ||
| last={i() === props.group.length - 1} | ||
| onClick={props.onClick} | ||
| /> | ||
| )} | ||
| </For> | ||
| </div> | ||
| ) | ||
| } |
| export { default as TwitterPicker } from './Twitter' | ||
| export type { TwitterPickerProps } from './Twitter' |
| import { merge } from 'lodash-es' | ||
| import { For, JSX, mergeProps } from 'solid-js' | ||
| import * as color from '../../helpers/color' | ||
| import { EditableInput, Swatch, useColorPicker, withColorPicker } from '../_common' | ||
| export type TwitterPickerProps = { | ||
| width?: string | number | ||
| triangle?: 'hide' | 'top-left' | 'top-right' | ||
| colors?: string[] | ||
| styles?: Record<string, JSX.CSSProperties> | ||
| className?: string | ||
| } | ||
| export const Twitter = (_props: TwitterPickerProps) => { | ||
| const props = mergeProps( | ||
| { | ||
| colors: [ | ||
| '#FF6900', | ||
| '#FCB900', | ||
| '#7BDCB5', | ||
| '#00D084', | ||
| '#8ED1FC', | ||
| '#0693E3', | ||
| '#ABB8C3', | ||
| '#EB144C', | ||
| '#F78DA7', | ||
| '#9900EF', | ||
| ], | ||
| width: 276, | ||
| triangle: 'top-left', | ||
| styles: {}, | ||
| className: '', | ||
| }, | ||
| _props, | ||
| ) | ||
| const { colors: currentColors, changeColor } = useColorPicker() | ||
| const styles = () => { | ||
| const width = typeof props.width === 'number' ? `${props.width}px` : props.width | ||
| const { triangle } = props | ||
| return merge<Record<string, JSX.CSSProperties>, Record<string, JSX.CSSProperties>>( | ||
| { | ||
| card: { | ||
| width, | ||
| background: '#fff', | ||
| border: '0 solid rgba(0,0,0,0.25)', | ||
| 'box-shadow': '0 1px 4px rgba(0,0,0,0.25)', | ||
| 'border-radius': '4px', | ||
| position: 'relative', | ||
| }, | ||
| body: { | ||
| padding: '15px 9px 9px 15px', | ||
| }, | ||
| label: { | ||
| 'font-size': '18px', | ||
| color: '#fff', | ||
| }, | ||
| triangle: { | ||
| width: '0px', | ||
| height: '0px', | ||
| 'border-style': 'solid', | ||
| 'border-width': '0 9px 10px 9px', | ||
| 'border-color': 'transparent transparent #fff transparent', | ||
| position: 'absolute', | ||
| display: triangle === 'hide' ? 'none' : undefined, | ||
| top: triangle === 'top-left' || triangle === 'top-right' ? '-10px' : undefined, | ||
| left: triangle === 'top-left' || triangle === 'top-right' ? '12px' : undefined, | ||
| }, | ||
| triangleShadow: { | ||
| width: '0px', | ||
| height: '0px', | ||
| 'border-style': 'solid', | ||
| 'border-width': '0 9px 10px 9px', | ||
| 'border-color': 'transparent transparent rgba(0,0,0,.1) transparent', | ||
| position: 'absolute', | ||
| display: triangle === 'hide' ? 'none' : undefined, | ||
| top: triangle === 'top-left' || triangle === 'top-right' ? '-11px' : undefined, | ||
| left: triangle === 'top-left' || triangle === 'top-right' ? '12px' : undefined, | ||
| }, | ||
| hash: { | ||
| background: '#F0F0F0', | ||
| height: '30px', | ||
| width: '30px', | ||
| 'border-radius': '4px 0 0 4px', | ||
| float: 'left', | ||
| color: '#98A1A4', | ||
| display: 'flex', | ||
| 'align-items': 'center', | ||
| 'justify-content': 'center', | ||
| }, | ||
| input: { | ||
| width: '100px', | ||
| 'font-size': '14px', | ||
| color: '#666', | ||
| border: '0px', | ||
| outline: 'none', | ||
| height: '28px', | ||
| 'box-shadow': 'inset 0 0 0 1px #F0F0F0', | ||
| 'box-sizing': 'content-box', | ||
| 'border-radius': '0 4px 4px 0', | ||
| float: 'left', | ||
| 'padding-left': '8px', | ||
| }, | ||
| swatch: { | ||
| width: '30px', | ||
| height: '30px', | ||
| float: 'left', | ||
| 'border-radius': '4px', | ||
| margin: '0 6px 6px 0', | ||
| }, | ||
| clear: { | ||
| clear: 'both', | ||
| }, | ||
| }, | ||
| props.styles, | ||
| ) | ||
| } | ||
| const handleChange = (hexcode: string, e: Event) => { | ||
| color.isValidHex(hexcode) && | ||
| changeColor( | ||
| { | ||
| hex: hexcode, | ||
| source: 'hex', | ||
| }, | ||
| e, | ||
| ) | ||
| } | ||
| return ( | ||
| <div style={styles().card} class={`twitter-picker ${props.className}`}> | ||
| <div style={styles().triangleShadow} /> | ||
| <div style={styles().triangle} /> | ||
| <div style={styles().body}> | ||
| <For each={props.colors}> | ||
| {(c) => ( | ||
| <Swatch | ||
| color={c} | ||
| styles={styles().swatch} | ||
| onClick={handleChange} | ||
| focusStyle={{ | ||
| 'box-shadow': `0 0 4px ${c}`, | ||
| }} | ||
| /> | ||
| )} | ||
| </For> | ||
| <div style={styles().hash}>#</div> | ||
| <EditableInput | ||
| label={''} | ||
| styles={{ input: styles().input }} | ||
| value={currentColors().hex.replace('#', '')} | ||
| onChange={handleChange} | ||
| /> | ||
| <div style={styles().clear} /> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
| export default withColorPicker(Twitter) |
| import { HslColor } from '../types' | ||
| export const calculateChange = ( | ||
| e: any, | ||
| hsl: HslColor, | ||
| direction: string, | ||
| initialA: any, | ||
| container: HTMLDivElement, | ||
| ) => { | ||
| const containerWidth = container.clientWidth | ||
| const containerHeight = container.clientHeight | ||
| const x = typeof e.pageX === 'number' ? e.pageX : e.touches[0].pageX | ||
| const y = typeof e.pageY === 'number' ? e.pageY : e.touches[0].pageY | ||
| const left = x - (container.getBoundingClientRect().left + window.pageXOffset) | ||
| const top = y - (container.getBoundingClientRect().top + window.pageYOffset) | ||
| if (direction === 'vertical') { | ||
| let a | ||
| if (top < 0) { | ||
| a = 0 | ||
| } else if (top > containerHeight) { | ||
| a = 1 | ||
| } else { | ||
| a = Math.round((top * 100) / containerHeight) / 100 | ||
| } | ||
| if (hsl.a !== a) { | ||
| return { | ||
| h: hsl.h, | ||
| s: hsl.s, | ||
| l: hsl.l, | ||
| a, | ||
| source: 'rgb', | ||
| } | ||
| } | ||
| } else { | ||
| let a | ||
| if (left < 0) { | ||
| a = 0 | ||
| } else if (left > containerWidth) { | ||
| a = 1 | ||
| } else { | ||
| a = Math.round((left * 100) / containerWidth) / 100 | ||
| } | ||
| if (initialA !== a) { | ||
| return { | ||
| h: hsl.h, | ||
| s: hsl.s, | ||
| l: hsl.l, | ||
| a, | ||
| source: 'rgb', | ||
| } | ||
| } | ||
| } | ||
| return null | ||
| } |
| const checkboardCache: { [key: string]: any } = {} | ||
| export const render = (c1: string, c2: string, size: number, serverCanvas: any) => { | ||
| if (typeof document === 'undefined' && !serverCanvas) { | ||
| return null | ||
| } | ||
| const canvas: HTMLCanvasElement = serverCanvas | ||
| ? new serverCanvas() | ||
| : document.createElement('canvas') | ||
| canvas.width = size * 2 | ||
| canvas.height = size * 2 | ||
| const ctx = canvas.getContext('2d') | ||
| if (!ctx) { | ||
| return null | ||
| } // If no context can be found, return early. | ||
| ctx.fillStyle = c1 | ||
| ctx.fillRect(0, 0, canvas.width, canvas.height) | ||
| ctx.fillStyle = c2 | ||
| ctx.fillRect(0, 0, size, size) | ||
| ctx.translate(size, size) | ||
| ctx.fillRect(0, 0, size, size) | ||
| return canvas.toDataURL() | ||
| } | ||
| export const get = (c1: string, c2: string, size: number, serverCanvas: any) => { | ||
| const key = `${c1}-${c2}-${size}${serverCanvas ? '-server' : ''}` | ||
| if (checkboardCache[key]) { | ||
| return checkboardCache[key] | ||
| } | ||
| const checkboard = render(c1, c2, size, serverCanvas) | ||
| checkboardCache[key] = checkboard | ||
| return checkboard | ||
| } |
| import { each } from 'lodash-es' | ||
| import tinycolor from 'tinycolor2' | ||
| export const simpleCheckForValidColor = (data: any) => { | ||
| const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'] | ||
| let checked = 0 | ||
| let passed = 0 | ||
| each(keysToCheck, (letter) => { | ||
| if (data[letter]) { | ||
| checked += 1 | ||
| if (!isNaN(data[letter])) { | ||
| passed += 1 | ||
| } | ||
| if (letter === 's' || letter === 'l') { | ||
| const percentPatt = /^\d+%$/ | ||
| if (percentPatt.test(data[letter])) { | ||
| passed += 1 | ||
| } | ||
| } | ||
| } | ||
| }) | ||
| return checked === passed ? data : false | ||
| } | ||
| export const toState = (data: any, oldHue?: number) => { | ||
| const color = data.hex ? tinycolor(data.hex) : tinycolor(data) | ||
| const hsl = color.toHsl() | ||
| const hsv = color.toHsv() | ||
| const rgb = color.toRgb() | ||
| const hex = color.toHex() | ||
| if (hsl.s === 0) { | ||
| hsl.h = oldHue || 0 | ||
| hsv.h = oldHue || 0 | ||
| } | ||
| const transparent = hex === '000000' && rgb.a === 0 | ||
| return { | ||
| hsl, | ||
| hex: transparent ? 'transparent' : `#${hex}`, | ||
| rgb, | ||
| hsv, | ||
| oldHue: data.h || oldHue || hsl.h, | ||
| source: data.source, | ||
| } | ||
| } | ||
| export const isValidHex = (hex: any) => { | ||
| if (hex === 'transparent') { | ||
| return true | ||
| } | ||
| // disable hex4 and hex8 | ||
| const lh = String(hex).charAt(0) === '#' ? 1 : 0 | ||
| return hex.length !== 4 + lh && hex.length < 7 + lh && tinycolor(hex).isValid() | ||
| } | ||
| export const getContrastingColor = (data: any) => { | ||
| if (!data) { | ||
| return '#fff' | ||
| } | ||
| const col = toState(data) | ||
| if (col.hex === 'transparent') { | ||
| return 'rgba(0,0,0,0.4)' | ||
| } | ||
| const yiq = (col.rgb.r * 299 + col.rgb.g * 587 + col.rgb.b * 114) / 1000 | ||
| return yiq >= 128 ? '#000' : '#fff' | ||
| } | ||
| export const red = { | ||
| hsl: { a: 1, h: 0, l: 0.5, s: 1 }, | ||
| hex: '#ff0000', | ||
| rgb: { r: 255, g: 0, b: 0, a: 1 }, | ||
| hsv: { h: 0, s: 1, v: 1, a: 1 }, | ||
| } | ||
| export const isvalidColorString = (str: string, type: string) => { | ||
| const stringWithoutDegree = str.replace('°', '') | ||
| return tinycolor(`${type} (${stringWithoutDegree})`).isValid() | ||
| } |
| import { HslColor } from '../types' | ||
| export const calculateChange = ( | ||
| e: any, | ||
| direction: string, | ||
| hsl: HslColor, | ||
| container: HTMLDivElement, | ||
| ) => { | ||
| const containerWidth = container.clientWidth | ||
| const containerHeight = container.clientHeight | ||
| const x = typeof e.pageX === 'number' ? e.pageX : e.touches[0].pageX | ||
| const y = typeof e.pageY === 'number' ? e.pageY : e.touches[0].pageY | ||
| const left = x - (container.getBoundingClientRect().left + window.pageXOffset) | ||
| const top = y - (container.getBoundingClientRect().top + window.pageYOffset) | ||
| if (direction === 'vertical') { | ||
| let h | ||
| if (top < 0) { | ||
| h = 359 | ||
| } else if (top > containerHeight) { | ||
| h = 0 | ||
| } else { | ||
| const percent = -((top * 100) / containerHeight) + 100 | ||
| h = (360 * percent) / 100 | ||
| } | ||
| if (hsl.h !== h) { | ||
| return { | ||
| h, | ||
| s: hsl.s, | ||
| l: hsl.l, | ||
| a: hsl.a, | ||
| source: 'hsl', | ||
| } | ||
| } | ||
| } else { | ||
| let h | ||
| if (left < 0) { | ||
| h = 0 | ||
| } else if (left > containerWidth) { | ||
| h = 359 | ||
| } else { | ||
| const percent = (left * 100) / containerWidth | ||
| h = (360 * percent) / 100 | ||
| } | ||
| if (hsl.h !== h) { | ||
| return { | ||
| h, | ||
| s: hsl.s, | ||
| l: hsl.l, | ||
| a: hsl.a, | ||
| source: 'hsl', | ||
| } | ||
| } | ||
| } | ||
| return null | ||
| } |
| import { HslColor } from '../types' | ||
| export function calculateChange(e: any, hsl: HslColor, container: HTMLDivElement) { | ||
| const { width: containerWidth, height: containerHeight } = container.getBoundingClientRect() | ||
| const x = typeof e.pageX === 'number' ? e.pageX : e.touches[0].pageX | ||
| const y = typeof e.pageY === 'number' ? e.pageY : e.touches[0].pageY | ||
| let left = x - (container.getBoundingClientRect().left + window.pageXOffset) | ||
| let top = y - (container.getBoundingClientRect().top + window.pageYOffset) | ||
| if (left < 0) { | ||
| left = 0 | ||
| } else if (left > containerWidth) { | ||
| left = containerWidth | ||
| } | ||
| if (top < 0) { | ||
| top = 0 | ||
| } else if (top > containerHeight) { | ||
| top = containerHeight | ||
| } | ||
| const saturation = left / containerWidth | ||
| const bright = 1 - top / containerHeight | ||
| return { | ||
| h: hsl.h, | ||
| s: saturation, | ||
| v: bright, | ||
| a: hsl.a, | ||
| source: 'hsv', | ||
| } | ||
| } |
| export * from './components/alpha' | ||
| export * from './components/material' | ||
| export * from './components/hue' | ||
| export * from './components/twitter' | ||
| export * from './components/block' | ||
| export * from './components/slider' | ||
| export * from './components/github' | ||
| export * from './components/compact' | ||
| export * from './components/swatches' | ||
| export * from './components/circle' | ||
| export * from './components/google' | ||
| export * from './components/chrome' | ||
| export * from './components/sketch' | ||
| export * from './components/photoshop' | ||
| export * from './components/hue' | ||
| export * from './types' |
+41
| export type HexColor = string | ||
| export type HslColor = { | ||
| h: number | ||
| l: number | ||
| s: number | ||
| a?: number | ||
| } | ||
| export type HsvColor = { | ||
| h: number | ||
| s: number | ||
| v: number | ||
| a?: number | ||
| } | ||
| export type RgbColor = { | ||
| r: number | ||
| g: number | ||
| b: number | ||
| a?: number | ||
| } | ||
| export type Color = HexColor | HslColor | HsvColor | RgbColor | ||
| export type ColorResult = { | ||
| hex: HexColor | ||
| hsl: HslColor | ||
| hsv: HsvColor | ||
| rgb: RgbColor | ||
| oldHue: number | ||
| } | ||
| export type ChangeColor = | ||
| | HslColor | ||
| | HsvColor | ||
| | (RgbColor & { source?: string }) | ||
| | { hex: HexColor; source: string } | ||
| | HexColor | ||
| export type Direction = 'horizontal' | 'vertical' |
| import { JSX } from 'solid-js'; | ||
| export declare type CheckboardProps = { | ||
| export type CheckboardProps = { | ||
| size?: number; | ||
@@ -4,0 +4,0 @@ white?: string; |
@@ -19,2 +19,2 @@ import { Accessor, Context, JSX } from 'solid-js'; | ||
| export declare function useColorPicker(): ColorPickerContextType; | ||
| export declare function withColorPicker<T extends object>(Component: (props: T) => JSX.Element): (props: T & Omit<ColorPickerProps, 'children'>) => JSX.Element; | ||
| export declare function withColorPicker<T extends object>(Component: (props: T) => JSX.Element): (props: T & Omit<ColorPickerProps, "children">) => JSX.Element; |
| import { JSX } from 'solid-js'; | ||
| import { ChangeColor, HslColor, HsvColor } from '../../types'; | ||
| export declare type SaturationProps = { | ||
| export type SaturationProps = { | ||
| hsl: HslColor; | ||
@@ -5,0 +5,0 @@ hsv: HsvColor; |
| import { JSX } from 'solid-js'; | ||
| export declare type SwatchProps = { | ||
| export type SwatchProps = { | ||
| color: string; | ||
@@ -4,0 +4,0 @@ styles?: JSX.CSSProperties; |
| import { JSX } from 'solid-js'; | ||
| export declare type AlphaPickerProps = { | ||
| export type AlphaPickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ height?: string | number; |
| import { JSX } from 'solid-js'; | ||
| export declare type BlockPickerProps = { | ||
| export type BlockPickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ colors?: string[]; |
| import { JSX } from 'solid-js'; | ||
| export declare type CirclePickerProps = { | ||
| export type CirclePickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ circleSize?: number; |
| import { JSX } from 'solid-js'; | ||
| export declare type CompactPickerProps = { | ||
| export type CompactPickerProps = { | ||
| colors?: string[]; | ||
@@ -4,0 +4,0 @@ styles?: Record<string, JSX.CSSProperties>; |
| import { JSX } from 'solid-js'; | ||
| export declare type GithubPickerProps = { | ||
| export type GithubPickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ styles?: Record<string, JSX.CSSProperties>; |
| import { JSX } from 'solid-js'; | ||
| export declare type GooglePickerProps = { | ||
| export type GooglePickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ styles?: Record<string, JSX.CSSProperties>; |
| import HuePointer from './HuePointer'; | ||
| import { JSX } from 'solid-js'; | ||
| export declare type HuePickerProps = { | ||
| export type HuePickerProps = { | ||
| width?: string | number; | ||
@@ -5,0 +5,0 @@ height?: string | number; |
| import { JSX } from 'solid-js'; | ||
| export declare type MaterialPickerProps = { | ||
| export type MaterialPickerProps = { | ||
| styles?: Record<string, JSX.CSSProperties>; | ||
@@ -4,0 +4,0 @@ className?: string; |
| import { JSX } from 'solid-js'; | ||
| export declare type PhotoshopPickerProps = { | ||
| export type PhotoshopPickerProps = { | ||
| header?: string; | ||
@@ -4,0 +4,0 @@ styles?: Record<string, JSX.CSSProperties>; |
| import { JSX } from 'solid-js'; | ||
| export declare type SketchPickerProps = { | ||
| export type SketchPickerProps = { | ||
| disableAlpha?: boolean; | ||
@@ -4,0 +4,0 @@ width?: string | number; |
| import { JSX } from 'solid-js'; | ||
| import SliderPointer from './SliderPointer'; | ||
| export declare type SliderPickerProps = { | ||
| export type SliderPickerProps = { | ||
| pointer?: typeof SliderPointer; | ||
@@ -5,0 +5,0 @@ styles?: Record<string, JSX.CSSProperties>; |
| import { JSX } from 'solid-js'; | ||
| export declare type SwatchesPickerProps = { | ||
| export type SwatchesPickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ height?: string | number; |
| import { JSX } from 'solid-js'; | ||
| import { Color, HexColor } from '../../types'; | ||
| declare type Props = { | ||
| type Props = { | ||
| onClick: (color: Color, event: Event) => void; | ||
@@ -5,0 +5,0 @@ active: HexColor; |
| import { JSX } from 'solid-js'; | ||
| export declare type TwitterPickerProps = { | ||
| export type TwitterPickerProps = { | ||
| width?: string | number; | ||
@@ -4,0 +4,0 @@ triangle?: 'hide' | 'top-left' | 'top-right'; |
@@ -1,3 +0,3 @@ | ||
| export declare type HexColor = string; | ||
| export declare type HslColor = { | ||
| export type HexColor = string; | ||
| export type HslColor = { | ||
| h: number; | ||
@@ -8,3 +8,3 @@ l: number; | ||
| }; | ||
| export declare type HsvColor = { | ||
| export type HsvColor = { | ||
| h: number; | ||
@@ -15,3 +15,3 @@ s: number; | ||
| }; | ||
| export declare type RgbColor = { | ||
| export type RgbColor = { | ||
| r: number; | ||
@@ -22,4 +22,4 @@ g: number; | ||
| }; | ||
| export declare type Color = HexColor | HslColor | HsvColor | RgbColor; | ||
| export declare type ColorResult = { | ||
| export type Color = HexColor | HslColor | HsvColor | RgbColor; | ||
| export type ColorResult = { | ||
| hex: HexColor; | ||
@@ -31,3 +31,3 @@ hsl: HslColor; | ||
| }; | ||
| export declare type ChangeColor = HslColor | HsvColor | (RgbColor & { | ||
| export type ChangeColor = HslColor | HsvColor | (RgbColor & { | ||
| source?: string; | ||
@@ -38,2 +38,2 @@ }) | { | ||
| } | HexColor; | ||
| export declare type Direction = 'horizontal' | 'vertical'; | ||
| export type Direction = 'horizontal' | 'vertical'; |
+40
-33
| { | ||
| "name": "solid-color", | ||
| "version": "0.0.4", | ||
| "version": "0.0.5", | ||
| "private": false, | ||
@@ -32,12 +32,18 @@ "description": "", | ||
| "exports": { | ||
| ".": { | ||
| "solid": "./dist/source/index.jsx", | ||
| "import": "./dist/esm/index.js", | ||
| "browser": { | ||
| "import": "./dist/esm/index.js", | ||
| "require": "./dist/cjs/index.js" | ||
| "solid": { | ||
| "development": "./dist/source/index.jsx", | ||
| "import": "./dist/source/index.jsx" | ||
| }, | ||
| "development": { | ||
| "import": { | ||
| "types": "./dist/types/index.d.ts", | ||
| "default": "./dist/esm/index.js" | ||
| }, | ||
| "require": "./dist/cjs/index.js", | ||
| "node": "./dist/cjs/index.js" | ||
| } | ||
| "require": "./dist/cjs/index.js" | ||
| }, | ||
| "import": { | ||
| "types": "./dist/types/index.d.ts", | ||
| "default": "./dist/esm/index.js" | ||
| }, | ||
| "require": "./dist/cjs/index.js" | ||
| }, | ||
@@ -49,2 +55,3 @@ "main": "dist/cjs/index.js", | ||
| "dist", | ||
| "src", | ||
| "README.md" | ||
@@ -67,26 +74,26 @@ ], | ||
| "devDependencies": { | ||
| "@solidjs/testing-library": "^0.6.0", | ||
| "@testing-library/jest-dom": "^5.16.5", | ||
| "@types/lodash-es": "^4.17.6", | ||
| "@types/testing-library__jest-dom": "^5.14.5", | ||
| "@types/tinycolor2": "^1.4.3", | ||
| "@typescript-eslint/eslint-plugin": "^5.48.2", | ||
| "@typescript-eslint/parser": "^5.48.2", | ||
| "bumpp": "^8.2.1", | ||
| "eslint": "^8.32.0", | ||
| "eslint-plugin-no-only-tests": "^3.1.0", | ||
| "eslint-plugin-solid": "^0.9.3", | ||
| "jsdom": "^21.1.0", | ||
| "@solidjs/testing-library": "^0.8.10", | ||
| "@testing-library/jest-dom": "^6.6.3", | ||
| "@types/lodash-es": "^4.17.12", | ||
| "@types/testing-library__jest-dom": "^6.0.0", | ||
| "@types/tinycolor2": "^1.4.6", | ||
| "@typescript-eslint/eslint-plugin": "^8.31.1", | ||
| "@typescript-eslint/parser": "^8.31.1", | ||
| "bumpp": "^10.1.0", | ||
| "eslint": "^9.25.1", | ||
| "eslint-plugin-no-only-tests": "^3.3.0", | ||
| "eslint-plugin-solid": "^0.14.5", | ||
| "jsdom": "^26.1.0", | ||
| "lodash-es": "^4.17.21", | ||
| "prettier": "2.7.1", | ||
| "rollup": "^2.77.2", | ||
| "rollup-preset-solid": "^1.4.0", | ||
| "solid-js": "^1.4.8", | ||
| "taze": "^0.7.6", | ||
| "terser": "^5.16.3", | ||
| "tinycolor2": "^1.5.2", | ||
| "typescript": "^4.7.4", | ||
| "vite": "^3.0.4", | ||
| "vite-plugin-solid": "^2.3.0", | ||
| "vitest": "^0.27.3" | ||
| "rollup": "^4.40.1", | ||
| "rollup-preset-solid": "^3.0.0", | ||
| "solid-js": "^1.9.5", | ||
| "taze": "^19.0.4", | ||
| "terser": "^5.39.0", | ||
| "tinycolor2": "^1.6.0", | ||
| "typescript": "^5.8.3", | ||
| "vite": "^6.3.3", | ||
| "vite-plugin-solid": "^2.11.6", | ||
| "vitest": "^3.1.2" | ||
| }, | ||
@@ -96,3 +103,3 @@ "peerDependencies": { | ||
| }, | ||
| "packageManager": "pnpm@7.5.0" | ||
| "packageManager": "pnpm@10.10.0" | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1765308
6.19%217
47.62%24141
21.94%