@contentful/field-editor-number 1.2.5 → 1.2.6
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.
- package/CHANGELOG.md +4 -0
- package/dist/field-editor-number.cjs.development.js +57 -69
- package/dist/field-editor-number.cjs.development.js.map +1 -1
- package/dist/field-editor-number.cjs.production.min.js +1 -1
- package/dist/field-editor-number.cjs.production.min.js.map +1 -1
- package/dist/field-editor-number.esm.js +57 -69
- package/dist/field-editor-number.esm.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.2.6](https://github.com/contentful/field-editors/compare/@contentful/field-editor-number@1.2.5...@contentful/field-editor-number@1.2.6) (2023-04-19)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @contentful/field-editor-number
|
|
9
|
+
|
|
6
10
|
## [1.2.5](https://github.com/contentful/field-editors/compare/@contentful/field-editor-number@1.2.4...@contentful/field-editor-number@1.2.5) (2023-03-14)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @contentful/field-editor-number
|
|
@@ -11,7 +11,7 @@ var fieldEditorShared = require('@contentful/field-editor-shared');
|
|
|
11
11
|
var tokens = _interopDefault(require('@contentful/f36-tokens'));
|
|
12
12
|
var emotion = require('emotion');
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const styles = {
|
|
15
15
|
container: /*#__PURE__*/emotion.css({
|
|
16
16
|
position: 'relative'
|
|
17
17
|
}),
|
|
@@ -33,7 +33,7 @@ var styles = {
|
|
|
33
33
|
padding: 0,
|
|
34
34
|
margin: 0,
|
|
35
35
|
outline: 'none',
|
|
36
|
-
border:
|
|
36
|
+
border: `0 solid ${tokens.gray300}`,
|
|
37
37
|
background: 'none',
|
|
38
38
|
borderLeftWidth: '1px',
|
|
39
39
|
'&:first-of-type': {
|
|
@@ -65,27 +65,25 @@ function parseNumber(value, type) {
|
|
|
65
65
|
|
|
66
66
|
return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
const FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;
|
|
69
|
+
const INT_REGEX = /^[+-]?([0-9]*)$/;
|
|
70
70
|
function isNumberInputValueValid(value, type) {
|
|
71
|
-
|
|
71
|
+
const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;
|
|
72
72
|
return regex.test(value);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return validation.range;
|
|
79
|
-
});
|
|
75
|
+
const getRangeFromField = field => {
|
|
76
|
+
const validations = field.validations || [];
|
|
77
|
+
const result = validations.find(validation => validation.range);
|
|
80
78
|
return result ? result.range : {};
|
|
81
79
|
};
|
|
82
|
-
|
|
80
|
+
const valueToString = value => {
|
|
83
81
|
return value === undefined ? '' : String(value);
|
|
84
82
|
};
|
|
85
|
-
|
|
86
|
-
var _number$toString$spli
|
|
83
|
+
const countDecimals = number => {
|
|
84
|
+
var _number$toString$spli;
|
|
87
85
|
|
|
88
|
-
return (_number$toString$spli =
|
|
86
|
+
return ((_number$toString$spli = number.toString().split('.')[1]) == null ? void 0 : _number$toString$spli.length) ?? 0;
|
|
89
87
|
};
|
|
90
88
|
|
|
91
89
|
var StepChangeType;
|
|
@@ -95,23 +93,20 @@ var StepChangeType;
|
|
|
95
93
|
StepChangeType["Decrement"] = "decrement";
|
|
96
94
|
})(StepChangeType || (StepChangeType = {}));
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
function InnerNumberEditor(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
var inputRef = React.useRef(null);
|
|
113
|
-
React.useEffect(function () {
|
|
114
|
-
var stringSdkValue = valueToString(sdkValue); // Update the input value if the SDK value (numeric) changes
|
|
96
|
+
const NUMBER_STEP = 1;
|
|
97
|
+
|
|
98
|
+
function InnerNumberEditor({
|
|
99
|
+
disabled,
|
|
100
|
+
errors,
|
|
101
|
+
field,
|
|
102
|
+
setValue,
|
|
103
|
+
value: sdkValue
|
|
104
|
+
}) {
|
|
105
|
+
const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));
|
|
106
|
+
const range = getRangeFromField(field);
|
|
107
|
+
const inputRef = React.useRef(null);
|
|
108
|
+
React.useEffect(() => {
|
|
109
|
+
const stringSdkValue = valueToString(sdkValue); // Update the input value if the SDK value (numeric) changes
|
|
115
110
|
|
|
116
111
|
if (stringSdkValue !== inputValue) {
|
|
117
112
|
setInputValue(stringSdkValue);
|
|
@@ -119,15 +114,15 @@ function InnerNumberEditor(_ref) {
|
|
|
119
114
|
|
|
120
115
|
}, [sdkValue]);
|
|
121
116
|
|
|
122
|
-
|
|
117
|
+
const updateExternalValue = value => {
|
|
123
118
|
if (sdkValue !== value) {
|
|
124
119
|
setValue(value);
|
|
125
120
|
}
|
|
126
121
|
};
|
|
127
122
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
123
|
+
const changeValueByStep = type => {
|
|
124
|
+
const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;
|
|
125
|
+
let nextValue = type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP; // Floating point numbers cannot represent all decimals precisely in binary.
|
|
131
126
|
// This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.
|
|
132
127
|
// See more details: https://floating-point-gui.de/
|
|
133
128
|
|
|
@@ -137,23 +132,19 @@ function InnerNumberEditor(_ref) {
|
|
|
137
132
|
}; // Keeps focus on the input
|
|
138
133
|
|
|
139
134
|
|
|
140
|
-
|
|
135
|
+
const handleControlPointerDown = event => {
|
|
141
136
|
var _inputRef$current;
|
|
142
137
|
|
|
143
138
|
event.preventDefault();
|
|
144
139
|
(_inputRef$current = inputRef.current) == null ? void 0 : _inputRef$current.focus();
|
|
145
140
|
};
|
|
146
141
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
ArrowUp:
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
ArrowDown: function ArrowDown() {
|
|
153
|
-
return changeValueByStep(StepChangeType.Decrement);
|
|
154
|
-
}
|
|
142
|
+
const handleKeyDown = event => {
|
|
143
|
+
const keyToFnMap = {
|
|
144
|
+
ArrowUp: () => changeValueByStep(StepChangeType.Increment),
|
|
145
|
+
ArrowDown: () => changeValueByStep(StepChangeType.Decrement)
|
|
155
146
|
};
|
|
156
|
-
|
|
147
|
+
const fn = keyToFnMap[event.key];
|
|
157
148
|
|
|
158
149
|
if (fn) {
|
|
159
150
|
event.preventDefault();
|
|
@@ -161,8 +152,8 @@ function InnerNumberEditor(_ref) {
|
|
|
161
152
|
}
|
|
162
153
|
};
|
|
163
154
|
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
const handleInputChange = e => {
|
|
156
|
+
const value = e.target.value;
|
|
166
157
|
|
|
167
158
|
if (!value) {
|
|
168
159
|
setInputValue(value);
|
|
@@ -175,7 +166,7 @@ function InnerNumberEditor(_ref) {
|
|
|
175
166
|
}
|
|
176
167
|
|
|
177
168
|
setInputValue(value);
|
|
178
|
-
|
|
169
|
+
const parsedNumber = parseNumber(value, field.type);
|
|
179
170
|
field.setInvalid(parsedNumber === undefined);
|
|
180
171
|
|
|
181
172
|
if (parsedNumber !== undefined) {
|
|
@@ -208,7 +199,7 @@ function InnerNumberEditor(_ref) {
|
|
|
208
199
|
// The same role that input type="number" has
|
|
209
200
|
// See more details: https://www.digitala11y.com/spinbutton-role/
|
|
210
201
|
role: "spinbutton",
|
|
211
|
-
"aria-valuenow": sdkValue
|
|
202
|
+
"aria-valuenow": sdkValue ?? 0,
|
|
212
203
|
"aria-valuetext": inputValue,
|
|
213
204
|
"aria-valuemin": range.min,
|
|
214
205
|
"aria-valuemax": range.max
|
|
@@ -218,18 +209,14 @@ function InnerNumberEditor(_ref) {
|
|
|
218
209
|
}, React.createElement("button", {
|
|
219
210
|
tabIndex: -1,
|
|
220
211
|
className: styles.control,
|
|
221
|
-
onClick:
|
|
222
|
-
return changeValueByStep(StepChangeType.Increment);
|
|
223
|
-
},
|
|
212
|
+
onClick: () => changeValueByStep(StepChangeType.Increment),
|
|
224
213
|
onPointerDown: handleControlPointerDown
|
|
225
214
|
}, React.createElement(f36Icons.ArrowUpTrimmedIcon, {
|
|
226
215
|
size: "medium"
|
|
227
216
|
})), React.createElement("button", {
|
|
228
217
|
tabIndex: -1,
|
|
229
218
|
className: styles.control,
|
|
230
|
-
onClick:
|
|
231
|
-
return changeValueByStep(StepChangeType.Decrement);
|
|
232
|
-
},
|
|
219
|
+
onClick: () => changeValueByStep(StepChangeType.Decrement),
|
|
233
220
|
onPointerDown: handleControlPointerDown
|
|
234
221
|
}, React.createElement(f36Icons.ArrowDownTrimmedIcon, {
|
|
235
222
|
size: "medium"
|
|
@@ -237,23 +224,24 @@ function InnerNumberEditor(_ref) {
|
|
|
237
224
|
}
|
|
238
225
|
|
|
239
226
|
function NumberEditor(props) {
|
|
240
|
-
|
|
227
|
+
const {
|
|
228
|
+
field
|
|
229
|
+
} = props;
|
|
241
230
|
return React.createElement(fieldEditorShared.FieldConnector, {
|
|
242
231
|
field: field,
|
|
243
232
|
isInitiallyDisabled: props.isInitiallyDisabled
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
});
|
|
233
|
+
}, ({
|
|
234
|
+
value,
|
|
235
|
+
errors,
|
|
236
|
+
disabled,
|
|
237
|
+
setValue
|
|
238
|
+
}) => React.createElement(InnerNumberEditor, {
|
|
239
|
+
disabled: disabled,
|
|
240
|
+
errors: errors,
|
|
241
|
+
field: field,
|
|
242
|
+
setValue: setValue,
|
|
243
|
+
value: value
|
|
244
|
+
}));
|
|
257
245
|
}
|
|
258
246
|
NumberEditor.defaultProps = {
|
|
259
247
|
isInitiallyDisabled: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-editor-number.cjs.development.js","sources":["../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts","../src/NumberEditor.tsx"],"sourcesContent":["import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n","import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","parseNumber","value","type","Number","isNaN","parseInt","parseFloat","FLOAT_REGEX","INT_REGEX","isNumberInputValueValid","regex","test","getRangeFromField","field","validations","result","find","validation","range","valueToString","undefined","String","countDecimals","number","toString","split","length","StepChangeType","NUMBER_STEP","InnerNumberEditor","disabled","errors","setValue","sdkValue","React","inputValue","setInputValue","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","currentValue","nextValue","Increment","toFixed","handleControlPointerDown","event","preventDefault","current","focus","handleKeyDown","keyToFnMap","ArrowUp","ArrowDown","Decrement","fn","key","handleInputChange","e","target","parsedNumber","setInvalid","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","onKeyDown","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"field-editor-number.cjs.development.js","sources":["../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts","../src/NumberEditor.tsx"],"sourcesContent":["import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n","import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","parseNumber","value","type","Number","isNaN","parseInt","parseFloat","FLOAT_REGEX","INT_REGEX","isNumberInputValueValid","regex","test","getRangeFromField","field","validations","result","find","validation","range","valueToString","undefined","String","countDecimals","number","toString","split","length","StepChangeType","NUMBER_STEP","InnerNumberEditor","disabled","errors","setValue","sdkValue","inputValue","setInputValue","React","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","currentValue","nextValue","Increment","toFixed","handleControlPointerDown","event","preventDefault","current","focus","handleKeyDown","keyToFnMap","ArrowUp","ArrowDown","Decrement","fn","key","handleInputChange","e","target","parsedNumber","setInvalid","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","onKeyDown","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("react"),n=require("@contentful/f36-components"),r=require("@contentful/f36-icons"),i=require("@contentful/field-editor-shared"),o=(e=require("@contentful/f36-tokens"))&&"object"==typeof e&&"default"in e?e.default:e,a=require("emotion");const l={container:a.css({position:"relative"}),controlsWrapper:a.css({position:"absolute",top:"1px",right:"1px",width:o.spacingL,height:"calc(100% - 2px)",display:"flex",flexDirection:"column"}),control:a.css({display:"flex",alignItems:"center",justifyContent:"center",minHeight:0,cursor:"pointer",padding:0,margin:0,outline:"none",border:"0 solid "+o.gray300,background:"none",borderLeftWidth:"1px","&:first-of-type":{borderTopRightRadius:o.borderRadiusMedium},"&:last-of-type":{borderTopWidth:"1px",borderBottomRightRadius:o.borderRadiusMedium},svg:{fill:o.gray600},"&:hover":{backgroundColor:o.gray200},"&:active":{backgroundColor:o.gray300}}),input:a.css({paddingRight:o.spacingXl})},s=/^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/,u=/^[+-]?([0-9]*)$/,c=e=>void 0===e?"":String(e);var d;function m({disabled:e,errors:i,field:o,setValue:a,value:m}){const[p,f]=t.useState(c(m)),v=(e=>{const t=(e.validations||[]).find(e=>e.range);return t?t.range:{}})(o),b=t.useRef(null);t.useEffect(()=>{const e=c(m);e!==p&&f(e)},[m]);const g=e=>{m!==e&&a(e)},x=e=>{const t=Number.isNaN(+p)?0:+p;let n=e===d.Increment?t+1:t-1;var r,i;n=+n.toFixed((r=t,(null==(i=r.toString().split(".")[1])?void 0:i.length)??0)),f(c(n)),a(n)},y=e=>{var t;e.preventDefault(),null==(t=b.current)||t.focus()};return t.createElement("div",{"data-test-id":"number-editor",className:l.container},t.createElement(n.TextInput,{type:"text",testId:"number-editor-input",className:l.input,min:v.min,max:v.max,isRequired:o.required,isInvalid:i.length>0,isDisabled:e,value:p,ref:b,onChange:e=>{const t=e.target.value;if(!t)return f(t),void g(void 0);if(!function(e,t){return("Integer"===t?u:s).test(e)}(t,o.type))return;f(t);const n=function(e,t){if(!Number.isNaN(+e))return"Integer"===t?parseInt(e,10):parseFloat(e)}(t,o.type);o.setInvalid(void 0===n),void 0!==n&&g(n)},onKeyDown:e=>{const t={ArrowUp:()=>x(d.Increment),ArrowDown:()=>x(d.Decrement)}[e.key];t&&(e.preventDefault(),t())},role:"spinbutton","aria-valuenow":m??0,"aria-valuetext":p,"aria-valuemin":v.min,"aria-valuemax":v.max}),!e&&t.createElement("div",{className:l.controlsWrapper,"aria-hidden":"true"},t.createElement("button",{tabIndex:-1,className:l.control,onClick:()=>x(d.Increment),onPointerDown:y},t.createElement(r.ArrowUpTrimmedIcon,{size:"medium"})),t.createElement("button",{tabIndex:-1,className:l.control,onClick:()=>x(d.Decrement),onPointerDown:y},t.createElement(r.ArrowDownTrimmedIcon,{size:"medium"}))))}function p(e){const{field:n}=e;return t.createElement(i.FieldConnector,{field:n,isInitiallyDisabled:e.isInitiallyDisabled},({value:e,errors:r,disabled:i,setValue:o})=>t.createElement(m,{disabled:i,errors:r,field:n,setValue:o,value:e}))}!function(e){e.Increment="increment",e.Decrement="decrement"}(d||(d={})),p.defaultProps={isInitiallyDisabled:!0},exports.NumberEditor=p;
|
|
2
2
|
//# sourceMappingURL=field-editor-number.cjs.production.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-editor-number.cjs.production.min.js","sources":["../src/NumberEditor.tsx","../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n","import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n"],"names":["StepChangeType","styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","FLOAT_REGEX","INT_REGEX","valueToString","value","undefined","String","InnerNumberEditor","disabled","errors","field","setValue","sdkValue","React","inputValue","setInputValue","range","result","validations","find","validation","getRangeFromField","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","type","number","currentValue","Number","isNaN","nextValue","Increment","toFixed","toString","split","_number$toString$spli2","length","handleControlPointerDown","event","preventDefault","current","focus","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","e","target","test","isNumberInputValueValid","parsedNumber","parseInt","parseFloat","parseNumber","setInvalid","onKeyDown","fn","ArrowUp","ArrowDown","Decrement","key","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"field-editor-number.cjs.production.min.js","sources":["../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts","../src/NumberEditor.tsx"],"sourcesContent":["import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n","import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","FLOAT_REGEX","INT_REGEX","valueToString","value","undefined","String","StepChangeType","InnerNumberEditor","disabled","errors","field","setValue","sdkValue","inputValue","setInputValue","React","range","result","validations","find","validation","getRangeFromField","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","type","currentValue","Number","isNaN","nextValue","Increment","number","toFixed","toString","split","length","handleControlPointerDown","event","preventDefault","current","focus","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","e","target","test","isNumberInputValueValid","parsedNumber","parseInt","parseFloat","parseNumber","setInvalid","onKeyDown","fn","ArrowUp","ArrowDown","Decrement","key","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { FieldConnector } from '@contentful/field-editor-shared';
|
|
|
5
5
|
import tokens from '@contentful/f36-tokens';
|
|
6
6
|
import { css } from 'emotion';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const styles = {
|
|
9
9
|
container: /*#__PURE__*/css({
|
|
10
10
|
position: 'relative'
|
|
11
11
|
}),
|
|
@@ -27,7 +27,7 @@ var styles = {
|
|
|
27
27
|
padding: 0,
|
|
28
28
|
margin: 0,
|
|
29
29
|
outline: 'none',
|
|
30
|
-
border:
|
|
30
|
+
border: `0 solid ${tokens.gray300}`,
|
|
31
31
|
background: 'none',
|
|
32
32
|
borderLeftWidth: '1px',
|
|
33
33
|
'&:first-of-type': {
|
|
@@ -59,27 +59,25 @@ function parseNumber(value, type) {
|
|
|
59
59
|
|
|
60
60
|
return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;
|
|
63
|
+
const INT_REGEX = /^[+-]?([0-9]*)$/;
|
|
64
64
|
function isNumberInputValueValid(value, type) {
|
|
65
|
-
|
|
65
|
+
const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;
|
|
66
66
|
return regex.test(value);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return validation.range;
|
|
73
|
-
});
|
|
69
|
+
const getRangeFromField = field => {
|
|
70
|
+
const validations = field.validations || [];
|
|
71
|
+
const result = validations.find(validation => validation.range);
|
|
74
72
|
return result ? result.range : {};
|
|
75
73
|
};
|
|
76
|
-
|
|
74
|
+
const valueToString = value => {
|
|
77
75
|
return value === undefined ? '' : String(value);
|
|
78
76
|
};
|
|
79
|
-
|
|
80
|
-
var _number$toString$spli
|
|
77
|
+
const countDecimals = number => {
|
|
78
|
+
var _number$toString$spli;
|
|
81
79
|
|
|
82
|
-
return (_number$toString$spli =
|
|
80
|
+
return ((_number$toString$spli = number.toString().split('.')[1]) == null ? void 0 : _number$toString$spli.length) ?? 0;
|
|
83
81
|
};
|
|
84
82
|
|
|
85
83
|
var StepChangeType;
|
|
@@ -89,23 +87,20 @@ var StepChangeType;
|
|
|
89
87
|
StepChangeType["Decrement"] = "decrement";
|
|
90
88
|
})(StepChangeType || (StepChangeType = {}));
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
function InnerNumberEditor(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
var inputRef = useRef(null);
|
|
107
|
-
useEffect(function () {
|
|
108
|
-
var stringSdkValue = valueToString(sdkValue); // Update the input value if the SDK value (numeric) changes
|
|
90
|
+
const NUMBER_STEP = 1;
|
|
91
|
+
|
|
92
|
+
function InnerNumberEditor({
|
|
93
|
+
disabled,
|
|
94
|
+
errors,
|
|
95
|
+
field,
|
|
96
|
+
setValue,
|
|
97
|
+
value: sdkValue
|
|
98
|
+
}) {
|
|
99
|
+
const [inputValue, setInputValue] = useState(valueToString(sdkValue));
|
|
100
|
+
const range = getRangeFromField(field);
|
|
101
|
+
const inputRef = useRef(null);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const stringSdkValue = valueToString(sdkValue); // Update the input value if the SDK value (numeric) changes
|
|
109
104
|
|
|
110
105
|
if (stringSdkValue !== inputValue) {
|
|
111
106
|
setInputValue(stringSdkValue);
|
|
@@ -113,15 +108,15 @@ function InnerNumberEditor(_ref) {
|
|
|
113
108
|
|
|
114
109
|
}, [sdkValue]);
|
|
115
110
|
|
|
116
|
-
|
|
111
|
+
const updateExternalValue = value => {
|
|
117
112
|
if (sdkValue !== value) {
|
|
118
113
|
setValue(value);
|
|
119
114
|
}
|
|
120
115
|
};
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
const changeValueByStep = type => {
|
|
118
|
+
const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;
|
|
119
|
+
let nextValue = type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP; // Floating point numbers cannot represent all decimals precisely in binary.
|
|
125
120
|
// This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.
|
|
126
121
|
// See more details: https://floating-point-gui.de/
|
|
127
122
|
|
|
@@ -131,23 +126,19 @@ function InnerNumberEditor(_ref) {
|
|
|
131
126
|
}; // Keeps focus on the input
|
|
132
127
|
|
|
133
128
|
|
|
134
|
-
|
|
129
|
+
const handleControlPointerDown = event => {
|
|
135
130
|
var _inputRef$current;
|
|
136
131
|
|
|
137
132
|
event.preventDefault();
|
|
138
133
|
(_inputRef$current = inputRef.current) == null ? void 0 : _inputRef$current.focus();
|
|
139
134
|
};
|
|
140
135
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ArrowUp:
|
|
144
|
-
|
|
145
|
-
},
|
|
146
|
-
ArrowDown: function ArrowDown() {
|
|
147
|
-
return changeValueByStep(StepChangeType.Decrement);
|
|
148
|
-
}
|
|
136
|
+
const handleKeyDown = event => {
|
|
137
|
+
const keyToFnMap = {
|
|
138
|
+
ArrowUp: () => changeValueByStep(StepChangeType.Increment),
|
|
139
|
+
ArrowDown: () => changeValueByStep(StepChangeType.Decrement)
|
|
149
140
|
};
|
|
150
|
-
|
|
141
|
+
const fn = keyToFnMap[event.key];
|
|
151
142
|
|
|
152
143
|
if (fn) {
|
|
153
144
|
event.preventDefault();
|
|
@@ -155,8 +146,8 @@ function InnerNumberEditor(_ref) {
|
|
|
155
146
|
}
|
|
156
147
|
};
|
|
157
148
|
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
const handleInputChange = e => {
|
|
150
|
+
const value = e.target.value;
|
|
160
151
|
|
|
161
152
|
if (!value) {
|
|
162
153
|
setInputValue(value);
|
|
@@ -169,7 +160,7 @@ function InnerNumberEditor(_ref) {
|
|
|
169
160
|
}
|
|
170
161
|
|
|
171
162
|
setInputValue(value);
|
|
172
|
-
|
|
163
|
+
const parsedNumber = parseNumber(value, field.type);
|
|
173
164
|
field.setInvalid(parsedNumber === undefined);
|
|
174
165
|
|
|
175
166
|
if (parsedNumber !== undefined) {
|
|
@@ -202,7 +193,7 @@ function InnerNumberEditor(_ref) {
|
|
|
202
193
|
// The same role that input type="number" has
|
|
203
194
|
// See more details: https://www.digitala11y.com/spinbutton-role/
|
|
204
195
|
role: "spinbutton",
|
|
205
|
-
"aria-valuenow": sdkValue
|
|
196
|
+
"aria-valuenow": sdkValue ?? 0,
|
|
206
197
|
"aria-valuetext": inputValue,
|
|
207
198
|
"aria-valuemin": range.min,
|
|
208
199
|
"aria-valuemax": range.max
|
|
@@ -212,18 +203,14 @@ function InnerNumberEditor(_ref) {
|
|
|
212
203
|
}, createElement("button", {
|
|
213
204
|
tabIndex: -1,
|
|
214
205
|
className: styles.control,
|
|
215
|
-
onClick:
|
|
216
|
-
return changeValueByStep(StepChangeType.Increment);
|
|
217
|
-
},
|
|
206
|
+
onClick: () => changeValueByStep(StepChangeType.Increment),
|
|
218
207
|
onPointerDown: handleControlPointerDown
|
|
219
208
|
}, createElement(ArrowUpTrimmedIcon, {
|
|
220
209
|
size: "medium"
|
|
221
210
|
})), createElement("button", {
|
|
222
211
|
tabIndex: -1,
|
|
223
212
|
className: styles.control,
|
|
224
|
-
onClick:
|
|
225
|
-
return changeValueByStep(StepChangeType.Decrement);
|
|
226
|
-
},
|
|
213
|
+
onClick: () => changeValueByStep(StepChangeType.Decrement),
|
|
227
214
|
onPointerDown: handleControlPointerDown
|
|
228
215
|
}, createElement(ArrowDownTrimmedIcon, {
|
|
229
216
|
size: "medium"
|
|
@@ -231,23 +218,24 @@ function InnerNumberEditor(_ref) {
|
|
|
231
218
|
}
|
|
232
219
|
|
|
233
220
|
function NumberEditor(props) {
|
|
234
|
-
|
|
221
|
+
const {
|
|
222
|
+
field
|
|
223
|
+
} = props;
|
|
235
224
|
return createElement(FieldConnector, {
|
|
236
225
|
field: field,
|
|
237
226
|
isInitiallyDisabled: props.isInitiallyDisabled
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
});
|
|
227
|
+
}, ({
|
|
228
|
+
value,
|
|
229
|
+
errors,
|
|
230
|
+
disabled,
|
|
231
|
+
setValue
|
|
232
|
+
}) => createElement(InnerNumberEditor, {
|
|
233
|
+
disabled: disabled,
|
|
234
|
+
errors: errors,
|
|
235
|
+
field: field,
|
|
236
|
+
setValue: setValue,
|
|
237
|
+
value: value
|
|
238
|
+
}));
|
|
251
239
|
}
|
|
252
240
|
NumberEditor.defaultProps = {
|
|
253
241
|
isInitiallyDisabled: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-editor-number.esm.js","sources":["../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts","../src/NumberEditor.tsx"],"sourcesContent":["import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n","import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","parseNumber","value","type","Number","isNaN","parseInt","parseFloat","FLOAT_REGEX","INT_REGEX","isNumberInputValueValid","regex","test","getRangeFromField","field","validations","result","find","validation","range","valueToString","undefined","String","countDecimals","number","toString","split","length","StepChangeType","NUMBER_STEP","InnerNumberEditor","disabled","errors","setValue","sdkValue","React","inputValue","setInputValue","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","currentValue","nextValue","Increment","toFixed","handleControlPointerDown","event","preventDefault","current","focus","handleKeyDown","keyToFnMap","ArrowUp","ArrowDown","Decrement","fn","key","handleInputChange","e","target","parsedNumber","setInvalid","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","onKeyDown","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"field-editor-number.esm.js","sources":["../src/NumberEditor.styles.ts","../src/parseNumber.ts","../src/utils.ts","../src/NumberEditor.tsx"],"sourcesContent":["import tokens from '@contentful/f36-tokens';\nimport { css } from 'emotion';\n\nexport const styles = {\n container: css({\n position: 'relative',\n }),\n controlsWrapper: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n width: tokens.spacingL,\n height: 'calc(100% - 2px)',\n display: 'flex',\n flexDirection: 'column',\n }),\n control: css({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 0,\n cursor: 'pointer',\n padding: 0,\n margin: 0,\n outline: 'none',\n border: `0 solid ${tokens.gray300}`,\n background: 'none',\n borderLeftWidth: '1px',\n\n '&:first-of-type': {\n borderTopRightRadius: tokens.borderRadiusMedium,\n },\n\n '&:last-of-type': {\n borderTopWidth: '1px',\n borderBottomRightRadius: tokens.borderRadiusMedium,\n },\n\n svg: {\n fill: tokens.gray600,\n },\n\n '&:hover': {\n backgroundColor: tokens.gray200,\n },\n\n '&:active': {\n backgroundColor: tokens.gray300,\n },\n }),\n input: css({\n paddingRight: tokens.spacingXl,\n }),\n};\n","export function parseNumber(value: string, type: string) {\n if (Number.isNaN(+value)) {\n return;\n }\n\n return type === 'Integer' ? parseInt(value, 10) : parseFloat(value);\n}\n\nconst FLOAT_REGEX = /^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]*)?$/;\nconst INT_REGEX = /^[+-]?([0-9]*)$/;\n\nexport function isNumberInputValueValid(value: string, type: string) {\n const regex = type === 'Integer' ? INT_REGEX : FLOAT_REGEX;\n\n return regex.test(value);\n}\n","import { FieldAPI } from '@contentful/field-editor-shared';\n\ntype RangeValidation = { min?: number; max?: number };\n\nexport const getRangeFromField = (field: FieldAPI): RangeValidation => {\n const validations = field.validations || [];\n const result = validations.find((validation) => (validation as any).range) as\n | { range: RangeValidation }\n | undefined;\n return result ? result.range : {};\n};\n\nexport const valueToString = (value: number | null | undefined) => {\n return value === undefined ? '' : String(value);\n};\n\nexport const countDecimals = (number: number) => {\n return number.toString().split('.')[1]?.length ?? 0;\n};\n","import * as React from 'react';\n\nimport { TextInput } from '@contentful/f36-components';\nimport { ArrowUpTrimmedIcon, ArrowDownTrimmedIcon } from '@contentful/f36-icons';\nimport {\n FieldAPI,\n FieldConnector,\n FieldConnectorChildProps,\n} from '@contentful/field-editor-shared';\n\nimport { styles } from './NumberEditor.styles';\nimport { isNumberInputValueValid, parseNumber } from './parseNumber';\nimport { getRangeFromField, valueToString, countDecimals } from './utils';\n\nexport interface NumberEditorProps {\n /**\n * is the field disabled initially\n */\n isInitiallyDisabled: boolean;\n\n /**\n * sdk.field\n */\n field: FieldAPI;\n}\n\ntype InnerNumberEditorProps = Pick<\n FieldConnectorChildProps<number>,\n 'disabled' | 'errors' | 'setValue' | 'value'\n> & {\n field: NumberEditorProps['field'];\n};\n\nenum StepChangeType {\n Increment = 'increment',\n Decrement = 'decrement',\n}\n\nconst NUMBER_STEP = 1;\n\nfunction InnerNumberEditor({\n disabled,\n errors,\n field,\n setValue,\n value: sdkValue,\n}: InnerNumberEditorProps) {\n const [inputValue, setInputValue] = React.useState(valueToString(sdkValue));\n const range = getRangeFromField(field);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n React.useEffect(() => {\n const stringSdkValue = valueToString(sdkValue);\n // Update the input value if the SDK value (numeric) changes\n if (stringSdkValue !== inputValue) {\n setInputValue(stringSdkValue);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- we want to trigger it only when sdkValue has changed\n }, [sdkValue]);\n\n const updateExternalValue = (value: number | undefined) => {\n if (sdkValue !== value) {\n setValue(value);\n }\n };\n\n const changeValueByStep = (type: StepChangeType) => {\n const currentValue = Number.isNaN(+inputValue) ? 0 : +inputValue;\n let nextValue =\n type === StepChangeType.Increment ? currentValue + NUMBER_STEP : currentValue - NUMBER_STEP;\n // Floating point numbers cannot represent all decimals precisely in binary.\n // This can lead to unexpected results, such as 0.1 + 0.2 = 0.30000000000000004.\n // See more details: https://floating-point-gui.de/\n nextValue = +nextValue.toFixed(countDecimals(currentValue));\n\n setInputValue(valueToString(nextValue));\n setValue(nextValue);\n };\n\n // Keeps focus on the input\n const handleControlPointerDown: React.PointerEventHandler<HTMLButtonElement> = (event) => {\n event.preventDefault();\n inputRef.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<any>) => {\n const keyToFnMap: {\n [key: string]: () => void;\n } = {\n ArrowUp: () => changeValueByStep(StepChangeType.Increment),\n ArrowDown: () => changeValueByStep(StepChangeType.Decrement),\n };\n\n const fn = keyToFnMap[event.key];\n if (fn) {\n event.preventDefault();\n fn();\n }\n };\n\n const handleInputChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value;\n if (!value) {\n setInputValue(value);\n updateExternalValue(undefined);\n return;\n }\n\n if (!isNumberInputValueValid(value, field.type)) {\n return;\n }\n\n setInputValue(value);\n\n const parsedNumber = parseNumber(value, field.type);\n field.setInvalid(parsedNumber === undefined);\n if (parsedNumber !== undefined) {\n updateExternalValue(parsedNumber);\n }\n };\n\n return (\n <div data-test-id=\"number-editor\" className={styles.container}>\n <TextInput\n // With type=\"number\" react doesn't call onChange for certain inputs, for example if you type `e`\n // so we use \"text\" instead and fully rely on our own validation.\n // See more details: https://github.com/facebook/react/issues/6556\n type=\"text\"\n testId=\"number-editor-input\"\n className={styles.input}\n min={range.min}\n max={range.max}\n isRequired={field.required}\n isInvalid={errors.length > 0}\n isDisabled={disabled}\n value={inputValue}\n ref={inputRef}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n // The same role that input type=\"number\" has\n // See more details: https://www.digitala11y.com/spinbutton-role/\n role=\"spinbutton\"\n aria-valuenow={sdkValue ?? 0}\n aria-valuetext={inputValue}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n />\n {/**\n * We hide this controls from screen readers and keyboard focus.\n * For those purposes we have a keyboard handler. The same way native input number works.\n */}\n {!disabled && (\n <div className={styles.controlsWrapper} aria-hidden=\"true\">\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Increment)}\n onPointerDown={handleControlPointerDown}>\n <ArrowUpTrimmedIcon size=\"medium\" />\n </button>\n <button\n tabIndex={-1}\n className={styles.control}\n onClick={() => changeValueByStep(StepChangeType.Decrement)}\n onPointerDown={handleControlPointerDown}>\n <ArrowDownTrimmedIcon size=\"medium\" />\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function NumberEditor(props: NumberEditorProps) {\n const { field } = props;\n\n return (\n <FieldConnector<number> field={field} isInitiallyDisabled={props.isInitiallyDisabled}>\n {({\n value,\n errors,\n disabled,\n setValue,\n }: Pick<FieldConnectorChildProps<number>, 'disabled' | 'errors' | 'setValue' | 'value'>) => (\n <InnerNumberEditor\n disabled={disabled}\n errors={errors}\n field={field}\n setValue={setValue}\n value={value}\n />\n )}\n </FieldConnector>\n );\n}\n\nNumberEditor.defaultProps = {\n isInitiallyDisabled: true,\n};\n"],"names":["styles","container","css","position","controlsWrapper","top","right","width","tokens","spacingL","height","display","flexDirection","control","alignItems","justifyContent","minHeight","cursor","padding","margin","outline","border","gray300","background","borderLeftWidth","borderTopRightRadius","borderRadiusMedium","borderTopWidth","borderBottomRightRadius","svg","fill","gray600","backgroundColor","gray200","input","paddingRight","spacingXl","parseNumber","value","type","Number","isNaN","parseInt","parseFloat","FLOAT_REGEX","INT_REGEX","isNumberInputValueValid","regex","test","getRangeFromField","field","validations","result","find","validation","range","valueToString","undefined","String","countDecimals","number","toString","split","length","StepChangeType","NUMBER_STEP","InnerNumberEditor","disabled","errors","setValue","sdkValue","inputValue","setInputValue","React","inputRef","stringSdkValue","updateExternalValue","changeValueByStep","currentValue","nextValue","Increment","toFixed","handleControlPointerDown","event","preventDefault","current","focus","handleKeyDown","keyToFnMap","ArrowUp","ArrowDown","Decrement","fn","key","handleInputChange","e","target","parsedNumber","setInvalid","className","TextInput","testId","min","max","isRequired","required","isInvalid","isDisabled","ref","onChange","onKeyDown","role","tabIndex","onClick","onPointerDown","ArrowUpTrimmedIcon","size","ArrowDownTrimmedIcon","NumberEditor","props","FieldConnector","isInitiallyDisabled","defaultProps"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/field-editor-number",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/field-editor-number.esm.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@contentful/f36-components": "^4.0.27",
|
|
25
25
|
"@contentful/f36-tokens": "^4.0.0",
|
|
26
|
-
"@contentful/field-editor-shared": "^1.
|
|
26
|
+
"@contentful/field-editor-shared": "^1.2.0",
|
|
27
27
|
"emotion": "^10.0.17"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@contentful/field-editor-test-utils": "^1.
|
|
30
|
+
"@contentful/field-editor-test-utils": "^1.3.0",
|
|
31
31
|
"@testing-library/jest-dom": "^5.12.0",
|
|
32
32
|
"@testing-library/react": "^11.2.6",
|
|
33
33
|
"@testing-library/user-event": "^13.1.9"
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": ">=16.8.0"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "de7e74e3485dd69c240cfe9c545e6e50e41fb295"
|
|
39
39
|
}
|