@pie-lib/config-ui 12.0.0-beta.4 → 12.0.0-next.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.
Files changed (120) hide show
  1. package/CHANGELOG.json +8 -1653
  2. package/CHANGELOG.md +540 -58
  3. package/LICENSE.md +5 -0
  4. package/NEXT.CHANGELOG.json +1 -0
  5. package/lib/alert-dialog.js +44 -20
  6. package/lib/alert-dialog.js.map +1 -1
  7. package/lib/checkbox.js +59 -61
  8. package/lib/checkbox.js.map +1 -1
  9. package/lib/choice-configuration/feedback-menu.js +30 -65
  10. package/lib/choice-configuration/feedback-menu.js.map +1 -1
  11. package/lib/choice-configuration/index.js +231 -244
  12. package/lib/choice-configuration/index.js.map +1 -1
  13. package/lib/choice-utils.js +7 -19
  14. package/lib/choice-utils.js.map +1 -1
  15. package/lib/feedback-config/feedback-selector.js +89 -115
  16. package/lib/feedback-config/feedback-selector.js.map +1 -1
  17. package/lib/feedback-config/group.js +28 -42
  18. package/lib/feedback-config/group.js.map +1 -1
  19. package/lib/feedback-config/index.js +55 -87
  20. package/lib/feedback-config/index.js.map +1 -1
  21. package/lib/form-section.js +32 -34
  22. package/lib/form-section.js.map +1 -1
  23. package/lib/help.js +41 -80
  24. package/lib/help.js.map +1 -1
  25. package/lib/index.js +2 -32
  26. package/lib/index.js.map +1 -1
  27. package/lib/input.js +24 -57
  28. package/lib/input.js.map +1 -1
  29. package/lib/inputs.js +62 -88
  30. package/lib/inputs.js.map +1 -1
  31. package/lib/langs.js +59 -102
  32. package/lib/langs.js.map +1 -1
  33. package/lib/layout/config-layout.js +95 -67
  34. package/lib/layout/config-layout.js.map +1 -1
  35. package/lib/layout/index.js +1 -4
  36. package/lib/layout/index.js.map +1 -1
  37. package/lib/layout/layout-contents.js +130 -75
  38. package/lib/layout/layout-contents.js.map +1 -1
  39. package/lib/layout/settings-box.js +28 -58
  40. package/lib/layout/settings-box.js.map +1 -1
  41. package/lib/mui-box/index.js +42 -58
  42. package/lib/mui-box/index.js.map +1 -1
  43. package/lib/number-text-field-custom.js +164 -152
  44. package/lib/number-text-field-custom.js.map +1 -1
  45. package/lib/number-text-field.js +87 -119
  46. package/lib/number-text-field.js.map +1 -1
  47. package/lib/radio-with-label.js +33 -26
  48. package/lib/radio-with-label.js.map +1 -1
  49. package/lib/settings/display-size.js +17 -33
  50. package/lib/settings/display-size.js.map +1 -1
  51. package/lib/settings/index.js +26 -46
  52. package/lib/settings/index.js.map +1 -1
  53. package/lib/settings/panel.js +202 -221
  54. package/lib/settings/panel.js.map +1 -1
  55. package/lib/settings/settings-radio-label.js +37 -29
  56. package/lib/settings/settings-radio-label.js.map +1 -1
  57. package/lib/settings/toggle.js +40 -33
  58. package/lib/settings/toggle.js.map +1 -1
  59. package/lib/tabs/index.js +26 -57
  60. package/lib/tabs/index.js.map +1 -1
  61. package/lib/tags-input/index.js +51 -100
  62. package/lib/tags-input/index.js.map +1 -1
  63. package/lib/two-choice.js +47 -91
  64. package/lib/two-choice.js.map +1 -1
  65. package/lib/with-stateful-model.js +11 -34
  66. package/lib/with-stateful-model.js.map +1 -1
  67. package/package.json +22 -11
  68. package/src/__tests__/alert-dialog.test.jsx +283 -0
  69. package/src/__tests__/checkbox.test.jsx +249 -0
  70. package/src/__tests__/choice-utils.test.js +12 -0
  71. package/src/__tests__/form-section.test.jsx +334 -0
  72. package/src/__tests__/help.test.jsx +184 -0
  73. package/src/__tests__/input.test.jsx +192 -0
  74. package/src/__tests__/langs.test.jsx +457 -0
  75. package/src/__tests__/number-text-field-custom.test.jsx +438 -0
  76. package/src/__tests__/number-text-field.test.jsx +341 -0
  77. package/src/__tests__/radio-with-label.test.jsx +259 -0
  78. package/src/__tests__/settings-panel.test.js +187 -0
  79. package/src/__tests__/settings.test.jsx +515 -0
  80. package/src/__tests__/tabs.test.jsx +193 -0
  81. package/src/__tests__/two-choice.test.js +110 -0
  82. package/src/__tests__/with-stateful-model.test.jsx +145 -0
  83. package/src/alert-dialog.jsx +31 -16
  84. package/src/checkbox.jsx +45 -39
  85. package/src/choice-configuration/__tests__/feedback-menu.test.jsx +163 -0
  86. package/src/choice-configuration/__tests__/index.test.jsx +234 -0
  87. package/src/choice-configuration/feedback-menu.jsx +15 -28
  88. package/src/choice-configuration/index.jsx +233 -182
  89. package/src/choice-utils.js +1 -1
  90. package/src/feedback-config/__tests__/feedback-config.test.jsx +141 -0
  91. package/src/feedback-config/__tests__/feedback-selector.test.jsx +107 -0
  92. package/src/feedback-config/feedback-selector.jsx +65 -60
  93. package/src/feedback-config/group.jsx +26 -29
  94. package/src/feedback-config/index.jsx +59 -47
  95. package/src/form-section.jsx +26 -18
  96. package/src/help.jsx +27 -36
  97. package/src/index.js +2 -5
  98. package/src/input.jsx +9 -9
  99. package/src/inputs.jsx +36 -50
  100. package/src/langs.jsx +57 -73
  101. package/src/layout/__tests__/config.layout.test.jsx +59 -0
  102. package/src/layout/__tests__/layout-content.test.jsx +3 -0
  103. package/src/layout/config-layout.jsx +70 -37
  104. package/src/layout/layout-contents.jsx +96 -39
  105. package/src/layout/settings-box.jsx +22 -21
  106. package/src/mui-box/index.jsx +37 -45
  107. package/src/number-text-field-custom.jsx +136 -81
  108. package/src/number-text-field.jsx +59 -37
  109. package/src/radio-with-label.jsx +28 -12
  110. package/src/settings/display-size.jsx +14 -13
  111. package/src/settings/index.js +20 -12
  112. package/src/settings/panel.jsx +147 -110
  113. package/src/settings/settings-radio-label.jsx +29 -13
  114. package/src/settings/toggle.jsx +39 -20
  115. package/src/tabs/index.jsx +15 -19
  116. package/src/tags-input/__tests__/index.test.jsx +113 -0
  117. package/src/tags-input/index.jsx +42 -47
  118. package/src/two-choice.jsx +19 -23
  119. package/src/with-stateful-model.jsx +5 -5
  120. package/README.md +0 -12
