@strapi/plugin-color-picker 4.13.0-beta.0 → 4.13.1

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.
@@ -1,4 +1,4 @@
1
- import React, { useRef, useState } from 'react';
1
+ import React, { forwardRef, useRef, useState } from 'react';
2
2
 
3
3
  import {
4
4
  BaseButton,
@@ -19,6 +19,7 @@ import { HexColorPicker } from 'react-colorful';
19
19
  import { useIntl } from 'react-intl';
20
20
  import styled from 'styled-components';
21
21
 
22
+ import { useComposedRefs } from '../../../hooks/useComposeRefs';
22
23
  import getTrad from '../../../utils/getTrad';
23
24
 
24
25
  const ColorPreview = styled.div`
@@ -74,112 +75,119 @@ const ColorPickerPopover = styled(Popover)`
74
75
  min-height: 270px;
75
76
  `;
76
77
 
77
- const ColorPickerInput = ({
78
- attribute,
79
- description,
80
- disabled,
81
- error,
82
- intlLabel,
83
- labelAction,
84
- name,
85
- onChange,
86
- required,
87
- value,
88
- }) => {
89
- const [showColorPicker, setShowColorPicker] = useState(false);
90
- const colorPickerButtonRef = useRef();
91
- const { formatMessage } = useIntl();
92
- const color = value || '#000000';
93
- const styleUppercase = { textTransform: 'uppercase' };
94
-
95
- const handleBlur = (e) => {
96
- e.preventDefault();
97
-
98
- if (!e.currentTarget.contains(e.relatedTarget)) {
99
- setShowColorPicker(false);
100
- }
101
- };
102
-
103
- return (
104
- <Field
105
- name={name}
106
- id={name}
107
- // GenericInput calls formatMessage and returns a string for the error
108
- error={error}
109
- hint={description && formatMessage(description)}
110
- required={required}
111
- >
112
- <Flex direction="column" alignItems="stretch" gap={1}>
113
- <FieldLabel action={labelAction}>{formatMessage(intlLabel)}</FieldLabel>
114
- <ColorPickerToggle
115
- ref={colorPickerButtonRef}
116
- aria-label={formatMessage({
117
- id: getTrad('color-picker.toggle.aria-label'),
118
- defaultMessage: 'Color picker toggle',
119
- })}
120
- aria-controls="color-picker-value"
121
- aria-haspopup="dialog"
122
- aria-expanded={showColorPicker}
123
- aria-disabled={disabled}
124
- disabled={disabled}
125
- onClick={() => setShowColorPicker(!showColorPicker)}
126
- >
127
- <Flex>
128
- <ColorPreview color={color} />
129
- <Typography
130
- style={styleUppercase}
131
- textColor={value ? null : 'neutral600'}
132
- variant="omega"
133
- >
134
- {color}
135
- </Typography>
136
- </Flex>
137
- <CarretDown aria-hidden />
138
- </ColorPickerToggle>
139
- {showColorPicker && (
140
- <ColorPickerPopover
141
- onBlur={handleBlur}
142
- role="dialog"
143
- source={colorPickerButtonRef}
144
- spacing={4}
78
+ const ColorPickerInput = forwardRef(
79
+ (
80
+ {
81
+ attribute,
82
+ description,
83
+ disabled,
84
+ error,
85
+ intlLabel,
86
+ labelAction,
87
+ name,
88
+ onChange,
89
+ required,
90
+ value,
91
+ },
92
+ forwardedRef
93
+ ) => {
94
+ const [showColorPicker, setShowColorPicker] = useState(false);
95
+ const colorPickerButtonRef = useRef();
96
+ const { formatMessage } = useIntl();
97
+ const color = value || '#000000';
98
+ const styleUppercase = { textTransform: 'uppercase' };
99
+
100
+ const handleBlur = (e) => {
101
+ e.preventDefault();
102
+
103
+ if (!e.currentTarget.contains(e.relatedTarget)) {
104
+ setShowColorPicker(false);
105
+ }
106
+ };
107
+
108
+ const composedRefs = useComposedRefs(forwardedRef, colorPickerButtonRef);
109
+
110
+ return (
111
+ <Field
112
+ name={name}
113
+ id={name}
114
+ // GenericInput calls formatMessage and returns a string for the error
115
+ error={error}
116
+ hint={description && formatMessage(description)}
117
+ required={required}
118
+ >
119
+ <Flex direction="column" alignItems="stretch" gap={1}>
120
+ <FieldLabel action={labelAction}>{formatMessage(intlLabel)}</FieldLabel>
121
+ <ColorPickerToggle
122
+ ref={composedRefs}
123
+ aria-label={formatMessage({
124
+ id: getTrad('color-picker.toggle.aria-label'),
125
+ defaultMessage: 'Color picker toggle',
126
+ })}
127
+ aria-controls="color-picker-value"
128
+ aria-haspopup="dialog"
129
+ aria-expanded={showColorPicker}
130
+ aria-disabled={disabled}
131
+ disabled={disabled}
132
+ onClick={() => setShowColorPicker(!showColorPicker)}
145
133
  >
146
- <FocusTrap onEscape={() => setShowColorPicker(false)}>
147
- <ColorPicker
148
- color={color}
149
- onChange={(hexValue) =>
150
- onChange({ target: { name, value: hexValue, type: attribute.type } })
151
- }
152
- />
153
- <Flex paddingTop={3} paddingLeft={4} justifyContent="flex-end">
154
- <Box paddingRight={2}>
155
- <Typography variant="omega" as="label" textColor="neutral600">
156
- {formatMessage({
157
- id: getTrad('color-picker.input.format'),
158
- defaultMessage: 'HEX',
159
- })}
160
- </Typography>
161
- </Box>
162
- <FieldInput
163
- id="color-picker-value"
164
- aria-label={formatMessage({
165
- id: getTrad('color-picker.input.aria-label'),
166
- defaultMessage: 'Color picker input',
167
- })}
168
- style={styleUppercase}
169
- value={value}
170
- placeholder="#000000"
171
- onChange={onChange}
134
+ <Flex>
135
+ <ColorPreview color={color} />
136
+ <Typography
137
+ style={styleUppercase}
138
+ textColor={value ? null : 'neutral600'}
139
+ variant="omega"
140
+ >
141
+ {color}
142
+ </Typography>
143
+ </Flex>
144
+ <CarretDown aria-hidden />
145
+ </ColorPickerToggle>
146
+ {showColorPicker && (
147
+ <ColorPickerPopover
148
+ onBlur={handleBlur}
149
+ role="dialog"
150
+ source={colorPickerButtonRef}
151
+ spacing={4}
152
+ >
153
+ <FocusTrap onEscape={() => setShowColorPicker(false)}>
154
+ <ColorPicker
155
+ color={color}
156
+ onChange={(hexValue) =>
157
+ onChange({ target: { name, value: hexValue, type: attribute.type } })
158
+ }
172
159
  />
173
- </Flex>
174
- </FocusTrap>
175
- </ColorPickerPopover>
176
- )}
177
- <FieldHint />
178
- <FieldError />
179
- </Flex>
180
- </Field>
181
- );
182
- };
160
+ <Flex paddingTop={3} paddingLeft={4} justifyContent="flex-end">
161
+ <Box paddingRight={2}>
162
+ <Typography variant="omega" as="label" textColor="neutral600">
163
+ {formatMessage({
164
+ id: getTrad('color-picker.input.format'),
165
+ defaultMessage: 'HEX',
166
+ })}
167
+ </Typography>
168
+ </Box>
169
+ <FieldInput
170
+ id="color-picker-value"
171
+ aria-label={formatMessage({
172
+ id: getTrad('color-picker.input.aria-label'),
173
+ defaultMessage: 'Color picker input',
174
+ })}
175
+ style={styleUppercase}
176
+ value={value}
177
+ placeholder="#000000"
178
+ onChange={onChange}
179
+ />
180
+ </Flex>
181
+ </FocusTrap>
182
+ </ColorPickerPopover>
183
+ )}
184
+ <FieldHint />
185
+ <FieldError />
186
+ </Flex>
187
+ </Field>
188
+ );
189
+ }
190
+ );
183
191
 
184
192
  ColorPickerInput.defaultProps = {
185
193
  description: null,
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Set a given ref to a given value
5
+ * This utility takes care of different types of refs: callback refs and RefObject(s)
6
+ */
7
+ function setRef(ref, value) {
8
+ if (typeof ref === 'function') {
9
+ ref(value);
10
+ } else if (ref !== null && ref !== undefined) {
11
+ ref.current = value;
12
+ }
13
+ }
14
+
15
+ /**
16
+ * A utility to compose multiple refs together
17
+ * Accepts callback refs and RefObject(s)
18
+ */
19
+ function composeRefs(...refs) {
20
+ return (node) => refs.forEach((ref) => setRef(ref, node));
21
+ }
22
+
23
+ /**
24
+ * Takes multiple React like refs either React.Ref or a callback:
25
+ * (node: T) => void and returns a single function that can be
26
+ * passed to a React component as a ref.
27
+ *
28
+ * Example:
29
+ * ```tsx
30
+ * import { useComposedRefs } from '../hooks/useComposedRefs';
31
+ *
32
+ * const Component = React.forwardRef<HTMLInputElement, ComponentProps>((props, forwardedRef) => {
33
+ * const ref = useComposedRefs(internalRef, forwardedRef);
34
+ *
35
+ * React.useEffect(() => {
36
+ * ref.current.focus();
37
+ * }, [ref]);
38
+ *
39
+ * return <input ref={ref} />
40
+ * }
41
+ * ```
42
+ */
43
+ function useComposedRefs(...refs) {
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ return React.useCallback(composeRefs(...refs), refs);
46
+ }
47
+
48
+ export { composeRefs, useComposedRefs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/plugin-color-picker",
3
- "version": "4.13.0-beta.0",
3
+ "version": "4.13.1",
4
4
  "description": "Strapi maintained Custom Fields",
5
5
  "strapi": {
6
6
  "name": "color-picker",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@strapi/design-system": "1.9.0",
13
- "@strapi/helper-plugin": "4.13.0-beta.0",
13
+ "@strapi/helper-plugin": "4.13.1",
14
14
  "@strapi/icons": "1.9.0",
15
15
  "prop-types": "^15.8.1",
16
16
  "react-colorful": "5.6.1",
@@ -70,5 +70,5 @@
70
70
  "node": ">=16.0.0 <=20.x.x",
71
71
  "npm": ">=6.0.0"
72
72
  },
73
- "gitHead": "f1b8431a6a0b7f9bd9a8444adb56217bba91ec07"
73
+ "gitHead": "a9afeb90c525d9b8ab033aa0c87e03a72134e0dd"
74
74
  }