@contentful/field-editor-checkbox 1.2.0 → 1.3.0

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,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "CheckboxEditor", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return CheckboxEditor;
9
+ }
10
+ });
11
+ const _react = _interop_require_wildcard(require("react"));
12
+ const _f36components = require("@contentful/f36-components");
13
+ const _fieldeditorshared = require("@contentful/field-editor-shared");
14
+ const _emotion = require("emotion");
15
+ const _get = _interop_require_default(require("lodash/get"));
16
+ const _nanoid = require("nanoid");
17
+ const _styles = _interop_require_wildcard(require("./styles"));
18
+ function _interop_require_default(obj) {
19
+ return obj && obj.__esModule ? obj : {
20
+ default: obj
21
+ };
22
+ }
23
+ function _getRequireWildcardCache(nodeInterop) {
24
+ if (typeof WeakMap !== "function") return null;
25
+ var cacheBabelInterop = new WeakMap();
26
+ var cacheNodeInterop = new WeakMap();
27
+ return (_getRequireWildcardCache = function(nodeInterop) {
28
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
29
+ })(nodeInterop);
30
+ }
31
+ function _interop_require_wildcard(obj, nodeInterop) {
32
+ if (!nodeInterop && obj && obj.__esModule) {
33
+ return obj;
34
+ }
35
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
36
+ return {
37
+ default: obj
38
+ };
39
+ }
40
+ var cache = _getRequireWildcardCache(nodeInterop);
41
+ if (cache && cache.has(obj)) {
42
+ return cache.get(obj);
43
+ }
44
+ var newObj = {};
45
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
46
+ for(var key in obj){
47
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
48
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
49
+ if (desc && (desc.get || desc.set)) {
50
+ Object.defineProperty(newObj, key, desc);
51
+ } else {
52
+ newObj[key] = obj[key];
53
+ }
54
+ }
55
+ }
56
+ newObj.default = obj;
57
+ if (cache) {
58
+ cache.set(obj, newObj);
59
+ }
60
+ return newObj;
61
+ }
62
+ function isEmptyListValue(value) {
63
+ return value === null || value.length === 0;
64
+ }
65
+ function getOptions(field, id) {
66
+ const validations = (0, _get.default)(field, [
67
+ 'items',
68
+ 'validations'
69
+ ], []);
70
+ const predefinedValues = validations.filter((validation)=>validation.in).map((validation)=>validation.in);
71
+ const firstPredefinedValues = predefinedValues.length > 0 ? predefinedValues[0] : [];
72
+ return firstPredefinedValues.map((value, index)=>({
73
+ id: [
74
+ 'entity',
75
+ field.id,
76
+ field.locale,
77
+ index,
78
+ id
79
+ ].join('.'),
80
+ value,
81
+ label: value
82
+ }));
83
+ }
84
+ const getInvalidValues = (field, values, options)=>{
85
+ const getValueFromOptions = options.map((item)=>item.value);
86
+ const invalidValues = values.filter((value)=>!getValueFromOptions.includes(value)).map((value, index)=>({
87
+ id: [
88
+ 'entity',
89
+ field.id,
90
+ field.locale,
91
+ index,
92
+ 'invalid'
93
+ ].join('.'),
94
+ label: value,
95
+ invalid: true,
96
+ value
97
+ }));
98
+ return invalidValues;
99
+ };
100
+ function CheckboxEditor(props) {
101
+ const [id] = (0, _react.useState)(()=>(0, _nanoid.nanoid)(6));
102
+ const { field , locales } = props;
103
+ const options = getOptions(field, id);
104
+ const misconfigured = options.length === 0;
105
+ if (misconfigured) {
106
+ return _react.createElement(_fieldeditorshared.PredefinedValuesError, null);
107
+ }
108
+ const direction = locales.direction[field.locale] || 'ltr';
109
+ return _react.createElement(_fieldeditorshared.FieldConnector, {
110
+ throttle: 0,
111
+ isEmptyValue: isEmptyListValue,
112
+ field: field,
113
+ isInitiallyDisabled: props.isInitiallyDisabled
114
+ }, ({ disabled , value , setValue })=>{
115
+ const values = value || [];
116
+ const addValue = (value)=>{
117
+ const newValues = [
118
+ ...values.filter((item)=>item !== value),
119
+ value
120
+ ];
121
+ setValue(newValues);
122
+ };
123
+ const removeValue = (value)=>{
124
+ const newValues = values.filter((item)=>item !== value);
125
+ setValue(newValues);
126
+ };
127
+ const invalidValues = getInvalidValues(field, values, options);
128
+ const mergedOptions = [
129
+ ...options,
130
+ ...invalidValues
131
+ ];
132
+ return _react.createElement(_f36components.Form, {
133
+ testId: "checkbox-editor",
134
+ className: (0, _emotion.cx)(_styles.form, direction === 'rtl' ? _styles.rightToLeft : '')
135
+ }, mergedOptions.map((item)=>_react.createElement(_f36components.Box, {
136
+ key: item.id,
137
+ marginBottom: "spacingS"
138
+ }, _react.createElement(_f36components.Checkbox, {
139
+ key: item.id,
140
+ id: item.id,
141
+ isChecked: values.includes(item.value),
142
+ isDisabled: disabled,
143
+ value: item.value,
144
+ name: `${field.id}.${field.locale}`,
145
+ onChange: (e)=>{
146
+ if (e.target.checked) {
147
+ addValue(item.value);
148
+ } else {
149
+ removeValue(item.value);
150
+ }
151
+ }
152
+ }, item.label), item.invalid && _react.createElement(_react.Fragment, null, _react.createElement("span", {
153
+ "data-test-id": "invalid-text",
154
+ className: _styles.invalidText
155
+ }, "(invalid)"), _react.createElement(_f36components.TextLink, {
156
+ as: "button",
157
+ className: _styles.removeBtn,
158
+ onClick: ()=>removeValue(item.value)
159
+ }, "Remove")))));
160
+ });
161
+ }
162
+ CheckboxEditor.defaultProps = {
163
+ isInitiallyDisabled: true
164
+ };
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ const _react = _interop_require_wildcard(require("react"));
6
+ const _fieldeditortestutils = require("@contentful/field-editor-test-utils");
7
+ require("@testing-library/jest-dom/extend-expect");
8
+ const _react1 = require("@testing-library/react");
9
+ const _CheckboxEditor = require("./CheckboxEditor");
10
+ function _getRequireWildcardCache(nodeInterop) {
11
+ if (typeof WeakMap !== "function") return null;
12
+ var cacheBabelInterop = new WeakMap();
13
+ var cacheNodeInterop = new WeakMap();
14
+ return (_getRequireWildcardCache = function(nodeInterop) {
15
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
16
+ })(nodeInterop);
17
+ }
18
+ function _interop_require_wildcard(obj, nodeInterop) {
19
+ if (!nodeInterop && obj && obj.__esModule) {
20
+ return obj;
21
+ }
22
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
23
+ return {
24
+ default: obj
25
+ };
26
+ }
27
+ var cache = _getRequireWildcardCache(nodeInterop);
28
+ if (cache && cache.has(obj)) {
29
+ return cache.get(obj);
30
+ }
31
+ var newObj = {};
32
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
33
+ for(var key in obj){
34
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
35
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
36
+ if (desc && (desc.get || desc.set)) {
37
+ Object.defineProperty(newObj, key, desc);
38
+ } else {
39
+ newObj[key] = obj[key];
40
+ }
41
+ }
42
+ }
43
+ newObj.default = obj;
44
+ if (cache) {
45
+ cache.set(obj, newObj);
46
+ }
47
+ return newObj;
48
+ }
49
+ (0, _react1.configure)({
50
+ testIdAttribute: 'data-test-id'
51
+ });
52
+ describe('CheckboxEditor', ()=>{
53
+ afterEach(_react1.cleanup);
54
+ it('renders a warning if no options are present', ()=>{
55
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((mock)=>{
56
+ return {
57
+ ...mock,
58
+ items: {
59
+ type: '',
60
+ validations: []
61
+ }
62
+ };
63
+ });
64
+ const { getByTestId , queryByTestId } = (0, _react1.render)(_react.createElement(_CheckboxEditor.CheckboxEditor, {
65
+ field: field,
66
+ locales: (0, _fieldeditortestutils.createFakeLocalesAPI)(),
67
+ isInitiallyDisabled: false
68
+ }));
69
+ expect(getByTestId('predefined-values-warning')).toBeInTheDocument();
70
+ expect(queryByTestId('dropdown-editor')).not.toBeInTheDocument();
71
+ });
72
+ it('renders checkboxes for predefined values', ()=>{
73
+ const predefined = [
74
+ 'banana',
75
+ 'orange',
76
+ 'strawberry'
77
+ ];
78
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((mock)=>{
79
+ return {
80
+ ...mock,
81
+ items: {
82
+ type: '',
83
+ validations: [
84
+ {
85
+ in: predefined
86
+ }
87
+ ]
88
+ }
89
+ };
90
+ });
91
+ const { container } = (0, _react1.render)(_react.createElement(_CheckboxEditor.CheckboxEditor, {
92
+ field: field,
93
+ locales: (0, _fieldeditortestutils.createFakeLocalesAPI)(),
94
+ isInitiallyDisabled: false
95
+ }));
96
+ const $inputs = container.querySelectorAll('input[type="checkbox"]');
97
+ expect($inputs).toHaveLength(3);
98
+ predefined.forEach((item, index)=>{
99
+ expect($inputs[index].value).toEqual(item);
100
+ });
101
+ });
102
+ it('calls setValue for every check event and removeValue if all items are unclicked', ()=>{
103
+ const predefined = [
104
+ 'banana',
105
+ 'orange',
106
+ 'strawberry'
107
+ ];
108
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((mock)=>{
109
+ jest.spyOn(mock, 'setValue');
110
+ jest.spyOn(mock, 'removeValue');
111
+ return {
112
+ ...mock,
113
+ items: {
114
+ type: '',
115
+ validations: [
116
+ {
117
+ in: predefined
118
+ }
119
+ ]
120
+ }
121
+ };
122
+ });
123
+ const { container } = (0, _react1.render)(_react.createElement(_CheckboxEditor.CheckboxEditor, {
124
+ field: field,
125
+ locales: (0, _fieldeditortestutils.createFakeLocalesAPI)(),
126
+ isInitiallyDisabled: false
127
+ }));
128
+ const $inputs = container.querySelectorAll('input[type="checkbox"]');
129
+ _react1.fireEvent.click($inputs[0]);
130
+ expect(field.setValue).toHaveBeenCalledWith([
131
+ predefined[0]
132
+ ]);
133
+ expect(field.setValue).toHaveBeenCalledTimes(1);
134
+ _react1.fireEvent.click($inputs[2]);
135
+ expect(field.setValue).toHaveBeenCalledWith([
136
+ predefined[0],
137
+ predefined[2]
138
+ ]);
139
+ expect(field.setValue).toHaveBeenCalledTimes(2);
140
+ _react1.fireEvent.click($inputs[1]);
141
+ expect(field.setValue).toHaveBeenCalledWith([
142
+ predefined[0],
143
+ predefined[2],
144
+ predefined[1]
145
+ ]);
146
+ expect(field.setValue).toHaveBeenCalledTimes(3);
147
+ $inputs.forEach(($input)=>{
148
+ _react1.fireEvent.click($input);
149
+ });
150
+ expect(field.removeValue).toHaveBeenCalledTimes(1);
151
+ });
152
+ it('renders invalid text and remove link when value set is not in predefined values', ()=>{
153
+ const predefined = [
154
+ 'banana',
155
+ 'orange',
156
+ 'strawberry'
157
+ ];
158
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((mock)=>{
159
+ jest.spyOn(mock, 'setValue');
160
+ jest.spyOn(mock, 'removeValue');
161
+ return {
162
+ ...mock,
163
+ items: {
164
+ type: '',
165
+ validations: [
166
+ {
167
+ in: predefined
168
+ }
169
+ ]
170
+ }
171
+ };
172
+ });
173
+ field.setValue([
174
+ 'mango'
175
+ ]);
176
+ const { getByTestId } = (0, _react1.render)(_react.createElement(_CheckboxEditor.CheckboxEditor, {
177
+ field: field,
178
+ locales: (0, _fieldeditortestutils.createFakeLocalesAPI)(),
179
+ isInitiallyDisabled: false
180
+ }));
181
+ expect(getByTestId('invalid-text')).toBeInTheDocument();
182
+ expect(getByTestId('cf-ui-text-link')).toBeInTheDocument();
183
+ _react1.fireEvent.click(getByTestId('cf-ui-text-link'));
184
+ expect(field.removeValue).toHaveBeenCalledTimes(1);
185
+ });
186
+ it('renders checkboxes with unique ids', async ()=>{
187
+ const predefined = [
188
+ 'banana',
189
+ 'orange',
190
+ 'strawberry'
191
+ ];
192
+ const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((mock)=>{
193
+ return {
194
+ ...mock,
195
+ items: {
196
+ type: '',
197
+ validations: [
198
+ {
199
+ in: predefined
200
+ }
201
+ ]
202
+ }
203
+ };
204
+ });
205
+ const locales = (0, _fieldeditortestutils.createFakeLocalesAPI)();
206
+ const { findAllByTestId } = (0, _react1.render)(_react.createElement("div", null, _react.createElement(_CheckboxEditor.CheckboxEditor, {
207
+ field: field,
208
+ locales: locales,
209
+ isInitiallyDisabled: false
210
+ }), _react.createElement(_CheckboxEditor.CheckboxEditor, {
211
+ field: field,
212
+ locales: locales,
213
+ isInitiallyDisabled: false
214
+ })));
215
+ const $labels = await findAllByTestId('cf-ui-checkbox');
216
+ const uniqueIds = Array.from(new Set($labels.map((label)=>label.getAttribute('for'))));
217
+ expect(uniqueIds).toHaveLength(6);
218
+ });
219
+ });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "CheckboxEditor", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _CheckboxEditor.CheckboxEditor;
9
+ }
10
+ });
11
+ const _CheckboxEditor = require("./CheckboxEditor");
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ form: function() {
13
+ return form;
14
+ },
15
+ rightToLeft: function() {
16
+ return rightToLeft;
17
+ },
18
+ invalidText: function() {
19
+ return invalidText;
20
+ },
21
+ removeBtn: function() {
22
+ return removeBtn;
23
+ }
24
+ });
25
+ const _f36tokens = _interop_require_default(require("@contentful/f36-tokens"));
26
+ const _emotion = require("emotion");
27
+ function _interop_require_default(obj) {
28
+ return obj && obj.__esModule ? obj : {
29
+ default: obj
30
+ };
31
+ }
32
+ const form = (0, _emotion.css)({
33
+ marginTop: _f36tokens.default.spacingS
34
+ });
35
+ const rightToLeft = (0, _emotion.css)({
36
+ direction: 'rtl'
37
+ });
38
+ const invalidText = (0, _emotion.css)({
39
+ color: _f36tokens.default.red500,
40
+ marginLeft: _f36tokens.default.spacing2Xs
41
+ });
42
+ const removeBtn = (0, _emotion.css)({
43
+ marginLeft: _f36tokens.default.spacingL
44
+ });
@@ -0,0 +1,112 @@
1
+ import * as React from 'react';
2
+ import { useState } from 'react';
3
+ import { Checkbox, Box } from '@contentful/f36-components';
4
+ import { TextLink, Form } from '@contentful/f36-components';
5
+ import { FieldConnector, PredefinedValuesError } from '@contentful/field-editor-shared';
6
+ import { cx } from 'emotion';
7
+ import get from 'lodash/get';
8
+ import { nanoid } from 'nanoid';
9
+ import * as styles from './styles';
10
+ function isEmptyListValue(value) {
11
+ return value === null || value.length === 0;
12
+ }
13
+ function getOptions(field, id) {
14
+ const validations = get(field, [
15
+ 'items',
16
+ 'validations'
17
+ ], []);
18
+ const predefinedValues = validations.filter((validation)=>validation.in).map((validation)=>validation.in);
19
+ const firstPredefinedValues = predefinedValues.length > 0 ? predefinedValues[0] : [];
20
+ return firstPredefinedValues.map((value, index)=>({
21
+ id: [
22
+ 'entity',
23
+ field.id,
24
+ field.locale,
25
+ index,
26
+ id
27
+ ].join('.'),
28
+ value,
29
+ label: value
30
+ }));
31
+ }
32
+ const getInvalidValues = (field, values, options)=>{
33
+ const getValueFromOptions = options.map((item)=>item.value);
34
+ const invalidValues = values.filter((value)=>!getValueFromOptions.includes(value)).map((value, index)=>({
35
+ id: [
36
+ 'entity',
37
+ field.id,
38
+ field.locale,
39
+ index,
40
+ 'invalid'
41
+ ].join('.'),
42
+ label: value,
43
+ invalid: true,
44
+ value
45
+ }));
46
+ return invalidValues;
47
+ };
48
+ export function CheckboxEditor(props) {
49
+ const [id] = useState(()=>nanoid(6));
50
+ const { field , locales } = props;
51
+ const options = getOptions(field, id);
52
+ const misconfigured = options.length === 0;
53
+ if (misconfigured) {
54
+ return React.createElement(PredefinedValuesError, null);
55
+ }
56
+ const direction = locales.direction[field.locale] || 'ltr';
57
+ return React.createElement(FieldConnector, {
58
+ throttle: 0,
59
+ isEmptyValue: isEmptyListValue,
60
+ field: field,
61
+ isInitiallyDisabled: props.isInitiallyDisabled
62
+ }, ({ disabled , value , setValue })=>{
63
+ const values = value || [];
64
+ const addValue = (value)=>{
65
+ const newValues = [
66
+ ...values.filter((item)=>item !== value),
67
+ value
68
+ ];
69
+ setValue(newValues);
70
+ };
71
+ const removeValue = (value)=>{
72
+ const newValues = values.filter((item)=>item !== value);
73
+ setValue(newValues);
74
+ };
75
+ const invalidValues = getInvalidValues(field, values, options);
76
+ const mergedOptions = [
77
+ ...options,
78
+ ...invalidValues
79
+ ];
80
+ return React.createElement(Form, {
81
+ testId: "checkbox-editor",
82
+ className: cx(styles.form, direction === 'rtl' ? styles.rightToLeft : '')
83
+ }, mergedOptions.map((item)=>React.createElement(Box, {
84
+ key: item.id,
85
+ marginBottom: "spacingS"
86
+ }, React.createElement(Checkbox, {
87
+ key: item.id,
88
+ id: item.id,
89
+ isChecked: values.includes(item.value),
90
+ isDisabled: disabled,
91
+ value: item.value,
92
+ name: `${field.id}.${field.locale}`,
93
+ onChange: (e)=>{
94
+ if (e.target.checked) {
95
+ addValue(item.value);
96
+ } else {
97
+ removeValue(item.value);
98
+ }
99
+ }
100
+ }, item.label), item.invalid && React.createElement(React.Fragment, null, React.createElement("span", {
101
+ "data-test-id": "invalid-text",
102
+ className: styles.invalidText
103
+ }, "(invalid)"), React.createElement(TextLink, {
104
+ as: "button",
105
+ className: styles.removeBtn,
106
+ onClick: ()=>removeValue(item.value)
107
+ }, "Remove")))));
108
+ });
109
+ }
110
+ CheckboxEditor.defaultProps = {
111
+ isInitiallyDisabled: true
112
+ };