@webbycrown/advanced-fields 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const reactColor = require("react-color");
6
+ const reactIntl = require("react-intl");
7
+ const designSystem = require("@strapi/design-system");
8
+ const normalizeHexColor = (value) => {
9
+ if (!value) return "";
10
+ const raw = String(value).trim();
11
+ if (!raw) return "";
12
+ const withHash = raw.startsWith("#") ? raw : `#${raw}`;
13
+ return withHash;
14
+ };
15
+ const isValidHexColor = (value) => {
16
+ if (!value) return false;
17
+ const v = normalizeHexColor(value);
18
+ return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v);
19
+ };
20
+ const AdvancedColor = ({
21
+ attribute = {},
22
+ description = { id: "", defaultMessage: "" },
23
+ disabled,
24
+ error,
25
+ intlLabel = { id: "", defaultMessage: "" },
26
+ name,
27
+ onChange,
28
+ required,
29
+ value
30
+ }) => {
31
+ const { formatMessage } = reactIntl.useIntl();
32
+ const containerRef = react.useRef(null);
33
+ const { options = {} } = attribute;
34
+ const {
35
+ defaultValue = "",
36
+ customErrorMessage = "",
37
+ fieldNote = ""
38
+ } = options;
39
+ const fieldNoteFromAttribute = attribute.options?.fieldNote || "";
40
+ const initialColor = react.useMemo(() => {
41
+ const normalized = value === void 0 ? defaultValue : value;
42
+ return normalizeHexColor(normalized);
43
+ }, [value, defaultValue]);
44
+ const [inputValue, setInputValue] = react.useState(initialColor);
45
+ const [validationError, setValidationError] = react.useState(null);
46
+ const [hasInteracted, setHasInteracted] = react.useState(false);
47
+ const [isPickerOpen, setIsPickerOpen] = react.useState(false);
48
+ react.useEffect(() => {
49
+ setInputValue(initialColor);
50
+ if (error) setValidationError(error);
51
+ }, [initialColor, error]);
52
+ react.useEffect(() => {
53
+ if (!isPickerOpen) return;
54
+ const onDocumentMouseDown = (e) => {
55
+ if (!containerRef.current) return;
56
+ if (containerRef.current.contains(e.target)) return;
57
+ setIsPickerOpen(false);
58
+ };
59
+ document.addEventListener("mousedown", onDocumentMouseDown);
60
+ return () => document.removeEventListener("mousedown", onDocumentMouseDown);
61
+ }, [isPickerOpen]);
62
+ const validateColor = (val) => {
63
+ if (required && (!val || String(val).trim().length === 0)) {
64
+ return customErrorMessage || "This field is required";
65
+ }
66
+ if (!val || String(val).trim().length === 0) return null;
67
+ if (!isValidHexColor(val)) {
68
+ return customErrorMessage || "Invalid color (use hex like #RRGGBB)";
69
+ }
70
+ return null;
71
+ };
72
+ const displayError = error || hasInteracted && validationError;
73
+ const handleChangeFromPicker = (pickerColor2) => {
74
+ const hex = pickerColor2?.hex ? String(pickerColor2.hex).toUpperCase() : "";
75
+ setInputValue(hex);
76
+ setHasInteracted(true);
77
+ const nextError = validateColor(hex);
78
+ setValidationError(nextError);
79
+ if (onChange) {
80
+ onChange({
81
+ target: {
82
+ name,
83
+ id: name,
84
+ type: attribute?.type || "string",
85
+ value: hex
86
+ }
87
+ });
88
+ }
89
+ };
90
+ const pickerColor = isValidHexColor(inputValue) ? inputValue : "#FFFFFF";
91
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name, error: displayError, children: [
92
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Label, { children: [
93
+ intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || name,
94
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#d02b20", marginLeft: "4px" }, children: "*" })
95
+ ] }),
96
+ /* @__PURE__ */ jsxRuntime.jsxs(
97
+ designSystem.Box,
98
+ {
99
+ style: {
100
+ position: "relative",
101
+ marginBottom: "12px"
102
+ },
103
+ ref: containerRef,
104
+ children: [
105
+ /* @__PURE__ */ jsxRuntime.jsxs(
106
+ "button",
107
+ {
108
+ type: "button",
109
+ onClick: () => !disabled && setIsPickerOpen((v) => !v),
110
+ style: {
111
+ width: "100%",
112
+ display: "flex",
113
+ alignItems: "center",
114
+ justifyContent: "space-between",
115
+ gap: "12px",
116
+ padding: "8px 10px",
117
+ borderRadius: "4px",
118
+ border: `1px solid ${displayError ? "#d02b20" : "#dcdce4"}`,
119
+ backgroundColor: disabled ? "#f6f6f9" : "#ffffff",
120
+ cursor: disabled ? "not-allowed" : "pointer",
121
+ fontFamily: "inherit"
122
+ },
123
+ children: [
124
+ /* @__PURE__ */ jsxRuntime.jsxs(
125
+ "span",
126
+ {
127
+ style: {
128
+ display: "inline-flex",
129
+ alignItems: "center",
130
+ gap: "10px"
131
+ },
132
+ children: [
133
+ /* @__PURE__ */ jsxRuntime.jsx(
134
+ "span",
135
+ {
136
+ style: {
137
+ width: "18px",
138
+ height: "18px",
139
+ borderRadius: "4px",
140
+ backgroundColor: pickerColor,
141
+ border: "1px solid rgba(0,0,0,0.12)"
142
+ }
143
+ }
144
+ ),
145
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#32324d", fontSize: "14px" }, children: pickerColor })
146
+ ]
147
+ }
148
+ ),
149
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#666" }, children: isPickerOpen ? "▲" : "▼" })
150
+ ]
151
+ }
152
+ ),
153
+ isPickerOpen && !disabled && /* @__PURE__ */ jsxRuntime.jsx(
154
+ "div",
155
+ {
156
+ style: {
157
+ position: "absolute",
158
+ top: "calc(100% + 6px)",
159
+ left: 0,
160
+ zIndex: 50
161
+ },
162
+ children: /* @__PURE__ */ jsxRuntime.jsx(
163
+ reactColor.ChromePicker,
164
+ {
165
+ color: pickerColor,
166
+ onChange: handleChangeFromPicker
167
+ }
168
+ )
169
+ }
170
+ )
171
+ ]
172
+ }
173
+ ),
174
+ displayError && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: displayError }),
175
+ description && (description.id || description.defaultMessage) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: description.id ? formatMessage(description) : description.defaultMessage }),
176
+ (fieldNote || fieldNoteFromAttribute) && /* @__PURE__ */ jsxRuntime.jsx(
177
+ "span",
178
+ {
179
+ style: {
180
+ fontStyle: "italic",
181
+ color: "#666",
182
+ fontSize: "12px",
183
+ display: "block",
184
+ marginTop: "4px"
185
+ },
186
+ children: fieldNote || fieldNoteFromAttribute
187
+ }
188
+ )
189
+ ] }) });
190
+ };
191
+ exports.default = AdvancedColor;
@@ -0,0 +1,191 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useRef, useMemo, useState, useEffect } from "react";
3
+ import { ChromePicker } from "react-color";
4
+ import { useIntl } from "react-intl";
5
+ import { Box, Field } from "@strapi/design-system";
6
+ const normalizeHexColor = (value) => {
7
+ if (!value) return "";
8
+ const raw = String(value).trim();
9
+ if (!raw) return "";
10
+ const withHash = raw.startsWith("#") ? raw : `#${raw}`;
11
+ return withHash;
12
+ };
13
+ const isValidHexColor = (value) => {
14
+ if (!value) return false;
15
+ const v = normalizeHexColor(value);
16
+ return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v);
17
+ };
18
+ const AdvancedColor = ({
19
+ attribute = {},
20
+ description = { id: "", defaultMessage: "" },
21
+ disabled,
22
+ error,
23
+ intlLabel = { id: "", defaultMessage: "" },
24
+ name,
25
+ onChange,
26
+ required,
27
+ value
28
+ }) => {
29
+ const { formatMessage } = useIntl();
30
+ const containerRef = useRef(null);
31
+ const { options = {} } = attribute;
32
+ const {
33
+ defaultValue = "",
34
+ customErrorMessage = "",
35
+ fieldNote = ""
36
+ } = options;
37
+ const fieldNoteFromAttribute = attribute.options?.fieldNote || "";
38
+ const initialColor = useMemo(() => {
39
+ const normalized = value === void 0 ? defaultValue : value;
40
+ return normalizeHexColor(normalized);
41
+ }, [value, defaultValue]);
42
+ const [inputValue, setInputValue] = useState(initialColor);
43
+ const [validationError, setValidationError] = useState(null);
44
+ const [hasInteracted, setHasInteracted] = useState(false);
45
+ const [isPickerOpen, setIsPickerOpen] = useState(false);
46
+ useEffect(() => {
47
+ setInputValue(initialColor);
48
+ if (error) setValidationError(error);
49
+ }, [initialColor, error]);
50
+ useEffect(() => {
51
+ if (!isPickerOpen) return;
52
+ const onDocumentMouseDown = (e) => {
53
+ if (!containerRef.current) return;
54
+ if (containerRef.current.contains(e.target)) return;
55
+ setIsPickerOpen(false);
56
+ };
57
+ document.addEventListener("mousedown", onDocumentMouseDown);
58
+ return () => document.removeEventListener("mousedown", onDocumentMouseDown);
59
+ }, [isPickerOpen]);
60
+ const validateColor = (val) => {
61
+ if (required && (!val || String(val).trim().length === 0)) {
62
+ return customErrorMessage || "This field is required";
63
+ }
64
+ if (!val || String(val).trim().length === 0) return null;
65
+ if (!isValidHexColor(val)) {
66
+ return customErrorMessage || "Invalid color (use hex like #RRGGBB)";
67
+ }
68
+ return null;
69
+ };
70
+ const displayError = error || hasInteracted && validationError;
71
+ const handleChangeFromPicker = (pickerColor2) => {
72
+ const hex = pickerColor2?.hex ? String(pickerColor2.hex).toUpperCase() : "";
73
+ setInputValue(hex);
74
+ setHasInteracted(true);
75
+ const nextError = validateColor(hex);
76
+ setValidationError(nextError);
77
+ if (onChange) {
78
+ onChange({
79
+ target: {
80
+ name,
81
+ id: name,
82
+ type: attribute?.type || "string",
83
+ value: hex
84
+ }
85
+ });
86
+ }
87
+ };
88
+ const pickerColor = isValidHexColor(inputValue) ? inputValue : "#FFFFFF";
89
+ return /* @__PURE__ */ jsx(Box, { col: 6, children: /* @__PURE__ */ jsxs(Field.Root, { name, error: displayError, children: [
90
+ /* @__PURE__ */ jsxs(Field.Label, { children: [
91
+ intlLabel.id ? formatMessage(intlLabel) : intlLabel.defaultMessage || name,
92
+ required && /* @__PURE__ */ jsx("span", { style: { color: "#d02b20", marginLeft: "4px" }, children: "*" })
93
+ ] }),
94
+ /* @__PURE__ */ jsxs(
95
+ Box,
96
+ {
97
+ style: {
98
+ position: "relative",
99
+ marginBottom: "12px"
100
+ },
101
+ ref: containerRef,
102
+ children: [
103
+ /* @__PURE__ */ jsxs(
104
+ "button",
105
+ {
106
+ type: "button",
107
+ onClick: () => !disabled && setIsPickerOpen((v) => !v),
108
+ style: {
109
+ width: "100%",
110
+ display: "flex",
111
+ alignItems: "center",
112
+ justifyContent: "space-between",
113
+ gap: "12px",
114
+ padding: "8px 10px",
115
+ borderRadius: "4px",
116
+ border: `1px solid ${displayError ? "#d02b20" : "#dcdce4"}`,
117
+ backgroundColor: disabled ? "#f6f6f9" : "#ffffff",
118
+ cursor: disabled ? "not-allowed" : "pointer",
119
+ fontFamily: "inherit"
120
+ },
121
+ children: [
122
+ /* @__PURE__ */ jsxs(
123
+ "span",
124
+ {
125
+ style: {
126
+ display: "inline-flex",
127
+ alignItems: "center",
128
+ gap: "10px"
129
+ },
130
+ children: [
131
+ /* @__PURE__ */ jsx(
132
+ "span",
133
+ {
134
+ style: {
135
+ width: "18px",
136
+ height: "18px",
137
+ borderRadius: "4px",
138
+ backgroundColor: pickerColor,
139
+ border: "1px solid rgba(0,0,0,0.12)"
140
+ }
141
+ }
142
+ ),
143
+ /* @__PURE__ */ jsx("span", { style: { color: "#32324d", fontSize: "14px" }, children: pickerColor })
144
+ ]
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: isPickerOpen ? "▲" : "▼" })
148
+ ]
149
+ }
150
+ ),
151
+ isPickerOpen && !disabled && /* @__PURE__ */ jsx(
152
+ "div",
153
+ {
154
+ style: {
155
+ position: "absolute",
156
+ top: "calc(100% + 6px)",
157
+ left: 0,
158
+ zIndex: 50
159
+ },
160
+ children: /* @__PURE__ */ jsx(
161
+ ChromePicker,
162
+ {
163
+ color: pickerColor,
164
+ onChange: handleChangeFromPicker
165
+ }
166
+ )
167
+ }
168
+ )
169
+ ]
170
+ }
171
+ ),
172
+ displayError && /* @__PURE__ */ jsx(Field.Error, { children: displayError }),
173
+ description && (description.id || description.defaultMessage) && /* @__PURE__ */ jsx(Field.Hint, { children: description.id ? formatMessage(description) : description.defaultMessage }),
174
+ (fieldNote || fieldNoteFromAttribute) && /* @__PURE__ */ jsx(
175
+ "span",
176
+ {
177
+ style: {
178
+ fontStyle: "italic",
179
+ color: "#666",
180
+ fontSize: "12px",
181
+ display: "block",
182
+ marginTop: "4px"
183
+ },
184
+ children: fieldNote || fieldNoteFromAttribute
185
+ }
186
+ )
187
+ ] }) });
188
+ };
189
+ export {
190
+ AdvancedColor as default
191
+ };