@nouance/payload-better-fields-plugin
Version:
A Payload plugin that aims to provide improved fields for the admin panel
157 lines (156 loc) • 6.33 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { RenderCustomComponent, useField } from '@payloadcms/ui';
import { FieldDescription } from '@payloadcms/ui/fields/FieldDescription';
import { FieldLabel } from '@payloadcms/ui/fields/FieldLabel';
import { useDebouncedCallback } from '@payloadcms/ui/hooks/useDebouncedCallback';
import { extend } from 'colord';
import namesPlugin from 'colord/plugins/names';
import React, { useCallback, useMemo, useState } from 'react';
import { HexAlphaColorPicker, HexColorPicker, HslaStringColorPicker, HslStringColorPicker, RgbaStringColorPicker, RgbStringColorPicker } from 'react-colorful';
import './styles.css';
// @ts-expect-error - unknown lib issue
extend([
namesPlugin
]);
const ColourComponents = {
hex: HexColorPicker,
hexA: HexAlphaColorPicker,
hsl: HslStringColorPicker,
hslA: HslaStringColorPicker,
rgb: RgbStringColorPicker,
rgbA: RgbaStringColorPicker
};
export const ColourPickerComponent = (props)=>{
const { type, expanded = false, field: { admin: { description } = {}, label, required }, inputRef, path, readOnly, showPreview, validate } = props;
const memoizedValidate = useCallback((value, options)=>{
if (typeof validate === 'function') {
return validate(value, {
...options,
required
});
}
}, [
validate,
required
]);
const isReadonly = Boolean(readOnly);
const { customComponents: { AfterInput, BeforeInput, Description, Label } = {}, setValue, value } = useField({
path,
// @ts-expect-error - memoizedValidate is not typed
validate: memoizedValidate
});
const [isAdding, setIsAdding] = useState(expanded);
const Picker = useMemo(()=>{
return type ? ColourComponents[type] : ColourComponents['hex'];
}, [
type
]);
// Had to debounce it here so it doesn't error with maxdepth
const debouncedAddColor = useDebouncedCallback((val)=>{
if (val !== value && !isReadonly) {
setValue(val);
if (inputRef?.current) {
inputRef.current.value = val ?? '';
}
}
}, 150);
const handleAddColor = useCallback((val)=>{
if (val !== value && !isReadonly) {
setValue(val);
}
}, [
value,
isReadonly,
setValue
]);
const labelToUse = label;
return /*#__PURE__*/ _jsxs("div", {
className: `bfColourPickerFieldWrapper`,
children: [
/*#__PURE__*/ _jsx(RenderCustomComponent, {
CustomComponent: Label,
Fallback: /*#__PURE__*/ _jsx(FieldLabel, {
label: labelToUse,
path: path,
required: required
})
}),
BeforeInput,
(expanded || isAdding) && /*#__PURE__*/ _jsxs("div", {
className: "expandedContainer",
children: [
/*#__PURE__*/ _jsx("div", {
className: [
'colourPickerWrapper',
isReadonly && 'readOnly'
].filter(Boolean).join(' '),
// @ts-expect-error - inert is not a valid attribute
inert: isReadonly ? '' : null,
children: /*#__PURE__*/ _jsx(Picker, {
color: value || '',
onBlur: (e)=>{
if (e.relatedTarget === null) {
setIsAdding(false);
}
},
onChange: debouncedAddColor,
onKeyDown: (e)=>(e.key === 'Enter' || e.key === 'Escape') && setIsAdding(false)
})
}),
/*#__PURE__*/ _jsx("input", {
className: `manual-field-input`,
id: `field-${path}`,
onChange: ({ currentTarget })=>{
handleAddColor(currentTarget.value);
},
readOnly: isReadonly,
ref: inputRef,
value: value || ''
})
]
}),
!expanded && /*#__PURE__*/ _jsxs("div", {
className: "buttonContainer",
children: [
/*#__PURE__*/ _jsx("button", {
"aria-label": value,
className: `chip chip--clickable`,
onClick: ()=>{
setIsAdding(!isAdding);
},
style: {
backgroundColor: value
},
type: "button"
}),
showPreview && /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("label", {
className: "srOnly",
htmlFor: `bfColourPickerField-previewField-${path.replace(/\./g, '__')}`,
children: "Preview"
}),
/*#__PURE__*/ _jsx("input", {
className: "previewField",
disabled: true,
id: `bfColourPickerField-previewField-${path.replace(/\./g, '__')}`,
value: value
})
]
})
]
}),
/*#__PURE__*/ _jsx(RenderCustomComponent, {
CustomComponent: Description,
Fallback: /*#__PURE__*/ _jsx(FieldDescription, {
className: `field-description-${path.replace(/\./g, '__')}`,
description: description ?? '',
path: path
})
}),
AfterInput
]
});
};
//# sourceMappingURL=Component.js.map