@contentful/field-editor-rating 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/RatingEditor.js +110 -0
- package/dist/cjs/RatingEditor.spec.js +136 -0
- package/dist/cjs/RatingRibbon.js +133 -0
- package/dist/cjs/index.js +11 -0
- package/dist/esm/RatingEditor.js +56 -0
- package/dist/esm/RatingEditor.spec.js +93 -0
- package/dist/esm/RatingRibbon.js +84 -0
- package/dist/esm/index.js +1 -0
- package/dist/{RatingEditor.d.ts → types/RatingEditor.d.ts} +26 -26
- package/dist/types/RatingEditor.spec.d.ts +1 -0
- package/dist/{RatingRibbon.d.ts → types/RatingRibbon.d.ts} +20 -20
- package/dist/{index.d.ts → types/index.d.ts} +1 -1
- package/package.json +26 -13
- package/CHANGELOG.md +0 -198
- package/dist/field-editor-rating.cjs.development.js +0 -152
- package/dist/field-editor-rating.cjs.development.js.map +0 -1
- package/dist/field-editor-rating.cjs.production.min.js +0 -2
- package/dist/field-editor-rating.cjs.production.min.js.map +0 -1
- package/dist/field-editor-rating.esm.js +0 -146
- package/dist/field-editor-rating.esm.js.map +0 -1
- package/dist/index.js +0 -8
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "RatingEditor", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return RatingEditor;
|
|
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 _get = _interop_require_default(require("lodash/get"));
|
|
15
|
+
const _RatingRibbon = require("./RatingRibbon");
|
|
16
|
+
function _interop_require_default(obj) {
|
|
17
|
+
return obj && obj.__esModule ? obj : {
|
|
18
|
+
default: obj
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
22
|
+
if (typeof WeakMap !== "function") return null;
|
|
23
|
+
var cacheBabelInterop = new WeakMap();
|
|
24
|
+
var cacheNodeInterop = new WeakMap();
|
|
25
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
26
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
27
|
+
})(nodeInterop);
|
|
28
|
+
}
|
|
29
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
30
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
33
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
34
|
+
return {
|
|
35
|
+
default: obj
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
39
|
+
if (cache && cache.has(obj)) {
|
|
40
|
+
return cache.get(obj);
|
|
41
|
+
}
|
|
42
|
+
var newObj = {};
|
|
43
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
44
|
+
for(var key in obj){
|
|
45
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
46
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
47
|
+
if (desc && (desc.get || desc.set)) {
|
|
48
|
+
Object.defineProperty(newObj, key, desc);
|
|
49
|
+
} else {
|
|
50
|
+
newObj[key] = obj[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
newObj.default = obj;
|
|
55
|
+
if (cache) {
|
|
56
|
+
cache.set(obj, newObj);
|
|
57
|
+
}
|
|
58
|
+
return newObj;
|
|
59
|
+
}
|
|
60
|
+
function isValidCount(count) {
|
|
61
|
+
return typeof count === 'number' && !isNaN(count) && count > 0;
|
|
62
|
+
}
|
|
63
|
+
function getStarCount(count) {
|
|
64
|
+
const defaultValue = 5;
|
|
65
|
+
if (isValidCount(count)) {
|
|
66
|
+
return Math.round(count);
|
|
67
|
+
} else if (typeof count === 'string') {
|
|
68
|
+
const parsed = parseInt(count, 10);
|
|
69
|
+
return isValidCount(parsed) ? Math.round(parsed) : defaultValue;
|
|
70
|
+
} else {
|
|
71
|
+
return defaultValue;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function RatingEditor(props) {
|
|
75
|
+
const { field } = props;
|
|
76
|
+
const starsCount = getStarCount((0, _get.default)(props.parameters, [
|
|
77
|
+
'instance',
|
|
78
|
+
'stars'
|
|
79
|
+
]));
|
|
80
|
+
return _react.createElement(_fieldeditorshared.FieldConnector, {
|
|
81
|
+
throttle: 0,
|
|
82
|
+
field: field,
|
|
83
|
+
isInitiallyDisabled: props.isInitiallyDisabled
|
|
84
|
+
}, ({ disabled , value , setValue })=>{
|
|
85
|
+
const clearOption = ()=>{
|
|
86
|
+
setValue(null);
|
|
87
|
+
};
|
|
88
|
+
return _react.createElement(_f36components.Flex, {
|
|
89
|
+
testId: "rating-editor",
|
|
90
|
+
flexDirection: "row",
|
|
91
|
+
marginTop: "spacingS"
|
|
92
|
+
}, _react.createElement(_RatingRibbon.RatingRibbon, {
|
|
93
|
+
disabled: disabled,
|
|
94
|
+
value: value,
|
|
95
|
+
stars: starsCount,
|
|
96
|
+
onSelect: (num)=>{
|
|
97
|
+
setValue(num);
|
|
98
|
+
}
|
|
99
|
+
}), value !== undefined && !disabled && _react.createElement(_f36components.Flex, {
|
|
100
|
+
marginLeft: "spacingM"
|
|
101
|
+
}, _react.createElement(_f36components.TextLink, {
|
|
102
|
+
as: "button",
|
|
103
|
+
testId: "rating-editor-clear",
|
|
104
|
+
onClick: clearOption
|
|
105
|
+
}, "Clear")));
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
RatingEditor.defaultProps = {
|
|
109
|
+
isInitiallyDisabled: true
|
|
110
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
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 _RatingEditor = require("./RatingEditor");
|
|
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('RatingEditor', ()=>{
|
|
53
|
+
afterEach(_react1.cleanup);
|
|
54
|
+
it('renders 5 stars by default', ()=>{
|
|
55
|
+
const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)();
|
|
56
|
+
const { getAllByTestId } = (0, _react1.render)(_react.createElement(_RatingEditor.RatingEditor, {
|
|
57
|
+
field: field,
|
|
58
|
+
isInitiallyDisabled: false
|
|
59
|
+
}));
|
|
60
|
+
expect(getAllByTestId('rating-editor-star')).toHaveLength(5);
|
|
61
|
+
});
|
|
62
|
+
it('renders custom number of stars', ()=>{
|
|
63
|
+
const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)();
|
|
64
|
+
const { getAllByTestId } = (0, _react1.render)(_react.createElement(_RatingEditor.RatingEditor, {
|
|
65
|
+
field: field,
|
|
66
|
+
isInitiallyDisabled: false,
|
|
67
|
+
parameters: {
|
|
68
|
+
installation: {},
|
|
69
|
+
instance: {
|
|
70
|
+
stars: 20
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
expect(getAllByTestId('rating-editor-star')).toHaveLength(20);
|
|
75
|
+
});
|
|
76
|
+
it('should should setValue by clicking on a item and removeValue by clicking on clear', ()=>{
|
|
77
|
+
const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>{
|
|
78
|
+
jest.spyOn(field, 'setValue');
|
|
79
|
+
jest.spyOn(field, 'removeValue');
|
|
80
|
+
return {
|
|
81
|
+
...field
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
const { container , getAllByTestId , getByTestId , queryByTestId } = (0, _react1.render)(_react.createElement(_RatingEditor.RatingEditor, {
|
|
85
|
+
field: field,
|
|
86
|
+
isInitiallyDisabled: false
|
|
87
|
+
}));
|
|
88
|
+
const $stars = getAllByTestId('rating-editor-star');
|
|
89
|
+
expect(queryByTestId('rating-editor-clean')).not.toBeInTheDocument();
|
|
90
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(0);
|
|
91
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(5);
|
|
92
|
+
_react1.fireEvent.click($stars[4]);
|
|
93
|
+
expect(field.setValue).toHaveBeenCalledWith(5);
|
|
94
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(5);
|
|
95
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(0);
|
|
96
|
+
_react1.fireEvent.click($stars[0]);
|
|
97
|
+
expect(field.setValue).toHaveBeenCalledWith(1);
|
|
98
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(1);
|
|
99
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(4);
|
|
100
|
+
_react1.fireEvent.click(getByTestId('rating-editor-clear'));
|
|
101
|
+
expect(field.removeValue).toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
it('should should setValue by focusing and using Enter', ()=>{
|
|
104
|
+
const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>{
|
|
105
|
+
jest.spyOn(field, 'setValue');
|
|
106
|
+
jest.spyOn(field, 'removeValue');
|
|
107
|
+
return {
|
|
108
|
+
...field
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
const { container , getAllByTestId , queryByTestId } = (0, _react1.render)(_react.createElement(_RatingEditor.RatingEditor, {
|
|
112
|
+
field: field,
|
|
113
|
+
isInitiallyDisabled: false
|
|
114
|
+
}));
|
|
115
|
+
const $stars = getAllByTestId('rating-editor-star');
|
|
116
|
+
expect(queryByTestId('rating-editor-clean')).not.toBeInTheDocument();
|
|
117
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(0);
|
|
118
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(5);
|
|
119
|
+
_react1.fireEvent.focus($stars[2]);
|
|
120
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(3);
|
|
121
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(2);
|
|
122
|
+
_react1.fireEvent.keyDown($stars[2], {
|
|
123
|
+
keyCode: 13
|
|
124
|
+
});
|
|
125
|
+
expect(field.setValue).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(field.setValue).toHaveBeenCalledWith(3);
|
|
127
|
+
_react1.fireEvent.focus($stars[4]);
|
|
128
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(5);
|
|
129
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(0);
|
|
130
|
+
_react1.fireEvent.keyDown($stars[4], {
|
|
131
|
+
keyCode: 13
|
|
132
|
+
});
|
|
133
|
+
expect(field.setValue).toHaveBeenCalledTimes(2);
|
|
134
|
+
expect(field.setValue).toHaveBeenCalledWith(5);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "RatingRibbon", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return RatingRibbon;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _react = _interop_require_wildcard(require("react"));
|
|
12
|
+
const _f36components = require("@contentful/f36-components");
|
|
13
|
+
const _f36icons = require("@contentful/f36-icons");
|
|
14
|
+
const _emotion = require("emotion");
|
|
15
|
+
function _define_property(obj, key, value) {
|
|
16
|
+
if (key in obj) {
|
|
17
|
+
Object.defineProperty(obj, key, {
|
|
18
|
+
value: value,
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true
|
|
22
|
+
});
|
|
23
|
+
} else {
|
|
24
|
+
obj[key] = value;
|
|
25
|
+
}
|
|
26
|
+
return obj;
|
|
27
|
+
}
|
|
28
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
29
|
+
if (typeof WeakMap !== "function") return null;
|
|
30
|
+
var cacheBabelInterop = new WeakMap();
|
|
31
|
+
var cacheNodeInterop = new WeakMap();
|
|
32
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
33
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
34
|
+
})(nodeInterop);
|
|
35
|
+
}
|
|
36
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
37
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
41
|
+
return {
|
|
42
|
+
default: obj
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
46
|
+
if (cache && cache.has(obj)) {
|
|
47
|
+
return cache.get(obj);
|
|
48
|
+
}
|
|
49
|
+
var newObj = {};
|
|
50
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
51
|
+
for(var key in obj){
|
|
52
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
53
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
54
|
+
if (desc && (desc.get || desc.set)) {
|
|
55
|
+
Object.defineProperty(newObj, key, desc);
|
|
56
|
+
} else {
|
|
57
|
+
newObj[key] = obj[key];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
newObj.default = obj;
|
|
62
|
+
if (cache) {
|
|
63
|
+
cache.set(obj, newObj);
|
|
64
|
+
}
|
|
65
|
+
return newObj;
|
|
66
|
+
}
|
|
67
|
+
class RatingRibbon extends _react.Component {
|
|
68
|
+
render() {
|
|
69
|
+
const items = [];
|
|
70
|
+
for(let i = 1; i <= this.props.stars; i++){
|
|
71
|
+
items.push(i);
|
|
72
|
+
}
|
|
73
|
+
return _react.createElement(_react.Fragment, null, items.map((num)=>_react.createElement(_f36components.IconButton, {
|
|
74
|
+
variant: "transparent",
|
|
75
|
+
size: "small",
|
|
76
|
+
icon: _react.createElement(_f36icons.StarIcon, {
|
|
77
|
+
variant: this.isSelected(num) ? 'primary' : 'muted',
|
|
78
|
+
className: (0, _emotion.css)({
|
|
79
|
+
width: '22px',
|
|
80
|
+
height: '22px'
|
|
81
|
+
})
|
|
82
|
+
}),
|
|
83
|
+
"data-selected": this.isSelected(num) ? 'true' : 'false',
|
|
84
|
+
testId: "rating-editor-star",
|
|
85
|
+
isDisabled: this.props.disabled,
|
|
86
|
+
key: num,
|
|
87
|
+
onClick: ()=>{
|
|
88
|
+
this.props.onSelect(num);
|
|
89
|
+
},
|
|
90
|
+
onKeyDown: (e)=>{
|
|
91
|
+
if (e.keyCode === 13) {
|
|
92
|
+
this.props.onSelect(num);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
onMouseOver: this.onFocus(num),
|
|
96
|
+
onMouseLeave: this.onBlur,
|
|
97
|
+
onFocus: this.onFocus(num),
|
|
98
|
+
onBlur: this.onBlur,
|
|
99
|
+
"aria-label": num.toString()
|
|
100
|
+
})));
|
|
101
|
+
}
|
|
102
|
+
constructor(...args){
|
|
103
|
+
super(...args);
|
|
104
|
+
_define_property(this, "state", {
|
|
105
|
+
hovered: null
|
|
106
|
+
});
|
|
107
|
+
_define_property(this, "isSelected", (num)=>{
|
|
108
|
+
const hovered = this.state.hovered;
|
|
109
|
+
const value = this.props.value;
|
|
110
|
+
if (hovered !== null) {
|
|
111
|
+
return num <= hovered;
|
|
112
|
+
}
|
|
113
|
+
if (value) {
|
|
114
|
+
return num <= value;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
});
|
|
118
|
+
_define_property(this, "onBlur", ()=>{
|
|
119
|
+
if (!this.props.disabled) {
|
|
120
|
+
this.setState({
|
|
121
|
+
hovered: null
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
_define_property(this, "onFocus", (num)=>()=>{
|
|
126
|
+
if (!this.props.disabled) {
|
|
127
|
+
this.setState({
|
|
128
|
+
hovered: num
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "RatingEditor", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _RatingEditor.RatingEditor;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _RatingEditor = require("./RatingEditor");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { TextLink, Flex } from '@contentful/f36-components';
|
|
3
|
+
import { FieldConnector } from '@contentful/field-editor-shared';
|
|
4
|
+
import get from 'lodash/get';
|
|
5
|
+
import { RatingRibbon } from './RatingRibbon';
|
|
6
|
+
function isValidCount(count) {
|
|
7
|
+
return typeof count === 'number' && !isNaN(count) && count > 0;
|
|
8
|
+
}
|
|
9
|
+
function getStarCount(count) {
|
|
10
|
+
const defaultValue = 5;
|
|
11
|
+
if (isValidCount(count)) {
|
|
12
|
+
return Math.round(count);
|
|
13
|
+
} else if (typeof count === 'string') {
|
|
14
|
+
const parsed = parseInt(count, 10);
|
|
15
|
+
return isValidCount(parsed) ? Math.round(parsed) : defaultValue;
|
|
16
|
+
} else {
|
|
17
|
+
return defaultValue;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function RatingEditor(props) {
|
|
21
|
+
const { field } = props;
|
|
22
|
+
const starsCount = getStarCount(get(props.parameters, [
|
|
23
|
+
'instance',
|
|
24
|
+
'stars'
|
|
25
|
+
]));
|
|
26
|
+
return React.createElement(FieldConnector, {
|
|
27
|
+
throttle: 0,
|
|
28
|
+
field: field,
|
|
29
|
+
isInitiallyDisabled: props.isInitiallyDisabled
|
|
30
|
+
}, ({ disabled , value , setValue })=>{
|
|
31
|
+
const clearOption = ()=>{
|
|
32
|
+
setValue(null);
|
|
33
|
+
};
|
|
34
|
+
return React.createElement(Flex, {
|
|
35
|
+
testId: "rating-editor",
|
|
36
|
+
flexDirection: "row",
|
|
37
|
+
marginTop: "spacingS"
|
|
38
|
+
}, React.createElement(RatingRibbon, {
|
|
39
|
+
disabled: disabled,
|
|
40
|
+
value: value,
|
|
41
|
+
stars: starsCount,
|
|
42
|
+
onSelect: (num)=>{
|
|
43
|
+
setValue(num);
|
|
44
|
+
}
|
|
45
|
+
}), value !== undefined && !disabled && React.createElement(Flex, {
|
|
46
|
+
marginLeft: "spacingM"
|
|
47
|
+
}, React.createElement(TextLink, {
|
|
48
|
+
as: "button",
|
|
49
|
+
testId: "rating-editor-clear",
|
|
50
|
+
onClick: clearOption
|
|
51
|
+
}, "Clear")));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
RatingEditor.defaultProps = {
|
|
55
|
+
isInitiallyDisabled: true
|
|
56
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createFakeFieldAPI } from '@contentful/field-editor-test-utils';
|
|
3
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
4
|
+
import { cleanup, configure, fireEvent, render } from '@testing-library/react';
|
|
5
|
+
import { RatingEditor } from './RatingEditor';
|
|
6
|
+
configure({
|
|
7
|
+
testIdAttribute: 'data-test-id'
|
|
8
|
+
});
|
|
9
|
+
describe('RatingEditor', ()=>{
|
|
10
|
+
afterEach(cleanup);
|
|
11
|
+
it('renders 5 stars by default', ()=>{
|
|
12
|
+
const [field] = createFakeFieldAPI();
|
|
13
|
+
const { getAllByTestId } = render(React.createElement(RatingEditor, {
|
|
14
|
+
field: field,
|
|
15
|
+
isInitiallyDisabled: false
|
|
16
|
+
}));
|
|
17
|
+
expect(getAllByTestId('rating-editor-star')).toHaveLength(5);
|
|
18
|
+
});
|
|
19
|
+
it('renders custom number of stars', ()=>{
|
|
20
|
+
const [field] = createFakeFieldAPI();
|
|
21
|
+
const { getAllByTestId } = render(React.createElement(RatingEditor, {
|
|
22
|
+
field: field,
|
|
23
|
+
isInitiallyDisabled: false,
|
|
24
|
+
parameters: {
|
|
25
|
+
installation: {},
|
|
26
|
+
instance: {
|
|
27
|
+
stars: 20
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
expect(getAllByTestId('rating-editor-star')).toHaveLength(20);
|
|
32
|
+
});
|
|
33
|
+
it('should should setValue by clicking on a item and removeValue by clicking on clear', ()=>{
|
|
34
|
+
const [field] = createFakeFieldAPI((field)=>{
|
|
35
|
+
jest.spyOn(field, 'setValue');
|
|
36
|
+
jest.spyOn(field, 'removeValue');
|
|
37
|
+
return {
|
|
38
|
+
...field
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const { container , getAllByTestId , getByTestId , queryByTestId } = render(React.createElement(RatingEditor, {
|
|
42
|
+
field: field,
|
|
43
|
+
isInitiallyDisabled: false
|
|
44
|
+
}));
|
|
45
|
+
const $stars = getAllByTestId('rating-editor-star');
|
|
46
|
+
expect(queryByTestId('rating-editor-clean')).not.toBeInTheDocument();
|
|
47
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(0);
|
|
48
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(5);
|
|
49
|
+
fireEvent.click($stars[4]);
|
|
50
|
+
expect(field.setValue).toHaveBeenCalledWith(5);
|
|
51
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(5);
|
|
52
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(0);
|
|
53
|
+
fireEvent.click($stars[0]);
|
|
54
|
+
expect(field.setValue).toHaveBeenCalledWith(1);
|
|
55
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(1);
|
|
56
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(4);
|
|
57
|
+
fireEvent.click(getByTestId('rating-editor-clear'));
|
|
58
|
+
expect(field.removeValue).toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
it('should should setValue by focusing and using Enter', ()=>{
|
|
61
|
+
const [field] = createFakeFieldAPI((field)=>{
|
|
62
|
+
jest.spyOn(field, 'setValue');
|
|
63
|
+
jest.spyOn(field, 'removeValue');
|
|
64
|
+
return {
|
|
65
|
+
...field
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
const { container , getAllByTestId , queryByTestId } = render(React.createElement(RatingEditor, {
|
|
69
|
+
field: field,
|
|
70
|
+
isInitiallyDisabled: false
|
|
71
|
+
}));
|
|
72
|
+
const $stars = getAllByTestId('rating-editor-star');
|
|
73
|
+
expect(queryByTestId('rating-editor-clean')).not.toBeInTheDocument();
|
|
74
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(0);
|
|
75
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(5);
|
|
76
|
+
fireEvent.focus($stars[2]);
|
|
77
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(3);
|
|
78
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(2);
|
|
79
|
+
fireEvent.keyDown($stars[2], {
|
|
80
|
+
keyCode: 13
|
|
81
|
+
});
|
|
82
|
+
expect(field.setValue).toHaveBeenCalledTimes(1);
|
|
83
|
+
expect(field.setValue).toHaveBeenCalledWith(3);
|
|
84
|
+
fireEvent.focus($stars[4]);
|
|
85
|
+
expect(container.querySelectorAll('[data-selected="true"]')).toHaveLength(5);
|
|
86
|
+
expect(container.querySelectorAll('[data-selected="false"]')).toHaveLength(0);
|
|
87
|
+
fireEvent.keyDown($stars[4], {
|
|
88
|
+
keyCode: 13
|
|
89
|
+
});
|
|
90
|
+
expect(field.setValue).toHaveBeenCalledTimes(2);
|
|
91
|
+
expect(field.setValue).toHaveBeenCalledWith(5);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
import * as React from 'react';
|
|
15
|
+
import { IconButton } from '@contentful/f36-components';
|
|
16
|
+
import { StarIcon } from '@contentful/f36-icons';
|
|
17
|
+
import { css } from 'emotion';
|
|
18
|
+
export class RatingRibbon extends React.Component {
|
|
19
|
+
render() {
|
|
20
|
+
const items = [];
|
|
21
|
+
for(let i = 1; i <= this.props.stars; i++){
|
|
22
|
+
items.push(i);
|
|
23
|
+
}
|
|
24
|
+
return React.createElement(React.Fragment, null, items.map((num)=>React.createElement(IconButton, {
|
|
25
|
+
variant: "transparent",
|
|
26
|
+
size: "small",
|
|
27
|
+
icon: React.createElement(StarIcon, {
|
|
28
|
+
variant: this.isSelected(num) ? 'primary' : 'muted',
|
|
29
|
+
className: css({
|
|
30
|
+
width: '22px',
|
|
31
|
+
height: '22px'
|
|
32
|
+
})
|
|
33
|
+
}),
|
|
34
|
+
"data-selected": this.isSelected(num) ? 'true' : 'false',
|
|
35
|
+
testId: "rating-editor-star",
|
|
36
|
+
isDisabled: this.props.disabled,
|
|
37
|
+
key: num,
|
|
38
|
+
onClick: ()=>{
|
|
39
|
+
this.props.onSelect(num);
|
|
40
|
+
},
|
|
41
|
+
onKeyDown: (e)=>{
|
|
42
|
+
if (e.keyCode === 13) {
|
|
43
|
+
this.props.onSelect(num);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
onMouseOver: this.onFocus(num),
|
|
47
|
+
onMouseLeave: this.onBlur,
|
|
48
|
+
onFocus: this.onFocus(num),
|
|
49
|
+
onBlur: this.onBlur,
|
|
50
|
+
"aria-label": num.toString()
|
|
51
|
+
})));
|
|
52
|
+
}
|
|
53
|
+
constructor(...args){
|
|
54
|
+
super(...args);
|
|
55
|
+
_define_property(this, "state", {
|
|
56
|
+
hovered: null
|
|
57
|
+
});
|
|
58
|
+
_define_property(this, "isSelected", (num)=>{
|
|
59
|
+
const hovered = this.state.hovered;
|
|
60
|
+
const value = this.props.value;
|
|
61
|
+
if (hovered !== null) {
|
|
62
|
+
return num <= hovered;
|
|
63
|
+
}
|
|
64
|
+
if (value) {
|
|
65
|
+
return num <= value;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
});
|
|
69
|
+
_define_property(this, "onBlur", ()=>{
|
|
70
|
+
if (!this.props.disabled) {
|
|
71
|
+
this.setState({
|
|
72
|
+
hovered: null
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
_define_property(this, "onFocus", (num)=>()=>{
|
|
77
|
+
if (!this.props.disabled) {
|
|
78
|
+
this.setState({
|
|
79
|
+
hovered: num
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RatingEditor } from './RatingEditor';
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
import { FieldAPI, ParametersAPI } from '@contentful/field-editor-shared';
|
|
3
|
-
export interface RatingEditorProps {
|
|
4
|
-
/**
|
|
5
|
-
* is the field disabled initially
|
|
6
|
-
*/
|
|
7
|
-
isInitiallyDisabled: boolean;
|
|
8
|
-
/**
|
|
9
|
-
* sdk.field
|
|
10
|
-
*/
|
|
11
|
-
field: FieldAPI;
|
|
12
|
-
/**
|
|
13
|
-
* sdk.parameters
|
|
14
|
-
*/
|
|
15
|
-
parameters?: ParametersAPI & {
|
|
16
|
-
instance: {
|
|
17
|
-
stars?: number;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export declare function RatingEditor(props: RatingEditorProps): JSX.Element;
|
|
22
|
-
export declare namespace RatingEditor {
|
|
23
|
-
var defaultProps: {
|
|
24
|
-
isInitiallyDisabled: boolean;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { FieldAPI, ParametersAPI } from '@contentful/field-editor-shared';
|
|
3
|
+
export interface RatingEditorProps {
|
|
4
|
+
/**
|
|
5
|
+
* is the field disabled initially
|
|
6
|
+
*/
|
|
7
|
+
isInitiallyDisabled: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* sdk.field
|
|
10
|
+
*/
|
|
11
|
+
field: FieldAPI;
|
|
12
|
+
/**
|
|
13
|
+
* sdk.parameters
|
|
14
|
+
*/
|
|
15
|
+
parameters?: ParametersAPI & {
|
|
16
|
+
instance: {
|
|
17
|
+
stars?: number;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function RatingEditor(props: RatingEditorProps): React.JSX.Element;
|
|
22
|
+
export declare namespace RatingEditor {
|
|
23
|
+
var defaultProps: {
|
|
24
|
+
isInitiallyDisabled: boolean;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/extend-expect';
|