UNPKG

sanity-plugin-simpler-color-input

Version:
274 lines (273 loc) 10.9 kB
import { set, unset, defineType, definePlugin } from "sanity"; import { jsx, jsxs } from "react/jsx-runtime"; import { ChevronDownIcon, CloseIcon, SearchIcon } from "@sanity/icons"; import { Container, Popover, Flex, Button, Box, Card, Text, Inline, TextInput, Stack } from "@sanity/ui"; import { useState, useCallback, useRef, useEffect } from "react"; import { BiHighlight, BiFontColor } from "react-icons/bi"; import styled from "styled-components"; const SimplerColorInput = (props) => { const [isOpen, setIsOpen] = useState(!1), [pickerIsOpen, setPickerIsOpen] = useState(!1), [searchValue, setSearchValue] = useState(""), { onChange } = props, value = props.value, type = props.schemaType, showColorValue = !!(type.options?.showColorValue ?? !0), [selectedColor, setSelectedColor] = useState(value), handleChange = useCallback( (color) => { setSelectedColor(color), setIsOpen(!1), onChange(set({ ...props.value, ...color })); }, [onChange, props.value] ), colorList = type.options?.colorList || type.type?.options?.defaultColorList, colorFormat = type.options?.colorFormat ?? type.type?.options?.defaultColorFormat, enableSearch = !!(type.options?.enableSearch ?? type.type?.options?.enableSearch), filteredColorList = searchValue.length ? colorList?.filter((color) => color.label.toLowerCase().includes(searchValue.toLowerCase())) : colorList, handlePickerChange = (color) => { let colorValue; switch (colorFormat) { case "hexa": colorValue = color.hexa; break; case "rgb": colorValue = `rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`; break; case "rgba": colorValue = `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${color.rgba.a.toFixed(2)})`; break; case "hsl": colorValue = `hsl(${color.hsl.h.toFixed(0)}, ${color.hsl.s.toFixed( 0 )}%, ${color.hsl.l.toFixed(0)}%)`; break; case "hsla": colorValue = `hsla(${color.hsla.h.toFixed(0)}, ${color.hsla.s.toFixed( 0 )}%, ${color.hsla.l.toFixed(0)}%, ${color.hsla.a.toFixed(2)})`; break; default: colorValue = color.hex; break; } const formattedColor = { label: "Custom", value: colorValue }; setSelectedColor(formattedColor), onChange(set({ ...props.value, ...formattedColor })); }, ref = useRef(null); useEffect(() => { isOpen || setSearchValue(""); const handleClickOutside = (event) => { ref.current && !ref.current.contains(event.target) && (setPickerIsOpen(!1), setIsOpen(!1)); }; return document.addEventListener("click", handleClickOutside, !0), () => { document.removeEventListener("click", handleClickOutside, !0); }; }, [isOpen, pickerIsOpen, ref]); const isRequired = type.validation[0]._required === "required", [Component, setComponent] = useState(/* @__PURE__ */ jsx("div", { children: "Loading..." })); return useEffect(() => { import("@uiw/react-color").then((module) => { const { Chrome, rgbStringToHsva, hslStringToHsva } = module; let pickerColor = selectedColor?.value || "#ffffff"; pickerColor.startsWith("rgb") ? pickerColor = rgbStringToHsva(pickerColor) : pickerColor.startsWith("hsl") && (pickerColor = hslStringToHsva(pickerColor)), setComponent( /* @__PURE__ */ jsxs(Container, { children: [ /* @__PURE__ */ jsx( Popover, { ref, content: /* @__PURE__ */ jsx( Chrome, { onChange: handlePickerChange, color: pickerColor, showAlpha: colorFormat ? colorFormat.slice(-1) === "a" : !1 } ), portal: !0, open: pickerIsOpen, children: /* @__PURE__ */ jsxs(Flex, { children: [ /* @__PURE__ */ jsx( Button, { style: { width: "100%", textAlign: "center", borderTopRightRadius: isRequired ? "" : "0", borderBottomRightRadius: isRequired ? "" : "0", flexShrink: 1, overflow: "hidden" }, mode: "ghost", padding: 2, onClick: () => colorList && colorList.length > 0 ? setIsOpen(!isOpen) : setPickerIsOpen(!pickerIsOpen), children: /* @__PURE__ */ jsxs(Flex, { justify: "center", gap: 4, children: [ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 1, overflow: "hidden", children: [ /* @__PURE__ */ jsx(Box, { style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx( Card, { style: { backgroundColor: selectedColor?.value || "#ffffff" }, radius: 2, shadow: 1, padding: 2, margin: 1 } ) }), /* @__PURE__ */ jsx(Box, { style: { ...showColorValue && { flexShrink: 0 } }, children: /* @__PURE__ */ jsxs(Text, { weight: "semibold", textOverflow: "ellipsis", children: [ selectedColor?.label || "Select a color...", " " ] }) }), showColorValue && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { textOverflow: "ellipsis", children: selectedColor?.value }) }) ] }), /* @__PURE__ */ jsx(ChevronDownIcon, { style: { flexShrink: 0 }, width: 32, height: 32 }) ] }) } ), !isRequired && /* @__PURE__ */ jsx( Button, { mode: "ghost", onClick: () => { if (value !== void 0 && value._key) { const annotationValue = { _type: value._type, _key: value._key }; setSelectedColor(annotationValue), onChange(set(annotationValue)); } else setSelectedColor(void 0), onChange(unset()); }, style: { borderTopLeftRadius: "0", borderBottomLeftRadius: "0" }, children: /* @__PURE__ */ jsxs(Inline, { space: 1, children: [ /* @__PURE__ */ jsx(CloseIcon, { width: 24, height: 24 }), /* @__PURE__ */ jsx(Text, { weight: "semibold", children: "Clear" }) ] }) } ) ] }) } ), isOpen && colorList && /* @__PURE__ */ jsxs(Card, { radius: 2, shadow: 3, marginTop: 1, overflow: "hidden", children: [ enableSearch && /* @__PURE__ */ jsx( Box, { padding: 3, style: { borderBottom: "1px solid var(--card-border-color)" }, children: /* @__PURE__ */ jsx( TextInput, { icon: SearchIcon, radius: 2, placeholder: "Search", onChange: (event) => { setSearchValue(event.currentTarget.value); }, autoFocus: !0 } ) } ), /* @__PURE__ */ jsx(Stack, { children: filteredColorList?.map( (color) => color.value === "custom" ? /* @__PURE__ */ jsx( Button, { radius: 0, mode: "bleed", onClick: () => { setIsOpen(!1), setPickerIsOpen(!0); }, children: /* @__PURE__ */ jsx(Text, { children: color.label }) }, color.label ) : /* @__PURE__ */ jsx( Button, { radius: 0, mode: "bleed", onClick: () => handleChange(color), children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Inline, { space: 3, children: [ /* @__PURE__ */ jsx( Card, { style: { backgroundColor: color.value, width: "16px", height: "16px" }, radius: 2, shadow: 1 } ), /* @__PURE__ */ jsx(Text, { children: color.label }) ] }) }) }, color.label ) ) }) ] }) ] }) ); }); }, [isOpen, selectedColor, searchValue, pickerIsOpen]), Component; }, ColorSpan$1 = styled.span` & > span { background-color: ${({ color }) => color}; border-bottom: unset; color: inherit; } `, HighlightColorAnnotation = (props) => /* @__PURE__ */ jsx(ColorSpan$1, { color: props.value?.value || "", children: props.renderDefault(props) }), highlightColor = defineType({ title: "Highlight color", type: "object", name: "highlightColor", icon: BiHighlight, components: { annotation: HighlightColorAnnotation, input: SimplerColorInput }, fields: [ { name: "label", type: "string" }, { name: "value", type: "string" } ] }), simplerColor = defineType({ title: "Simpler Color", type: "object", name: "simplerColor", components: { input: SimplerColorInput }, fields: [ { name: "label", type: "string" }, { name: "value", type: "string" } ] }), ColorSpan = styled.span` & > span { background-color: inherit; border-bottom: unset; color: ${({ color }) => color}; } `, TextColorAnnotation = (props) => /* @__PURE__ */ jsx(ColorSpan, { color: props.value?.value || "", children: props.renderDefault(props) }), textColor = defineType({ title: "Text color", type: "object", name: "textColor", icon: BiFontColor, components: { annotation: TextColorAnnotation, input: SimplerColorInput }, fields: [ { name: "label", type: "string" }, { name: "value", type: "string" } ] }), simplerColorInput = definePlugin((options) => ({ name: "sanity-plugin-simpler-color-input", schema: { types: [ { ...simplerColor, options }, { ...textColor, options }, { ...highlightColor, options } ] } })); export { SimplerColorInput, simplerColorInput }; //# sourceMappingURL=index.mjs.map