@plone/volto 17.0.0-alpha.24 → 17.0.0-alpha.25

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 (78) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +41 -0
  3. package/CONTRIBUTING.md +5 -1
  4. package/README.md +2 -1
  5. package/locales/ca/LC_MESSAGES/volto.po +5 -0
  6. package/locales/ca.json +1 -1
  7. package/locales/de/LC_MESSAGES/volto.po +5 -0
  8. package/locales/de.json +1 -1
  9. package/locales/en/LC_MESSAGES/volto.po +5 -0
  10. package/locales/en.json +1 -1
  11. package/locales/es/LC_MESSAGES/volto.po +5 -0
  12. package/locales/es.json +1 -1
  13. package/locales/eu/LC_MESSAGES/volto.po +5 -0
  14. package/locales/eu.json +1 -1
  15. package/locales/fi/LC_MESSAGES/volto.po +5 -0
  16. package/locales/fi.json +1 -1
  17. package/locales/fr/LC_MESSAGES/volto.po +5 -0
  18. package/locales/fr.json +1 -1
  19. package/locales/it/LC_MESSAGES/volto.po +5 -0
  20. package/locales/it.json +1 -1
  21. package/locales/ja/LC_MESSAGES/volto.po +5 -0
  22. package/locales/ja.json +1 -1
  23. package/locales/nl/LC_MESSAGES/volto.po +5 -0
  24. package/locales/nl.json +1 -1
  25. package/locales/pt/LC_MESSAGES/volto.po +5 -0
  26. package/locales/pt.json +1 -1
  27. package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
  28. package/locales/pt_BR.json +1 -1
  29. package/locales/ro/LC_MESSAGES/volto.po +5 -0
  30. package/locales/ro.json +1 -1
  31. package/locales/volto.pot +6 -1
  32. package/locales/zh_CN/LC_MESSAGES/volto.po +5 -0
  33. package/locales/zh_CN.json +1 -1
  34. package/package.json +1 -1
  35. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
  36. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
  37. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
  38. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +6 -0
  39. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
  40. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +10 -0
  41. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +30 -0
  42. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +10 -0
  43. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
  44. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +6 -0
  45. package/packages/volto-slate/package.json +1 -1
  46. package/src/actions/index.js +1 -0
  47. package/src/actions/relations/relations.js +17 -0
  48. package/src/components/manage/Blocks/Image/schema.js +5 -1
  49. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -11
  50. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +4 -3
  51. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
  52. package/src/components/manage/Contents/Contents.jsx +27 -0
  53. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +11 -9
  54. package/src/components/manage/Controlpanels/Relations/Relations.jsx +3 -3
  55. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
  56. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +15 -9
  57. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +25 -10
  58. package/src/components/manage/Diff/DiffField.jsx +25 -1
  59. package/src/components/manage/LinksToItem/LinksToItem.jsx +1 -1
  60. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +1 -1
  61. package/src/components/manage/Sharing/Sharing.jsx +11 -5
  62. package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
  63. package/src/components/theme/Comments/Comment.stories.jsx +84 -0
  64. package/src/components/theme/Comments/Comments.jsx +273 -378
  65. package/src/components/theme/Logout/Logout.jsx +36 -83
  66. package/src/components/theme/Search/SearchTags.jsx +30 -60
  67. package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
  68. package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
  69. package/src/constants/ActionTypes.js +1 -0
  70. package/src/reducers/relations/relations.js +74 -46
  71. package/src/server.jsx +9 -0
  72. package/theme/themes/pastanaga/collections/form.overrides +46 -0
  73. package/theme/themes/pastanaga/elements/input.overrides +6 -0
  74. package/theme/themes/pastanaga/elements/label.overrides +10 -0
  75. package/.gitignore~ +0 -71
  76. package/news/4547.breaking~ +0 -1
  77. package/package.json~ +0 -444
  78. package/src/config/index.js~ +0 -223
@@ -1,19 +1,11 @@
1
- /**
2
- * Login container.
3
- * @module components/theme/Logout/Logout
4
- */
5
-
6
- import React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
- import { compose } from 'redux';
10
- import { defineMessages, injectIntl } from 'react-intl';
1
+ import { useEffect, useMemo } from 'react';
2
+ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
3
+ import { useHistory } from 'react-router-dom';
4
+ import { defineMessages, useIntl } from 'react-intl';
11
5
  import qs from 'query-string';