@@ -1,23 +1,23 @@
1
1
  import React from 'react';
2
2
 
3
- import MuiTabs from '@material-ui/core/Tabs';
4
- import MuiTab from '@material-ui/core/Tab';
3
+ import MuiTabs from '@mui/material/Tabs';
4
+ import MuiTab from '@mui/material/Tab';
5
5
  import PropTypes from 'prop-types';
6
- import { withStyles } from '@material-ui/core';
6
+ import { styled } from '@mui/material/styles';
7
+
8
+ const StyledMuiTab = styled(MuiTab)(() => ({}));
7
9
 
8
10
  export class Tabs extends React.Component {
9
11
  static propTypes = {
10
- classes: PropTypes.object,
11
12
  className: PropTypes.string,
12
13
  contentClassName: PropTypes.string,
13
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired
14
+ contentStyle: PropTypes.object,
15
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
14
16
  };
15
17
 
16
18
  constructor(props) {
17
19
  super(props);
18
- this.state = {
19
- value: 0
20
- };
20
+ this.state = { value: 0 };
21
21
  }
22
22
 
23
23
  handleChange = (event, value) => {
@@ -26,26 +26,22 @@ export class Tabs extends React.Component {
26
26
 
27
27
  render() {
28
28
  const { value } = this.state;
29
- const { children, className, contentClassName, classes } = this.props;
29
+ const { children, className, contentClassName, contentStyle = {} } = this.props;
30
30
 
31
- const tabClasses = {
32
- root: classes.tabRoot
33
- };
34
31
  return (
35
32
  <div className={className}>
36
33
  <MuiTabs indicatorColor="primary" value={value} onChange={this.handleChange}>
37
34
  {React.Children.map(children, (c, index) =>
38
- c && c.props.title ? (
39
- <MuiTab classes={tabClasses} key={index} label={c.props.title} />
40
- ) : null
35
+ c && c.props.title ? <StyledMuiTab key={index} label={c.props.title} /> : null,
41
36
  )}
42
37
  </MuiTabs>
43
- <div className={contentClassName}>{children[value]}</div>
38
+
39
+ <div className={contentClassName} style={contentStyle}>
40
+ {children[value]}
41
+ </div>
44
42
  </div>
45
43
  );
46
44
  }
47
45
  }
48
46
 
49
- export default withStyles(() => ({
50
- tabRoot: {}
51
- }))(Tabs);
47
+ export default Tabs;
@@ -0,0 +1,113 @@
1
+ import { TagsInput } from '../index';
2
+ import { render, screen, userEvent, pressKey, Keys } from '@pie-lib/test-utils';
3
+ import React from 'react';
4
+
5
+ describe('TagsInput', () => {
6
+ describe('rendering', () => {
7
+ it('renders existing tags as chips', () => {
8
+ render(<TagsInput tags={['foo', 'bar']} onChange={jest.fn()} />);
9
+
10
+ expect(screen.getByText('foo')).toBeInTheDocument();
11
+ expect(screen.getByText('bar')).toBeInTheDocument();
12
+ });
13
+
14
+ it('renders input field', () => {
15
+ render(<TagsInput tags={['foo']} onChange={jest.fn()} />);
16
+
17
+ const input = screen.getByRole('textbox');
18
+ expect(input).toBeInTheDocument();
19
+ });
20
+ });
21
+
22
+ describe('user interactions', () => {
23
+ let onChange;
24
+ const renderComponent = (tags = ['foo']) => {
25
+ onChange = jest.fn();
26
+ return render(<TagsInput onChange={onChange} tags={tags} />);
27
+ };
28
+
29
+ describe('focus behavior', () => {
30
+ it('allows user to focus the input', async () => {
31
+ const user = userEvent.setup();
32
+ renderComponent();
33
+
34
+ const input = screen.getByRole('textbox');
35
+ await user.click(input);
36
+
37
+ expect(input).toHaveFocus();
38
+ });
39
+
40
+ it('allows user to blur the input', async () => {
41
+ const user = userEvent.setup();
42
+ renderComponent();
43
+
44
+ const input = screen.getByRole('textbox');
45
+ await user.click(input);
46
+ expect(input).toHaveFocus();
47
+
48
+ await user.tab();
49
+ expect(input).not.toHaveFocus();
50
+ });
51
+ });
52
+
53
+ describe('typing in input', () => {
54
+ it('updates input value when user types', async () => {
55
+ const user = userEvent.setup();
56
+ renderComponent();
57
+
58
+ const input = screen.getByRole('textbox');
59
+ await user.type(input, 'boo');
60
+
61
+ expect(input).toHaveValue('boo');
62
+ });
63
+ });
64
+
65
+ describe('adding tags', () => {
66
+ it('adds new tag when user presses Enter', async () => {
67
+ const user = userEvent.setup();
68
+ renderComponent();
69
+
70
+ const input = screen.getByRole('textbox');
71
+ await user.type(input, 'banana');
72
+ pressKey(input, Keys.ENTER);
73
+
74
+ expect(onChange).toHaveBeenCalledWith(['foo', 'banana']);
75
+ });
76
+
77
+ it('does not add duplicate tags', async () => {
78
+ const user = userEvent.setup();
79
+ renderComponent();
80
+
81
+ const input = screen.getByRole('textbox');
82
+ await user.type(input, 'foo');
83
+ pressKey(input, Keys.ENTER);
84
+
85
+ expect(onChange).not.toHaveBeenCalled();
86
+ });
87
+
88
+ it('clears input after adding tag', async () => {
89
+ const user = userEvent.setup();
90
+ renderComponent();
91
+
92
+ const input = screen.getByRole('textbox');
93
+ await user.type(input, 'banana');
94
+ pressKey(input, Keys.ENTER);
95
+
96
+ expect(input).toHaveValue('');
97
+ });
98
+ });
99
+
100
+ describe('deleting tags', () => {
101
+ it('removes tag when user clicks delete button', async () => {
102
+ const user = userEvent.setup();
103
+ renderComponent(['foo', 'bar']);
104
+
105
+ // Find the delete button for 'foo' tag
106
+ const deleteButtons = screen.getAllByTestId('CancelIcon');
107
+ await user.click(deleteButtons[0]);
108
+
109
+ expect(onChange).toHaveBeenCalledWith(['bar']);
110
+ });
111
+ });
112
+ });
113
+ });
@@ -1,41 +1,60 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { withStyles } from '@material-ui/core/styles';
3
+ import { styled } from '@mui/material/styles';
4
4
  import uniq from 'lodash/uniq';
5
- import Chip from '@material-ui/core/Chip';
5
+ import Chip from '@mui/material/Chip';
6
6
  import MuiBox from '../mui-box';
7
7
 
8
8
  const ENTER = 13;
9
9
 
10
- const Tag = withStyles(() => ({
11
- tag: {
12
- padding: '0px',
13
- margin: '1px'
14
- }
15
- }))(({ classes, label, onDelete }) => (
16
- <Chip className={classes.tag} label={label} onDelete={onDelete} />
17
- ));
10
+ const StyledChip = styled(Chip)(() => ({
11
+ padding: '0px',
12
+ margin: '1px',
13
+ }));
14
+
15
+ const Tag = ({ label, onDelete }) => <StyledChip label={label} onDelete={onDelete} />;
18
16
 
19
17
  Tag.propTypes = {
20
18
  label: PropTypes.string.isRequired,
21
- onDelete: PropTypes.func.isRequired
19
+ onDelete: PropTypes.func.isRequired,
22
20
  };
23
21
 
22
+ const StyledTagsInput = styled('div')(({ theme }) => ({
23
+ border: `0px solid ${theme.palette.background.paper}`,
24
+ display: 'flex',
25
+ flexWrap: 'wrap',
26
+ }));
27
+
28
+ const StyledInput = styled('input')(({ theme }) => ({
29
+ padding: '2px',
30
+ margin: '1px',
31
+ minWidth: '30px',
32
+ width: '100%',
33
+ flex: '1',
34
+ border: `0px solid ${theme.palette.background.paper}`,
35
+ height: '28px',
36
+ fontSize: theme.typography.fontSize,
37
+ fontFamily: theme.typography.fontFamily,
38
+ outline: 'none',
39
+ '&:focus': {
40
+ outline: 'none',
41
+ },
42
+ }));
43
+
24
44
  export class TagsInput extends React.Component {
25
45
  static propTypes = {
26
- classes: PropTypes.object.isRequired,
27
46
  tags: PropTypes.arrayOf(PropTypes.string).isRequired,
28
- onChange: PropTypes.func.isRequired
47
+ onChange: PropTypes.func.isRequired,
29
48
  };
30
49
 
31
50
  constructor(props) {
32
51
  super(props);
33
52
  this.state = {
34
53
  value: '',
35
- focused: false
54
+ focused: false,
36
55
  };
37
56
 
38
- this.onKeyDown = event => {
57
+ this.onKeyDown = (event) => {
39
58
  if (event.keyCode === ENTER && this.state.value !== '') {
40
59
  const tag = this.state.value.trim();
41
60
  const newTags = uniq(this.props.tags.concat([tag]));
@@ -47,11 +66,11 @@ export class TagsInput extends React.Component {
47
66
  }
48
67
  };
49
68
 
50
- this.onChange = event => {
69
+ this.onChange = (event) => {
51
70
  this.setState({ value: event.target.value });
52
71
  };
53
72
 
54
- this.deleteTag = tag => {
73
+ this.deleteTag = (tag) => {
55
74
  const { tags } = this.props;
56
75
 
57
76
  const tagIndex = tags.indexOf(tag);
@@ -72,50 +91,26 @@ export class TagsInput extends React.Component {
72
91
  };
73
92
 
74
93
  render() {
75
- const { classes, tags } = this.props;
94
+ const { tags } = this.props;
76
95
  return (
77
96
  <MuiBox focused={this.state.focused}>
78
- <div className={classes.tagsInput}>
97
+ <StyledTagsInput>
79
98
  {(tags || []).map((t, index) => (
80
99
  <Tag key={index} label={t} onDelete={() => this.deleteTag(t)} />
81
100
  ))}
82
- <input
83
- ref={r => (this.input = r)}
101
+ <StyledInput
102
+ ref={(r) => (this.input = r)}
84
103
  onKeyDown={this.onKeyDown}
85
104
  onChange={this.onChange}
86
- className={classes.input}
87
105
  value={this.state.value}
88
106
  onFocus={this.onFocus}
89
107
  onBlur={this.onBlur}
90
108
  type="text"
91
109
  />
92
- </div>
110
+ </StyledTagsInput>
93
111
  </MuiBox>
94
112
  );
95
113
  }
96
114
  }
97
115
 
98
- const styles = theme => ({
99
- tagsInput: {
100
- border: 'solid 0px white',
101
- display: 'flex',
102
- flexWrap: 'wrap'
103
- },
104
- input: {
105
- padding: '2px',
106
- margin: '1px',
107
- minWidth: '30px',
108
- width: '100%',
109
- flex: '1',
110
- border: 'solid 0px white',
111
- height: '28px',
112
- fontSize: theme.typography.fontSize,
113
- fontFamily: theme.typography.fontFamily,
114
- outline: 'none',
115
- '&:focus': {
116
- outline: 'none'
117
- }
118
- }
119
- });
120
-
121
- export default withStyles(styles)(TagsInput);
116
+ export default TagsInput;
@@ -2,22 +2,19 @@ import { InputContainer } from '@pie-lib/render-ui';
2
2
  import PropTypes from 'prop-types';
3
3
  import RadioWithLabel from './radio-with-label';
4
4
  import React from 'react';
5
- import classNames from 'classnames';
6
- import { withStyles } from '@material-ui/core/styles';
5
+ import { styled } from '@mui/material/styles';
7
6
 
8
- const styles = theme => ({
9
- group: {
10
- display: 'flex',
11
- flexWrap: 'wrap',
12
- paddingLeft: 0,
13
- marginTop: theme.spacing.unit
14
- },
15
- vertical: {
16
- flexDirection: 'column'
17
- }
18
- });
7
+ const StyledGroup = styled('div')(({ theme, direction }) => ({
8
+ display: 'flex',
9
+ flexWrap: 'wrap',
10
+ paddingLeft: 0,
11
+ marginTop: theme.spacing(1),
12
+ ...(direction === 'vertical' && {
13
+ flexDirection: 'column',
14
+ }),
15
+ }));
19
16
 
20
- class RawNChoice extends React.Component {
17
+ class NChoice extends React.Component {
21
18
  static propTypes = {
22
19
  header: PropTypes.string.isRequired,
23
20
  className: PropTypes.string,
@@ -26,24 +23,23 @@ class RawNChoice extends React.Component {
26
23
  value: PropTypes.string,
27
24
  onChange: PropTypes.func.isRequired,
28
25
  direction: PropTypes.oneOf(['horizontal', 'vertical']),
29
- classes: PropTypes.object.isRequired
30
26
  };
31
27
 
32
- handleChange = event => {
28
+ handleChange = (event) => {
33
29
  this.props.onChange(event.currentTarget.value);
34
30
  };
35
31
 
36
32
  render() {
37
- const { header, className, classes, customLabel, opts, value, direction } = this.props;
33
+ const { header, className, customLabel, opts, value, direction } = this.props;
38
34
 
39
- const preppedOpts = opts.map(o => {
35
+ const preppedOpts = opts.map((o) => {
40
36
  return typeof o === 'string' ? { label: o, value: o } : o;
41
37
  });
42
38
  const LabelComponent = customLabel || RadioWithLabel;
43
39
 
44
40
  return (
45
41
  <InputContainer label={header} className={className}>
46
- <div className={classNames(classes.group, classes[direction])}>
42
+ <StyledGroup direction={direction}>
47
43
  {preppedOpts.map((o, index) => (
48
44
  <LabelComponent
49
45
  value={o.value}
@@ -53,13 +49,13 @@ class RawNChoice extends React.Component {
53
49
  label={o.label}
54
50
  />
55
51
  ))}
56
- </div>
52
+ </StyledGroup>
57
53
  </InputContainer>
58
54
  );
59
55
  }
60
56
  }
61
57
 
62
- export const NChoice = withStyles(styles)(RawNChoice);
58
+ export { NChoice };
63
59
 
64
60
  const labelValue = PropTypes.shape({ label: PropTypes.string, value: PropTypes.string });
65
61
 
@@ -71,7 +67,7 @@ class TwoChoice extends React.Component {
71
67
  one: PropTypes.oneOfType([labelValue, PropTypes.string]),
72
68
  two: PropTypes.oneOfType([labelValue, PropTypes.string]),
73
69
  className: PropTypes.string,
74
- customLabel: PropTypes.func
70
+ customLabel: PropTypes.func,
75
71
  };
76
72
 
77
73
  render() {
@@ -91,4 +87,4 @@ class TwoChoice extends React.Component {
91
87
  }
92
88
  }
93
89
 
94
- export default withStyles(styles)(TwoChoice);
90
+ export default TwoChoice;
@@ -1,25 +1,25 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
- const withStatefulModel = Component => {
4
+ const withStatefulModel = (Component) => {
5
5
  class Stateful extends React.Component {
6
6
  static propTypes = {
7
7
  model: PropTypes.object.isRequired,
8
- onChange: PropTypes.func.isRequired
8
+ onChange: PropTypes.func.isRequired,
9
9
  };
10
10
 
11
11
  constructor(props) {
12
12
  super(props);
13
13
  this.state = {
14
- model: props.model
14
+ model: props.model,
15
15
  };
16
16
  }
17
17
 
18
- componentWillReceiveProps(props) {
18
+ UNSAFE_componentWillReceiveProps(props) {
19
19
  this.setState({ model: props.model });
20
20
  }
21
21
 
22
- onChange = model => {
22
+ onChange = (model) => {
23
23
  this.setState({ model }, () => {
24
24
  this.props.onChange(this.state.model);
25
25
  });
package/README.md DELETED
@@ -1,12 +0,0 @@
1
- # install
2
-
3
- ```
4
- npm install
5
- ```
6
-
7
- # demo
8
-
9
- ```
10
- cd demo
11
- ../node_modules/.bin/webpack-dev-server --hot --inline
12
- ```