@wordpress/components
Version:
UI components for WordPress.
8 lines (7 loc) • 10.9 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/color-picker/component.tsx"],
"sourcesContent": ["/**\n * External dependencies\n */\n\nimport { colord, extend, getFormat } from 'colord';\nimport namesPlugin from 'colord/plugins/names';\n\n/**\n * WordPress dependencies\n */\nimport { useCallback, useEffect, useRef, useState, useMemo } from '@wordpress/element';\nimport { useDebounce } from '@wordpress/compose';\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { useContextSystem, contextConnect } from '../context';\nimport { ColorfulWrapper, SelectControl, AuxiliaryColorArtefactWrapper, AuxiliaryColorArtefactHStackHeader, ColorInputWrapper } from './styles';\nimport { ColorCopyButton } from './color-copy-button';\nimport { ColorInput } from './color-input';\nimport { Picker } from './picker';\nimport { useControlledValue } from '../utils/hooks';\nimport { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nextend([namesPlugin]);\n\n/**\n * Merges incoming HSLA with previous state, preserving hue for achromatic\n * colors and saturation only at lightness extremes (black/white) where\n * it has no visual effect.\n */\nfunction mergeHSLA(nextHSLA, prevHSLA) {\n if (nextHSLA.s === 0) {\n if (nextHSLA.l === 0 || nextHSLA.l === 100) {\n return {\n ...nextHSLA,\n h: prevHSLA.h,\n s: prevHSLA.s\n };\n }\n return {\n ...nextHSLA,\n h: prevHSLA.h\n };\n }\n return nextHSLA;\n}\nconst options = [{\n label: 'RGB',\n value: 'rgb'\n}, {\n label: 'HSL',\n value: 'hsl'\n}, {\n label: 'Hex',\n value: 'hex'\n}];\nconst UnconnectedColorPicker = (props, forwardedRef) => {\n const {\n enableAlpha = false,\n color: colorProp,\n onChange,\n defaultValue = '#fff',\n copyFormat,\n ...divProps\n } = useContextSystem(props, 'ColorPicker');\n\n // Use a safe default value for the color and remove the possibility of `undefined`.\n const [color, setColor] = useControlledValue({\n onChange,\n value: colorProp,\n defaultValue\n });\n const safeColordColor = useMemo(() => {\n return colord(color || '');\n }, [color]);\n const debouncedSetColor = useDebounce(setColor);\n\n // Internal HSLA state preserves hue and saturation values that\n // would otherwise be lost when converting to/from hex at achromatic\n // colors (e.g. pure black or white where any H/S maps to the same hex).\n const [internalHSLA, setInternalHSLA] = useState(() => ({\n ...safeColordColor.toHsl()\n }));\n\n // Track the last hex we produced so the sync effect can\n // distinguish our own updates from external prop changes.\n const lastProducedHexRef = useRef(safeColordColor.toHex());\n\n // Sync internalHSLA when the color prop changes externally (e.g.\n // parent passes a new color that wasn't produced by our onChange).\n useEffect(() => {\n const incomingHex = safeColordColor.toHex();\n\n // If this hex matches what we last produced, it's our own\n // update arriving back \u2014 skip the sync to avoid overwriting\n // internalHSLA with lossy round-tripped values.\n if (incomingHex === lastProducedHexRef.current) {\n return;\n }\n\n // Genuinely external change \u2014 sync internalHSLA.\n lastProducedHexRef.current = incomingHex;\n const externalHSLA = safeColordColor.toHsl();\n setInternalHSLA(prev => mergeHSLA(externalHSLA, prev));\n }, [safeColordColor]);\n\n // Handler for HSL-aware components (Picker, HSL inputs) that\n // provide raw HSLA values without information loss.\n // Uses direct setColor (not debounced) to prevent race conditions\n // where a stale debounced hex would overwrite newer internalHSLA.\n // This is safe performance-wise because react-colorful internally\n // throttles its onChange callbacks using requestAnimationFrame.\n\n const handleHSLAChange = useCallback(nextHSLA => {\n // No mergeHSLA here \u2014 this handler receives the user's explicit\n // choice from the picker or HSL inputs, with no lossy conversion.\n setInternalHSLA(nextHSLA);\n const previousHex = lastProducedHexRef.current;\n const nextHex = colord(nextHSLA).toHex();\n // Only notify parent when the hex actually changes. This\n // avoids firing onChange for H/S changes on achromatic\n // colors (e.g. adjusting hue on pure white).\n if (nextHex !== previousHex) {\n lastProducedHexRef.current = nextHex;\n setColor(nextHex);\n }\n }, [setColor]);\n\n // Handler for components that provide Colord values (RGB, Hex inputs).\n // Uses debouncedSetColor since the hex input fires per keystroke.\n const handleChange = useCallback(nextValue => {\n const nextHSLA = nextValue.toHsl();\n setInternalHSLA(prev => mergeHSLA(nextHSLA, prev));\n const nextHex = nextValue.toHex();\n lastProducedHexRef.current = nextHex;\n debouncedSetColor(nextHex);\n }, [debouncedSetColor]);\n const [colorType, setColorType] = useState(copyFormat || 'hex');\n\n /*\n * ! Listener intended for the CAPTURE phase\n *\n * Capture paste events over the entire color picker, looking for clipboard\n * data that could be parsed as a color. If not, let the paste event\n * propagate normally, so that individual input controls within the\n * component have a chance to handle it.\n */\n const maybeHandlePaste = useCallback(event => {\n const pastedText = event.clipboardData?.getData('text')?.trim();\n if (!pastedText) {\n return;\n }\n const parsedColor = colord(pastedText);\n if (!parsedColor.isValid()) {\n return;\n }\n\n // Apply all valid colors, even if the format isn't supported in\n // the UI (e.g. names like \"cyan\" or, in the future color spaces\n // like \"lch\" if we add the right colord plugins)\n handleChange(parsedColor);\n\n // This redundancy helps TypeScript and is safer than assertions\n const supportedFormats = {\n hex: 'hex',\n rgb: 'rgb',\n hsl: 'hsl'\n };\n const detectedFormat = String(getFormat(pastedText));\n const newColorType = supportedFormats[detectedFormat];\n if (newColorType) {\n setColorType(newColorType);\n }\n\n // Stop at capture phase; no bubbling\n event.stopPropagation();\n event.preventDefault();\n }, [handleChange, setColorType]);\n return /*#__PURE__*/_jsxs(ColorfulWrapper, {\n ref: forwardedRef,\n ...divProps,\n onPasteCapture: maybeHandlePaste,\n children: [/*#__PURE__*/_jsx(Picker, {\n onChange: handleHSLAChange,\n hsla: internalHSLA,\n enableAlpha: enableAlpha\n }), /*#__PURE__*/_jsxs(AuxiliaryColorArtefactWrapper, {\n children: [/*#__PURE__*/_jsxs(AuxiliaryColorArtefactHStackHeader, {\n justify: \"space-between\",\n children: [/*#__PURE__*/_jsx(SelectControl, {\n size: \"compact\",\n options: options,\n value: colorType,\n onChange: nextColorType => setColorType(nextColorType),\n label: __('Color format'),\n hideLabelFromVision: true,\n variant: \"minimal\"\n }), /*#__PURE__*/_jsx(ColorCopyButton, {\n color: safeColordColor,\n colorType: copyFormat || colorType\n })]\n }), /*#__PURE__*/_jsx(ColorInputWrapper, {\n direction: \"column\",\n gap: 2,\n children: /*#__PURE__*/_jsx(ColorInput, {\n colorType: colorType,\n color: safeColordColor,\n hsla: internalHSLA,\n onChange: handleChange,\n onHSLChange: handleHSLAChange,\n enableAlpha: enableAlpha\n })\n })]\n })]\n });\n};\nexport const ColorPicker = contextConnect(UnconnectedColorPicker, 'ColorPicker');\nexport default ColorPicker;"],
"mappings": "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",
"names": ["namesPlugin", "_jsxs", "_jsx"]
}