UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

1 lines • 13.5 kB
{"version":3,"file":"ColorPicker.mjs","names":["colorPickerMessages","useControlledState","Input","InputNumber"],"sources":["../../../src/base-ui/ColorPicker/ColorPicker.tsx"],"sourcesContent":["'use client';\n\nimport { cx, useThemeMode } from 'antd-style';\nimport { Pipette } from 'lucide-react';\nimport { type CSSProperties, memo, useEffect, useRef, useState } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Input, InputNumber } from '@/base-ui/Input';\nimport { rootVariants } from '@/base-ui/Input/style';\nimport { panelStyles } from '@/base-ui/panelStyles';\nimport {\n PopoverPopup,\n PopoverPortal,\n PopoverPositioner,\n PopoverRoot,\n PopoverTriggerElement,\n} from '@/base-ui/Popover';\nimport { Slider } from '@/base-ui/Slider';\nimport colorPickerMessages from '@/i18n/resources/en/colorPicker';\nimport { useTranslation } from '@/i18n/useTranslation';\nimport Icon from '@/Icon';\n\nimport { formatColor, type Hsva, normalizeHexInput, parseColor } from './color';\nimport SaturationArea from './SaturationArea';\nimport { styles } from './style';\nimport type { ColorPickerProps } from './type';\n\nconst DEFAULT_COLOR = '#000000';\n\nconst hasEyeDropper = () => typeof window !== 'undefined' && 'EyeDropper' in window;\n\nconst ColorPicker = memo<ColorPickerProps>(\n ({\n alpha = false,\n children,\n className,\n defaultValue = DEFAULT_COLOR,\n disabled,\n onChange,\n onChangeComplete,\n presets,\n showText,\n size = 'middle',\n style,\n value,\n }) => {\n const { t } = useTranslation(colorPickerMessages);\n const { isDarkMode } = useThemeMode();\n const [hex, setHex] = useControlledState<string>(defaultValue, {\n defaultValue,\n onChange,\n value,\n });\n const [hsva, setHsva] = useState<Hsva>(() => parseColor(hex));\n const [draft, setDraft] = useState(hex.slice(1).toUpperCase());\n const popupRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setHsva((current) =>\n formatColor(current, alpha) === hex.toLowerCase() ? current : parseColor(hex, current.h),\n );\n setDraft(hex.slice(1).toUpperCase());\n }, [hex, alpha]);\n\n const update = (next: Hsva) => {\n setHsva(next);\n setHex(formatColor(next, alpha));\n };\n const commit = (next: Hsva) => onChangeComplete?.(formatColor(next, alpha));\n const apply = (next: Hsva) => {\n update(next);\n commit(next);\n };\n\n const commitDraft = () => {\n const normalized = normalizeHexInput(draft);\n if (!normalized) return setDraft(hex.slice(1).toUpperCase());\n apply(parseColor(normalized, hsva.h));\n };\n\n const swatch = (dimension: number) => (\n <span className={styles.swatch} style={{ height: dimension, width: dimension }}>\n <span style={{ background: hex }} />\n </span>\n );\n\n const trigger =\n children ??\n (showText ? (\n <button\n aria-label={t('colorPicker.trigger')}\n disabled={disabled}\n style={style}\n type=\"button\"\n className={cx(\n rootVariants({ size, variant: isDarkMode ? 'filled' : 'outlined' }),\n styles.textTrigger,\n className,\n )}\n >\n {swatch(18)}\n <span style={{ fontFamily: 'var(--lobe-font-family-code, monospace)' }}>\n {hex.toUpperCase()}\n </span>\n </button>\n ) : (\n <button\n aria-label={t('colorPicker.trigger')}\n className={cx(styles.swatchButton, className)}\n disabled={disabled}\n style={style}\n type=\"button\"\n >\n {swatch(24)}\n </button>\n ));\n\n return (\n <PopoverRoot>\n <PopoverTriggerElement>{trigger}</PopoverTriggerElement>\n <PopoverPortal>\n <PopoverPositioner placement=\"bottomLeft\">\n <PopoverPopup\n className={panelStyles.popup}\n ref={popupRef}\n initialFocus={() =>\n popupRef.current?.querySelector<HTMLElement>('[role=\"slider\"]') ?? true\n }\n >\n <div className={styles.panel}>\n <div className={styles.summary}>\n {swatch(40)}\n <div>\n <div className={styles.value}>{hex.toUpperCase()}</div>\n <div className={panelStyles.label}>\n {alpha ? `HEX · ${Math.round(hsva.a * 100)}%` : 'HEX'}\n </div>\n </div>\n {hasEyeDropper() && (\n <button\n aria-label={t('colorPicker.eyeDropper')}\n className={panelStyles.nav}\n style={{ marginInlineStart: 'auto' }}\n type=\"button\"\n onClick={async () => {\n const dropper = new (\n window as unknown as {\n EyeDropper: new () => { open: () => Promise<{ sRGBHex: string }> };\n }\n ).EyeDropper();\n const result = await dropper.open().catch(() => null);\n if (result) apply({ ...parseColor(result.sRGBHex, hsva.h), a: hsva.a });\n }}\n >\n <Icon icon={Pipette} size={14} />\n </button>\n )}\n </div>\n <SaturationArea\n hue={hsva.h}\n label={t('colorPicker.saturation')}\n saturation={hsva.s}\n value={hsva.v}\n onChange={(s, v) => update({ ...hsva, s, v })}\n onChangeComplete={(s, v) => commit({ ...hsva, s, v })}\n />\n <Slider\n aria-label={t('colorPicker.hue')}\n max={360}\n min={0}\n value={hsva.h}\n classNames={{\n indicator: styles.hidden,\n thumb: styles.sliderThumb,\n track: styles.hueTrack,\n }}\n onChange={(h) => update({ ...hsva, h })}\n onChangeComplete={(h) => commit({ ...hsva, h })}\n />\n {alpha && (\n <Slider\n aria-label={t('colorPicker.alpha')}\n max={100}\n min={0}\n value={Math.round(hsva.a * 100)}\n classNames={{\n indicator: styles.hidden,\n thumb: styles.sliderThumb,\n track: styles.alphaTrack,\n }}\n styles={{\n track: {\n '--lobe-color-picker-alpha': formatColor(hsva, false),\n } as CSSProperties,\n }}\n onChange={(a) => update({ ...hsva, a: a / 100 })}\n onChangeComplete={(a) => commit({ ...hsva, a: a / 100 })}\n />\n )}\n <div className={styles.hexRow}>\n <Input\n aria-label=\"HEX\"\n prefix={<span className={panelStyles.label}>HEX</span>}\n value={draft}\n variant=\"filled\"\n onBlur={commitDraft}\n onChange={(event) => setDraft(event.target.value)}\n onPressEnter={commitDraft}\n />\n {alpha && (\n <InputNumber\n aria-label={t('colorPicker.alpha')}\n className={styles.alphaField}\n controls={false}\n max={100}\n min={0}\n suffix=\"%\"\n value={Math.round(hsva.a * 100)}\n variant=\"filled\"\n onChange={(a) => a !== null && apply({ ...hsva, a: a / 100 })}\n />\n )}\n </div>\n {presets && presets.length > 0 && (\n <div\n aria-label={t('colorPicker.presets')}\n className={styles.presets}\n role=\"group\"\n >\n {presets.map((color) => (\n <button\n aria-label={color}\n aria-pressed={color.toLowerCase() === hex.slice(0, 7).toLowerCase()}\n className={styles.preset}\n key={color}\n style={{ background: color }}\n type=\"button\"\n onClick={() =>\n apply({ ...parseColor(color, hsva.h), a: parseColor(color).a })\n }\n />\n ))}\n </div>\n )}\n </div>\n </PopoverPopup>\n </PopoverPositioner>\n </PopoverPortal>\n </PopoverRoot>\n );\n },\n);\n\nColorPicker.displayName = 'ColorPicker';\n\nexport default ColorPicker;\n"],"mappings":"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"}