12
-
13
- import { Login } from '@plone/volto/components';
6
+ import { Login, Toast } from '@plone/volto/components';
14
7
  import { logout, purgeMessages } from '@plone/volto/actions';
15
8
  import { toast } from 'react-toastify';
16
- import { Toast } from '@plone/volto/components';
17
9
 
18
10
  const messages = defineMessages({
19
11
  loggedOut: {
@@ -26,83 +18,44 @@ const messages = defineMessages({
26
18
  },
27
19
  });
28
20
 
29
- /**
30
- * Logout class.
31
- * @class Logout
32
- * @extends Component
33
- */
34
- class Logout extends Component {
35
- /**
36
- * Property types.
37
- * @property {Object} propTypes Property types.
38
- * @static
39
- */
40
- static propTypes = {
41
- logout: PropTypes.func.isRequired,
42
- purgeMessages: PropTypes.func.isRequired,
43
- query: PropTypes.shape({
44
- return_url: PropTypes.string,
45
- }),
46
- };
47
-
48
- /**
49
- * Default properties.
50
- * @property {Object} defaultProps Default properties.
51
- * @static
52
- */
53
- static defaultProps = {
54
- query: null,
55
- };
56
-
57
- componentDidMount() {
58
- this.props.logout();
59
- this.props.purgeMessages();
60
- }
61
-
62
- /**
63
- * Component will receive props
64
- * @method componentWillReceiveProps
65
- * @param {Object} nextProps Next properties
66
- * @returns {undefined}
67
- */
68
- UNSAFE_componentWillReceiveProps(nextProps) {
69
- if (!nextProps.token) {
70
- this.props.history.replace(this.props.returnUrl || '/');
21
+ const Logout = ({ location }) => {
22
+ const token = useSelector((state) => state.userSession.token, shallowEqual);
23
+ const history = useHistory();
24
+ const dispatch = useDispatch();
25
+ const intl = useIntl();
26
+
27
+ const returnUrl = useMemo(
28
+ () =>
29
+ qs.parse(location.search).return_url ||
30
+ location.pathname
31
+ .replace(/\/login\/?$/, '')
32
+ .replace(/\/logout\/?$/, '') ||
33
+ '/',
34
+ [location],
35
+ );
36
+
37
+ useEffect(() => {
38
+ dispatch(logout());
39
+ dispatch(purgeMessages());
40
+ }, [dispatch]);
41
+
42
+ useEffect(() => {
43
+ if (!token) {
44
+ history.replace(returnUrl || '/');
71
45
  if (!toast.isActive('loggedOut')) {
72
46
  toast.info(
73
47
  <Toast
74
48
  info
75
- title={this.props.intl.formatMessage(messages.loggedOut)}
76
- content={this.props.intl.formatMessage(messages.loggedOutContent)}
49
+ title={intl.formatMessage(messages.loggedOut)}
50
+ content={intl.formatMessage(messages.loggedOutContent)}
77
51
  />,
78
52
  { autoClose: false, toastId: 'loggedOut' },
79
53
  );
80
54
  }
81
55
  }
82
- }
56
+ }, [history, returnUrl, intl, token]);
57
+
58
+ return <Login location={{ query: location.query }} />;
59
+ };
83
60
 
84
- /**
85
- * Render method.
86
- * @method render
87
- * @returns {string} Markup for the component.
88
- */
89
- render() {
90
- return <Login location={{ query: this.props.location.query }} />;
91
- }
92
- }
93
- export default compose(
94
- injectIntl,
95
- connect(
96
- (state, props) => ({
97
- query: qs.parse(props.location.search),
98
- token: state.userSession.token,
99
- returnUrl:
100
- qs.parse(props.location.search).return_url ||
101
- props.location.pathname
102
- .replace(/\/login\/?$/, '')
103
- .replace(/\/logout\/?$/, '') ||
104
- '/',
105
- }),
106
- { logout, purgeMessages },
107
- ),
108
- )(Logout);
61
+ export default Logout;
@@ -1,71 +1,41 @@
1
- /**
2
- * Search tags components.
3
- * @module components/theme/Search/SearchTags
4
- */
5
-
6
- import React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
1
+ import { useEffect } from 'react';
2
+ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
9
3
  import { Link } from 'react-router-dom';
10
4
 
11
5
  import { getVocabulary } from '@plone/volto/actions';
12
6
 
13
7
  const vocabulary = 'plone.app.vocabularies.Keywords';
14
8
 
15
- /**
16
- * Search tags container class.
17
- * @class SearchTags
18
- * @extends Component
19
- */
20
- class SearchTags extends Component {
21
- /**
22
- * Property types.
23
- * @property {Object} propTypes Property types.
24
- * @static
25
- */
26
- static propTypes = {
27
- getVocabulary: PropTypes.func.isRequired,
28
- items: PropTypes.arrayOf(
29
- PropTypes.shape({
30
- label: PropTypes.string,
31
- }),
32
- ).isRequired,
33
- };
34
-
35
- componentDidMount() {
36
- this.props.getVocabulary({ vocabNameOrURL: vocabulary });
37
- }
9
+ const SearchTags = () => {
10
+ const dispatch = useDispatch();
38
11
 
39
- /**
40
- * Render method.
41
- * @method render
42
- * @returns {string} Markup for the component.
43
- */
44
- render() {
45
- return this.props.items && this.props.items.length > 0 ? (
46
- <div>
47
- {this.props.items.map((item) => (
48
- <Link
49
- className="ui label"
50
- to={`/search?Subject=${item.label}`}
51
- key={item.label}
52
- >
53
- {item.label}
54
- </Link>
55
- ))}
56
- </div>
57
- ) : (
58
- <span />
59
- );
60
- }
61
- }
12
+ useEffect(() => {
13
+ dispatch(getVocabulary({ vocabNameOrURL: vocabulary }));
14
+ }, [dispatch]);
62
15
 
63
- export default connect(
64
- (state) => ({
65
- items:
16
+ const items = useSelector(
17
+ (state) =>
66
18
  state.vocabularies[vocabulary] && state.vocabularies[vocabulary].items
67
19
  ? state.vocabularies[vocabulary].items
68
20
  : [],
69
- }),
70
- { getVocabulary },
71
- )(SearchTags);
21
+ shallowEqual,
22
+ );
23
+
24
+ return items && items.length > 0 ? (
25
+ <div>
26
+ {items.map((item) => (
27
+ <Link
28
+ className="ui label"
29
+ to={`/search?Subject=${item.label}`}
30
+ key={item.label}
31
+ >
32
+ {item.label}
33
+ </Link>
34
+ ))}
35
+ </div>
36
+ ) : (
37
+ <span />
38
+ );
39
+ };
40
+
41
+ export default SearchTags;
@@ -22,6 +22,13 @@ const messages = defineMessages({
22
22
  defaultMessage: 'Sitemap',
23
23
  },
24
24
  });
25
+
26
+ export function getSitemapPath(pathname = '', lang) {
27
+ const prefix = pathname.replace(/\/sitemap$/gm, '').replace(/^\//, '');
28
+ const path = prefix || lang || '';
29
+ return path;
30
+ }
31
+
25
32
  /**
26
33
  * Sitemap class.
27
34
  * @class Sitemap
@@ -39,11 +46,13 @@ class Sitemap extends Component {
39
46
 
40
47
  componentDidMount() {
41
48
  const { settings } = config;
42
- if (settings.isMultilingual) {
43
- this.props.getNavigation(`${toBackendLang(this.props.lang)}`, 4);
44
- } else {
45
- this.props.getNavigation('', 4);
46
- }
49
+
50
+ const lang = settings.isMultilingual
51
+ ? `${toBackendLang(this.props.lang)}`
52
+ : null;
53
+
54
+ const path = getSitemapPath(this.props.location.pathname, lang);
55
+ this.props.getNavigation(path, 4);
47
56
  }
48
57
 
49
58
  /**
@@ -105,15 +114,17 @@ export default compose(
105
114
  {
106
115
  key: 'navigation',
107
116
  promise: ({ location, store: { dispatch, getState } }) => {
117
+ if (!__SERVER__) return;
108
118
  const { settings } = config;
109
- const lang = getState().intl.locale;
110
- if (settings.isMultilingual) {
111
- return (
112
- __SERVER__ && dispatch(getNavigation(`${toBackendLang(lang)}`, 4))
113
- );
114
- } else {
115
- return __SERVER__ && dispatch(getNavigation('', 4));
116
- }
119
+
120
+ const path = getSitemapPath(
121
+ location.pathname,
122
+ settings.isMultilingual
123
+ ? toBackendLang(getState().intl.locale)
124
+ : null,
125
+ );
126
+
127
+ return dispatch(getNavigation(path, 4));
117
128
  },
118
129
  },
119
130
  ]),
@@ -4,7 +4,7 @@ import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
6
 
7
- import { __test__ as Sitemap } from './Sitemap';
7
+ import { __test__ as Sitemap, getSitemapPath } from './Sitemap';
8
8
 
9
9
  const mockStore = configureStore();
10
10
 
@@ -46,7 +46,7 @@ describe('Sitemap', () => {
46
46
  const component = renderer.create(
47
47
  <Provider store={store}>
48
48
  <MemoryRouter>
49
- <Sitemap />
49
+ <Sitemap location={{ pathname: '/page-1' }} />
50
50
  </MemoryRouter>
51
51
  </Provider>,
52
52
  );
@@ -54,3 +54,24 @@ describe('Sitemap', () => {
54
54
  expect(json).toMatchSnapshot();
55
55
  });
56
56
  });
57
+
58
+ describe('getSitemapPath', () => {
59
+ it('accepts empty path', () => {
60
+ expect(getSitemapPath('', null)).toBe('');
61
+ });
62
+
63
+ it('accepts a path', () => {
64
+ expect(getSitemapPath('/page-1/sitemap', null)).toBe('page-1');
65
+ });
66
+ it('accepts a path', () => {
67
+ expect(getSitemapPath('/page-1/sitemap', null)).toBe('page-1');
68
+ });
69
+
70
+ it('uses a language as default root', () => {
71
+ expect(getSitemapPath('/', 'de')).toBe('de');
72
+ });
73
+
74
+ it('accepts language-rooted paths', () => {
75
+ expect(getSitemapPath('/de/mission', 'de')).toBe('de/mission');
76
+ });
77
+ });
@@ -39,6 +39,7 @@ export const GET_QUERYSTRING_RESULTS = 'GET_QUERYSTRING_RESULTS';
39
39
  export const CREATE_RELATIONS = 'CREATE_RELATIONS';
40
40
  export const DELETE_RELATIONS = 'DELETE_RELATIONS';
41
41
  export const LIST_RELATIONS = 'LIST_RELATIONS';
42
+ export const STATS_RELATIONS = 'STATS_RELATIONS';
42
43
  export const REBUILD_RELATIONS = 'REBUILD_RELATIONS';
43
44
  export const GET_SCHEMA = 'GET_SCHEMA';
44
45
  export const POST_SCHEMA = 'POST_SCHEMA';
@@ -7,23 +7,29 @@ import {
7
7
  CREATE_RELATIONS,
8
8
  DELETE_RELATIONS,
9
9
  LIST_RELATIONS,
10
+ STATS_RELATIONS,
10
11
  REBUILD_RELATIONS,
11
12
  } from '@plone/volto/constants/ActionTypes';
12
13
 
13
14
  const initialState = {
14
- relations: null,
15
- stats: null,
16
- create: {
15
+ relations: {
17
16
  error: null,
18
17
  loaded: false,
19
18
  loading: false,
19
+ data: null,
20
20
  },
21
- delete: {
21
+ stats: {
22
+ error: null,
23
+ loaded: false,
24
+ loading: false,
25
+ data: null,
26
+ },
27
+ create: {
22
28
  error: null,
23
29
  loaded: false,
24
30
  loading: false,
25
31
  },
26
- list: {
32
+ delete: {
27
33
  error: null,
28
34
  loaded: false,
29
35
  loading: false,
@@ -55,17 +61,6 @@ function getRequestKey(actionType) {
55
61
  */
56
62
  export default function relations(state = initialState, action = {}) {
57
63
  switch (action.type) {
58
- case `${CREATE_RELATIONS}_PENDING`:
59
- case `${DELETE_RELATIONS}_PENDING`:
60
- case `${REBUILD_RELATIONS}_PENDING`:
61
- return {
62
- ...state,
63
- [getRequestKey(action.type)]: {
64
- loading: true,
65
- loaded: false,
66
- error: null,
67
- },
68
- };
69
64
  case `${LIST_RELATIONS}_PENDING`:
70
65
  return action.subrequest
71
66
  ? {
@@ -73,10 +68,7 @@ export default function relations(state = initialState, action = {}) {
73
68
  subrequests: {
74
69
  ...state.subrequests,
75
70
  [action.subrequest]: {
76
- ...(state.subrequests[action.subrequest] || {
77
- relations: null,
78
- stats: null,
79
- }),
71
+ data: null,
80
72
  loaded: false,
81
73
  loading: true,
82
74
  error: null,
@@ -85,7 +77,8 @@ export default function relations(state = initialState, action = {}) {
85
77
  }
86
78
  : {
87
79
  ...state,
88
- [getRequestKey(action.type)]: {
80
+ relations: {
81
+ data: null,
89
82
  loading: true,
90
83
  loaded: false,
91
84
  error: null,
@@ -98,39 +91,22 @@ export default function relations(state = initialState, action = {}) {
98
91
  subrequests: {
99
92
  ...state.subrequests,
100
93
  [action.subrequest]: {
94
+ data: action.result.relations,
101
95
  loading: false,
102
96
  loaded: true,
103
97
  error: null,
104
- relations: action.result.relations
105
- ? action.result.relations
106
- : [],
107
- stats: null,
108
98
  },
109
99
  },
110
100
  }
111
101
  : {
112
102
  ...state,
113
- relations: action.result.relations
114
- ? action.result.relations
115
- : state.relations,
116
- stats: action.result.stats ? action.result : state.stats,
117
- [getRequestKey(action.type)]: {
103
+ relations: {
104
+ data: action.result.relations,
118
105
  loading: false,
119
106
  loaded: true,
120
107
  error: null,
121
108
  },
122
109
  };
123
- case `${CREATE_RELATIONS}_SUCCESS`:
124
- case `${DELETE_RELATIONS}_SUCCESS`:
125
- case `${REBUILD_RELATIONS}_SUCCESS`:
126
- return {
127
- ...state,
128
- [getRequestKey(action.type)]: {
129
- loading: false,
130
- loaded: true,
131
- error: null,
132
- },
133
- };
134
110
  case `${LIST_RELATIONS}_FAIL`:
135
111
  return action.subrequest
136
112
  ? {
@@ -138,8 +114,7 @@ export default function relations(state = initialState, action = {}) {
138
114
  subrequests: {
139
115
  ...state.subrequests,
140
116
  [action.subrequest]: {
141
- relations: null,
142
- stats: null,
117
+ data: null,
143
118
  loading: false,
144
119
  loaded: false,
145
120
  error: action.error,
@@ -148,14 +123,67 @@ export default function relations(state = initialState, action = {}) {
148
123
  }
149
124
  : {
150
125
  ...state,
151
- relations: null,
152
- stats: null,
153
- [getRequestKey(action.type)]: {
126
+ relations: {
127
+ data: null,
154
128
  loading: false,
155
129
  loaded: false,
156
130
  error: action.error,
157
131
  },
158
132
  };
133
+
134
+ case `${STATS_RELATIONS}_PENDING`:
135
+ return {
136
+ ...state,
137
+ [getRequestKey(action.type)]: {
138
+ loading: true,
139
+ loaded: false,
140
+ error: null,
141
+ data: null,
142
+ },
143
+ };
144
+ case `${STATS_RELATIONS}_SUCCESS`:
145
+ return {
146
+ ...state,
147
+ [getRequestKey(action.type)]: {
148
+ loading: false,
149
+ loaded: true,
150
+ error: null,
151
+ data: action.result,
152
+ },
153
+ };
154
+ case `${STATS_RELATIONS}_FAIL`:
155
+ return {
156
+ ...state,
157
+ [getRequestKey(action.type)]: {
158
+ loading: false,
159
+ loaded: false,
160
+ error: action.error,
161
+ data: null,
162
+ },
163
+ };
164
+
165
+ case `${CREATE_RELATIONS}_PENDING`:
166
+ case `${DELETE_RELATIONS}_PENDING`:
167
+ case `${REBUILD_RELATIONS}_PENDING`:
168
+ return {
169
+ ...state,
170
+ [getRequestKey(action.type)]: {
171
+ loading: true,
172
+ loaded: false,
173
+ error: null,
174
+ },
175
+ };
176
+ case `${CREATE_RELATIONS}_SUCCESS`:
177
+ case `${DELETE_RELATIONS}_SUCCESS`:
178
+ case `${REBUILD_RELATIONS}_SUCCESS`:
179
+ return {
180
+ ...state,
181
+ [getRequestKey(action.type)]: {
182
+ loading: false,
183
+ loaded: true,
184
+ error: null,
185
+ },
186
+ };
159
187
  case `${CREATE_RELATIONS}_FAIL`:
160
188
  case `${DELETE_RELATIONS}_FAIL`:
161
189
  case `${REBUILD_RELATIONS}_FAIL`:
package/src/server.jsx CHANGED
@@ -263,6 +263,15 @@ server.get('/*', (req, res) => {
263
263
  const readCriticalCss =
264
264
  config.settings.serverConfig.readCriticalCss || defaultReadCriticalCss;
265
265
 
266
+ // If we are showing an "old browser" warning,
267
+ // make sure it doesn't get cached in a shared cache
268
+ const browserdetect = store.getState().browserdetect;
269
+ if (config.settings.notSupportedBrowsers.includes(browserdetect?.name)) {
270
+ res.set({
271
+ 'Cache-Control': 'private',
272
+ });
273
+ }
274
+
266
275
  if (context.url) {
267
276
  res.redirect(flattenToAppURL(context.url));
268
277
  } else if (context.error_code) {
@@ -49,6 +49,52 @@
49
49
  }
50
50
  }
51
51
 
52
+ .ui.form .fields.error .field textarea,
53
+ .ui.form .fields.error .field select,
54
+ .ui.form .fields.error .field input:not([type]),
55
+ .ui.form .fields.error .field input[type='date'],
56
+ .ui.form .fields.error .field input[type='datetime-local'],
57
+ .ui.form .fields.error .field input[type='email'],
58
+ .ui.form .fields.error .field input[type='number'],
59
+ .ui.form .fields.error .field input[type='password'],
60
+ .ui.form .fields.error .field input[type='search'],
61
+ .ui.form .fields.error .field input[type='tel'],
62
+ .ui.form .fields.error .field input[type='time'],
63
+ .ui.form .fields.error .field input[type='text'],
64
+ .ui.form .fields.error .field input[type='file'],
65
+ .ui.form .fields.error .field input[type='url'],
66
+ .ui.form .field.error textarea,
67
+ .ui.form .field.error select,
68
+ .ui.form .field.error input:not([type]),
69
+ .ui.form .field.error input[type='date'],
70
+ .ui.form .field.error input[type='datetime-local'],
71
+ .ui.form .field.error input[type='email'],
72
+ .ui.form .field.error input[type='number'],
73
+ .ui.form .field.error input[type='password'],
74
+ .ui.form .field.error input[type='search'],
75
+ .ui.form .field.error input[type='tel'],
76
+ .ui.form .field.error input[type='time'],
77
+ .ui.form .field.error input[type='text'],
78
+ .ui.form .field.error input[type='file'],
79
+ .ui.form .field.error input[type='url'],
80
+ .ui.form .field.error textarea:focus,
81
+ .ui.form .field.error select:focus,
82
+ .ui.form .field.error input:not([type]):focus,
83
+ .ui.form .field.error input[type='date']:focus,
84
+ .ui.form .field.error input[type='datetime-local']:focus,
85
+ .ui.form .field.error input[type='email']:focus,
86
+ .ui.form .field.error input[type='number']:focus,
87
+ .ui.form .field.error input[type='password']:focus,
88
+ .ui.form .field.error input[type='search']:focus,
89
+ .ui.form .field.error input[type='tel']:focus,
90
+ .ui.form .field.error input[type='time']:focus,
91
+ .ui.form .field.error input[type='text']:focus,
92
+ .ui.form .field.error input[type='file']:focus,
93
+ .ui.form .field.error input[type='url']:focus {
94
+ border-color: #d01157;
95
+ background: none;
96
+ }
97
+
52
98
  .ui.form .field > .selection.dropdown {
53
99
  height: 60px;
54
100
  }
@@ -6,6 +6,12 @@
6
6
  font-weight: @inputFontWeight;
7
7
  }
8
8
 
9
+ /* This aligns the height of the field name label to the other side in case
10
+ of an error is present, it overrides a default from SemanticUI grid definitions. */
11
+ .ui.grid > .stretched.row > .column > .wrapper {
12
+ flex-grow: 0;
13
+ }
14
+
9
15
  .inline.field {
10
16
  .wrapper {
11
17
  display: flex;
@@ -6,3 +6,13 @@
6
6
  margin: 0em 0em 0em 0.75em;
7
7
  }
8
8
  }
9
+
10
+ .ui.form {
11
+ .ui.basic.red.label.form-error-label {
12
+ padding-left: 0;
13
+ border: none;
14
+ margin-top: 0;
15
+ color: #d01157 !important;
16
+ font-weight: normal;
17
+ }
18
+ }