@plone/volto 18.33.1 → 18.35.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 (173) hide show
  1. package/.release-it.json +3 -0
  2. package/CHANGELOG.md +52 -0
  3. package/README.md +0 -1
  4. package/locales/af/LC_MESSAGES/volto.po +55 -0
  5. package/locales/af.json +1 -1
  6. package/locales/ar/LC_MESSAGES/volto.po +55 -0
  7. package/locales/ar.json +1 -1
  8. package/locales/bg/LC_MESSAGES/volto.po +55 -0
  9. package/locales/bg.json +1 -1
  10. package/locales/bn/LC_MESSAGES/volto.po +55 -0
  11. package/locales/bn.json +1 -1
  12. package/locales/ca/LC_MESSAGES/volto.po +57 -2
  13. package/locales/ca.json +1 -1
  14. package/locales/cs/LC_MESSAGES/volto.po +55 -0
  15. package/locales/cs.json +1 -1
  16. package/locales/cy/LC_MESSAGES/volto.po +55 -0
  17. package/locales/cy.json +1 -1
  18. package/locales/da/LC_MESSAGES/volto.po +55 -0
  19. package/locales/da.json +1 -1
  20. package/locales/de/LC_MESSAGES/volto.po +59 -4
  21. package/locales/de.json +1 -1
  22. package/locales/el/LC_MESSAGES/volto.po +55 -0
  23. package/locales/el.json +1 -1
  24. package/locales/en/LC_MESSAGES/volto.po +55 -0
  25. package/locales/en.json +1 -1
  26. package/locales/en_AU/LC_MESSAGES/volto.po +55 -0
  27. package/locales/en_AU.json +1 -1
  28. package/locales/en_GB/LC_MESSAGES/volto.po +55 -0
  29. package/locales/en_GB.json +1 -1
  30. package/locales/eo/LC_MESSAGES/volto.po +55 -0
  31. package/locales/eo.json +1 -1
  32. package/locales/es/LC_MESSAGES/volto.po +73 -18
  33. package/locales/es.json +1 -1
  34. package/locales/et/LC_MESSAGES/volto.po +55 -0
  35. package/locales/et.json +1 -1
  36. package/locales/eu/LC_MESSAGES/volto.po +58 -3
  37. package/locales/eu.json +1 -1
  38. package/locales/fa/LC_MESSAGES/volto.po +55 -0
  39. package/locales/fa.json +1 -1
  40. package/locales/fi/LC_MESSAGES/volto.po +55 -0
  41. package/locales/fi.json +1 -1
  42. package/locales/fr/LC_MESSAGES/volto.po +56 -1
  43. package/locales/fr.json +1 -1
  44. package/locales/fu/LC_MESSAGES/volto.po +55 -0
  45. package/locales/fu.json +1 -1
  46. package/locales/gl/LC_MESSAGES/volto.po +60 -5
  47. package/locales/gl.json +1 -1
  48. package/locales/he/LC_MESSAGES/volto.po +55 -0
  49. package/locales/he.json +1 -1
  50. package/locales/hi/LC_MESSAGES/volto.po +58 -3
  51. package/locales/hi.json +1 -1
  52. package/locales/hr/LC_MESSAGES/volto.po +55 -0
  53. package/locales/hr.json +1 -1
  54. package/locales/hu/LC_MESSAGES/volto.po +55 -0
  55. package/locales/hu.json +1 -1
  56. package/locales/hy/LC_MESSAGES/volto.po +55 -0
  57. package/locales/hy.json +1 -1
  58. package/locales/id/LC_MESSAGES/volto.po +55 -0
  59. package/locales/id.json +1 -1
  60. package/locales/it/LC_MESSAGES/volto.po +56 -1
  61. package/locales/it.json +1 -1
  62. package/locales/ja/LC_MESSAGES/volto.po +55 -0
  63. package/locales/ja.json +1 -1
  64. package/locales/ka/LC_MESSAGES/volto.po +55 -0
  65. package/locales/ka.json +1 -1
  66. package/locales/kn/LC_MESSAGES/volto.po +55 -0
  67. package/locales/kn.json +1 -1
  68. package/locales/ko/LC_MESSAGES/volto.po +55 -0
  69. package/locales/ko.json +1 -1
  70. package/locales/lt/LC_MESSAGES/volto.po +55 -0
  71. package/locales/lt.json +1 -1
  72. package/locales/lv/LC_MESSAGES/volto.po +55 -0
  73. package/locales/lv.json +1 -1
  74. package/locales/mi/LC_MESSAGES/volto.po +55 -0
  75. package/locales/mi.json +1 -1
  76. package/locales/mk/LC_MESSAGES/volto.po +55 -0
  77. package/locales/mk.json +1 -1
  78. package/locales/my/LC_MESSAGES/volto.po +55 -0
  79. package/locales/my.json +1 -1
  80. package/locales/nb_NO/LC_MESSAGES/volto.po +55 -0
  81. package/locales/nb_NO.json +1 -1
  82. package/locales/nl/LC_MESSAGES/volto.po +56 -1
  83. package/locales/nl.json +1 -1
  84. package/locales/nn/LC_MESSAGES/volto.po +55 -0
  85. package/locales/nn.json +1 -1
  86. package/locales/pl/LC_MESSAGES/volto.po +55 -0
  87. package/locales/pl.json +1 -1
  88. package/locales/pt/LC_MESSAGES/volto.po +55 -0
  89. package/locales/pt.json +1 -1
  90. package/locales/pt_BR/LC_MESSAGES/volto.po +69 -14
  91. package/locales/pt_BR.json +1 -1
  92. package/locales/rm/LC_MESSAGES/volto.po +55 -0
  93. package/locales/rm.json +1 -1
  94. package/locales/ro/LC_MESSAGES/volto.po +56 -1
  95. package/locales/ro.json +1 -1
  96. package/locales/ru/LC_MESSAGES/volto.po +56 -1
  97. package/locales/ru.json +1 -1
  98. package/locales/sk/LC_MESSAGES/volto.po +55 -0
  99. package/locales/sk.json +1 -1
  100. package/locales/sl/LC_MESSAGES/volto.po +55 -0
  101. package/locales/sl.json +1 -1
  102. package/locales/sm/LC_MESSAGES/volto.po +55 -0
  103. package/locales/sm.json +1 -1
  104. package/locales/sq/LC_MESSAGES/volto.po +55 -0
  105. package/locales/sq.json +1 -1
  106. package/locales/sr/LC_MESSAGES/volto.po +55 -0
  107. package/locales/sr.json +1 -1
  108. package/locales/sr@cyrl/LC_MESSAGES/volto.po +55 -0
  109. package/locales/sr@cyrl.json +1 -1
  110. package/locales/sr@latn/LC_MESSAGES/volto.po +55 -0
  111. package/locales/sr@latn.json +1 -1
  112. package/locales/sv/LC_MESSAGES/volto.po +55 -0
  113. package/locales/sv.json +1 -1
  114. package/locales/ta/LC_MESSAGES/volto.po +56 -1
  115. package/locales/ta.json +1 -1
  116. package/locales/te/LC_MESSAGES/volto.po +55 -0
  117. package/locales/te.json +1 -1
  118. package/locales/th/LC_MESSAGES/volto.po +55 -0
  119. package/locales/th.json +1 -1
  120. package/locales/to/LC_MESSAGES/volto.po +55 -0
  121. package/locales/to.json +1 -1
  122. package/locales/tr/LC_MESSAGES/volto.po +55 -0
  123. package/locales/tr.json +1 -1
  124. package/locales/uk/LC_MESSAGES/volto.po +55 -0
  125. package/locales/uk.json +1 -1
  126. package/locales/vi/LC_MESSAGES/volto.po +55 -0
  127. package/locales/vi.json +1 -1
  128. package/locales/volto.pot +56 -1
  129. package/locales/zh_CN/LC_MESSAGES/volto.po +55 -0
  130. package/locales/zh_CN.json +1 -1
  131. package/locales/zh_Hant/LC_MESSAGES/volto.po +55 -0
  132. package/locales/zh_Hant.json +1 -1
  133. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +55 -0
  134. package/locales/zh_Hant_HK.json +1 -1
  135. package/news/7308.fix +1 -0
  136. package/news/8084.fix +1 -0
  137. package/package.json +19 -19
  138. package/razzle.config.js +1 -0
  139. package/src/actions/users/users.js +2 -2
  140. package/src/components/manage/Blocks/Block/Order/Item.jsx +18 -10
  141. package/src/components/manage/Blocks/Block/Order/Item.test.jsx +90 -0
  142. package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +7 -0
  143. package/src/components/manage/Controlpanels/ContentTypes.jsx +9 -2
  144. package/src/components/manage/Controlpanels/DatabaseInformation.jsx +9 -0
  145. package/src/components/manage/Controlpanels/ModerateComments.jsx +8 -0
  146. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +3 -0
  147. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +58 -5
  148. package/src/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.jsx +624 -0
  149. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +8 -0
  150. package/src/components/manage/Form/Form.jsx +6 -1
  151. package/src/components/manage/Form/ModalForm.jsx +165 -87
  152. package/src/components/manage/Sidebar/Sidebar.jsx +1 -0
  153. package/src/components/manage/Toast/Toast.jsx +35 -1
  154. package/src/components/manage/Toast/Toast.test.jsx +8 -5
  155. package/src/components/manage/Widgets/DatetimeWidget.jsx +92 -58
  156. package/src/components/manage/Widgets/DatetimeWidget.test.jsx +55 -0
  157. package/src/components/manage/Widgets/FormFieldWrapper.jsx +7 -5
  158. package/src/components/manage/Widgets/TextWidget.jsx +4 -0
  159. package/src/components/manage/Widgets/UrlWidget.jsx +51 -6
  160. package/src/components/theme/Search/Search.jsx +24 -1
  161. package/src/components/theme/Unauthorized/Unauthorized.jsx +30 -22
  162. package/src/components/theme/Unauthorized/Unauthorized.test.jsx +28 -1
  163. package/src/helpers/FormValidation/validators.ts +15 -2
  164. package/theme/themes/default/globals/site.variables +2 -2
  165. package/theme/themes/pastanaga/collections/form.overrides +21 -0
  166. package/theme/themes/pastanaga/elements/button.overrides +30 -3
  167. package/theme/themes/pastanaga/extras/main.less +16 -0
  168. package/theme/themes/pastanaga/globals/site.variables +0 -2
  169. package/types/components/manage/Blocks/Block/Order/Item.test.d.ts +1 -0
  170. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +2 -6
  171. package/types/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.d.ts +1 -0
  172. package/types/components/manage/Controlpanels/index.d.ts +1 -1
  173. package/webpack-plugins/webpack-less-plugin.js +1 -1
@@ -19,6 +19,8 @@ const TextWidget = (props) => {
19
19
  placeholder,
20
20
  isDisabled,
21
21
  focus,
22
+ required,
23
+ error,
22
24
  } = props;
23
25
 
24
26
  const ref = useRef();
@@ -49,6 +51,8 @@ const TextWidget = (props) => {
49
51
  onClick={() => onClick()}
50
52
  minLength={minLength || null}
51
53
  maxLength={maxLength || null}
54
+ aria-required={required ? 'true' : undefined}
55
+ aria-invalid={error?.length > 0 ? 'true' : undefined}
52
56
  />
53
57
  {icon && iconAction && (
54
58
  <button className={`field-${id}-action-button`} onClick={iconAction}>
@@ -14,10 +14,30 @@ import {
14
14
  flattenToAppURL,
15
15
  URLUtils,
16
16
  } from '@plone/volto/helpers/Url/Url';
17
+ import { defineMessages, useIntl } from 'react-intl';
17
18
  import withObjectBrowser from '@plone/volto/components/manage/Sidebar/ObjectBrowser';
18
19
  import clearSVG from '@plone/volto/icons/clear.svg';
19
20
  import navTreeSVG from '@plone/volto/icons/nav.svg';
20
21
 
22
+ const messages = defineMessages({
23
+ urlMissing: {
24
+ id: 'URL is missing',
25
+ defaultMessage: 'URL is missing',
26
+ },
27
+ urlInvalid: {
28
+ id: 'URL is invalid',
29
+ defaultMessage: 'URL is invalid',
30
+ },
31
+ clearUrl: {
32
+ id: 'Clear URL',
33
+ defaultMessage: 'Clear URL',
34
+ },
35
+ openUrlBrowser: {
36
+ id: 'Open URL browser',
37
+ defaultMessage: 'Open URL browser',
38
+ },
39
+ });
40
+
21
41
  /** Widget to edit urls
22
42
  *
23
43
  * This is the default widget used for the `remoteUrl` field. You can also use
@@ -40,9 +60,10 @@ export const UrlWidget = (props) => {
40
60
  maxLength,
41
61
  placeholder,
42
62
  isDisabled,
63
+ required,
43
64
  } = props;
44
65
  const inputId = `field-${id}`;
45
-
66
+ const intl = useIntl();
46
67
  const [value, setValue] = useState(flattenToAppURL(props.value));
47
68
  const [isInvalid, setIsInvalid] = useState(false);
48
69
  /**
@@ -54,6 +75,7 @@ export const UrlWidget = (props) => {
54
75
  const clear = () => {
55
76
  setValue('');
56
77
  onChange(id, undefined);
78
+ setIsInvalid(false);
57
79
  };
58
80
 
59
81
  const onChangeValue = (_value) => {
@@ -83,6 +105,14 @@ export const UrlWidget = (props) => {
83
105
  onChange(id, newValue === '' ? undefined : newValue);
84
106
  };
85
107
 
108
+ // A11y: if the field is required and the user leaves it empty, we mark it as missing
109
+ const handleBlur = ({ target }) => {
110
+ if (required && (!target.value || target.value === '')) {
111
+ setIsInvalid(true);
112
+ }
113
+ onBlur(id, target.value === '' ? undefined : target.value);
114
+ };
115
+
86
116
  return (
87
117
  <FormFieldWrapper {...props} className="url wide">
88
118
  <div className="wrapper">
@@ -90,24 +120,38 @@ export const UrlWidget = (props) => {
90
120
  id={inputId}
91
121
  name={id}
92
122
  type="url"
123
+ required={required}
124
+ aria-required={required}
125
+ aria-invalid={isInvalid}
126
+ aria-errormessage={isInvalid ? `${inputId}-error` : undefined}
93
127
  value={value || ''}
94
128
  disabled={isDisabled}
95
129
  placeholder={placeholder}
96
130
  onChange={({ target }) => onChangeValue(target.value)}
97
- onBlur={({ target }) =>
98
- onBlur(id, target.value === '' ? undefined : target.value)
99
- }
131
+ onBlur={handleBlur}
100
132
  onClick={() => onClick()}
101
133
  minLength={minLength || null}
102
134
  maxLength={maxLength || null}
103
135
  error={isInvalid}
104
136
  />
137
+ {isInvalid && (
138
+ <span
139
+ id={`${inputId}-error`}
140
+ role="alert"
141
+ className="visually-hidden-volto"
142
+ >
143
+ {value?.length > 0
144
+ ? intl.formatMessage(messages.urlInvalid)
145
+ : intl.formatMessage(messages.urlMissing)}
146
+ </span>
147
+ )}
105
148
  {value?.length > 0 ? (
106
149
  <Button.Group>
107
150
  <Button
151
+ type="button"
108
152
  basic
109
153
  className="cancel"
110
- aria-label="clearUrlBrowser"
154
+ aria-label={intl.formatMessage(messages.clearUrl)}
111
155
  onClick={(e) => {
112
156
  e.preventDefault();
113
157
  e.stopPropagation();
@@ -120,9 +164,10 @@ export const UrlWidget = (props) => {
120
164
  ) : (
121
165
  <Button.Group>
122
166
  <Button
167
+ type="button"
123
168
  basic
124
169
  icon
125
- aria-label="openUrlBrowser"
170
+ aria-label={intl.formatMessage(messages.openUrlBrowser)}
126
171
  onClick={(e) => {
127
172
  e.preventDefault();
128
173
  e.stopPropagation();
@@ -85,6 +85,7 @@ class Search extends Component {
85
85
  componentDidMount() {
86
86
  this.doSearch();
87
87
  this.setState({ isClient: true });
88
+ this.focusResults();
88
89
  }
89
90
 
90
91
  /**
@@ -97,6 +98,22 @@ class Search extends Component {
97
98
  if (this.props.location.search !== nextProps.location.search) {
98
99
  this.doSearch();
99
100
  }
101
+
102
+ if (
103
+ JSON.stringify(this.props.search) !== JSON.stringify(nextProps.search)
104
+ ) {
105
+ //on opening results page, move focus on results
106
+ this.focusResults();
107
+ }
108
+ };
109
+
110
+ focusResults = () => {
111
+ //on opening results page, move focus on results
112
+ setTimeout(function () {
113
+ if (document.querySelector('#page-search #search-results')) {
114
+ document.querySelector('#page-search #search-results').focus();
115
+ }
116
+ }, 100);
100
117
  };
101
118
 
102
119
  /**
@@ -162,7 +179,13 @@ class Search extends Component {
162
179
  return (
163
180
  <Container id="page-search">
164
181
  <Helmet title={this.props.intl.formatMessage(messages.Search)} />
165
- <div className="container">
182
+ <div
183
+ className="container"
184
+ role="region"
185
+ aria-live="polite"
186
+ id="search-results"
187
+ tabIndex={-1}
188
+ >
166
189
  <article id="content">
167
190
  <header>
168
191
  <h1 className="documentFirstHeading">
@@ -8,6 +8,7 @@ import { getBaseUrl } from '@plone/volto/helpers/Url/Url';
8
8
  import BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
9
9
 
10
10
  const Unauthorized = () => {
11
+ const token = useSelector((state) => state.userSession.token);
11
12
  const error_message = useSelector((state) => state.apierror?.message);
12
13
  let location = useLocation();
13
14
 
@@ -19,28 +20,35 @@ const Unauthorized = () => {
19
20
  </h1>
20
21
  <h3>{error_message}</h3>
21
22
  <p className="description">
22
- <FormattedMessage
23
- id="You are trying to access a protected resource, please {login} first."
24
- defaultMessage="You are trying to access a protected resource, please {login} first."
25
- values={{
26
- login: (
27
- <Link
28
- to={{
29
- pathname: `${getBaseUrl(location.pathname)}/login`,
30
- state: {
31
- // This is needed to cover the use case of being logged in in
32
- // another backend (eg. in development), having a token for
33
- // localhost and try to use it, the login route has to know that
34
- // it's the same as it comes from a logout
35
- isLogout: true,
36
- },
37
- }}
38
- >
39
- <FormattedMessage id="log in" defaultMessage="log in" />
40
- </Link>
41
- ),
42
- }}
43
- />
23
+ {token ? (
24
+ <FormattedMessage
25
+ id="You are trying to access a protected resource."
26
+ defaultMessage="You are trying to access a protected resource."
27
+ />
28
+ ) : (
29
+ <FormattedMessage
30
+ id="You are trying to access a protected resource, please {login} first."
31
+ defaultMessage="You are trying to access a protected resource, please {login} first."
32
+ values={{
33
+ login: (
34
+ <Link
35
+ to={{
36
+ pathname: `${getBaseUrl(location.pathname)}/login`,
37
+ state: {
38
+ // This is needed to cover the use case of being logged in in
39
+ // another backend (eg. in development), having a token for
40
+ // localhost and try to use it, the login route has to know that
41
+ // it's the same as it comes from a logout
42
+ isLogout: true,
43
+ },
44
+ }}
45
+ >
46
+ <FormattedMessage id="log in" defaultMessage="log in" />
47
+ </Link>
48
+ ),
49
+ }}
50
+ />
51
+ )}
44
52
  </p>
45
53
  <p>
46
54
  <FormattedMessage
@@ -9,8 +9,35 @@ import Unauthorized from './Unauthorized';
9
9
  const mockStore = configureStore();
10
10
 
11
11
  describe('Unauthorized', () => {
12
- it('renders a not found component', () => {
12
+ it('renders an unauthorized component', () => {
13
13
  const store = mockStore({
14
+ userSession: {
15
+ token: null,
16
+ },
17
+ intl: {
18
+ locale: 'en',
19
+ messages: {},
20
+ },
21
+ apierror: {
22
+ message: 'You are not authorized to access this resource',
23
+ },
24
+ });
25
+ const component = renderer.create(
26
+ <Provider store={store}>
27
+ <MemoryRouter>
28
+ <Unauthorized />
29
+ </MemoryRouter>
30
+ </Provider>,
31
+ );
32
+ const json = component.toJSON();
33
+ expect(json).toMatchSnapshot();
34
+ });
35
+
36
+ it('renders an unauthorized component for authenticated user', () => {
37
+ const store = mockStore({
38
+ userSession: {
39
+ token: '1234',
40
+ },
14
41
  intl: {
15
42
  locale: 'en',
16
43
  messages: {},
@@ -153,6 +153,15 @@ export const hasUniqueItemsValidator = ({
153
153
  return !isValid ? formatMessage(messages.uniqueItems) : null;
154
154
  };
155
155
 
156
+ const formatDateValue = (isoString: string) => {
157
+ const date = new Date(isoString);
158
+ if (isNaN(date.getTime())) return isoString;
159
+ return new Intl.DateTimeFormat(undefined, {
160
+ dateStyle: 'medium',
161
+ timeStyle: 'short',
162
+ }).format(date);
163
+ };
164
+
156
165
  export const startEventDateRangeValidator = ({
157
166
  value,
158
167
  field,
@@ -163,7 +172,9 @@ export const startEventDateRangeValidator = ({
163
172
  value && formData.end && new Date(value) < new Date(formData.end);
164
173
  return !isValid
165
174
  ? formatMessage(messages.startEventRange, {
166
- endDateValueOrEndFieldName: formData.end || 'end',
175
+ endDateValueOrEndFieldName: formData.end
176
+ ? formatDateValue(formData.end)
177
+ : 'end',
167
178
  })
168
179
  : null;
169
180
  };
@@ -178,7 +189,9 @@ export const endEventDateRangeValidator = ({
178
189
  value && formData.start && new Date(value) > new Date(formData.start);
179
190
  return !isValid
180
191
  ? formatMessage(messages.endEventRange, {
181
- startDateValueOrStartFieldName: formData.start || 'start',
192
+ startDateValueOrStartFieldName: formData.start
193
+ ? formatDateValue(formData.start)
194
+ : 'start',
182
195
  })
183
196
  : null;
184
197
  };
@@ -82,8 +82,8 @@
82
82
 
83
83
  /* Input Text Color */
84
84
  @inputColor: @textColor;
85
- @inputPlaceholderColor: lighten(@inputColor, 75);
86
- @inputPlaceholderFocusColor: lighten(@inputColor, 45);
85
+ @inputPlaceholderColor: lighten(@inputColor, 35);
86
+ @inputPlaceholderFocusColor: lighten(@inputColor, 65);
87
87
 
88
88
  /* Line Height Default For Inputs in Browser (Descenders are 17px at 14px base em) */
89
89
  @inputLineHeight: unit((17 / 14), em);
@@ -31,6 +31,27 @@
31
31
  line-height: initial;
32
32
  }
33
33
 
34
+ // Restore visible focus for keyboard navigation — overrides Semantic UI's `outline: none` on form inputs
35
+ .ui.form input:not([type]),
36
+ .ui.form input[type='date'],
37
+ .ui.form input[type='datetime-local'],
38
+ .ui.form input[type='email'],
39
+ .ui.form input[type='number'],
40
+ .ui.form input[type='password'],
41
+ .ui.form input[type='search'],
42
+ .ui.form input[type='tel'],
43
+ .ui.form input[type='time'],
44
+ .ui.form input[type='text'],
45
+ .ui.form input[type='file'],
46
+ .ui.form input[type='url'],
47
+ .ui.form textarea {
48
+ padding-left: 5px;
49
+
50
+ &:focus-visible {
51
+ outline: revert;
52
+ }
53
+ }
54
+
34
55
  .ui.form .ui.input input:not([type]),
35
56
  .ui.form .ui.input input[type='date'],
36
57
  .ui.form .ui.input input[type='datetime-local'],
@@ -27,7 +27,8 @@
27
27
  }
28
28
 
29
29
  #main,
30
- .slate-inline-toolbar.slate-toolbar {
30
+ .slate-inline-toolbar.slate-toolbar,
31
+ .contenttype-plone-site .ui.page.modals {
31
32
  .ui.basic.buttons .button,
32
33
  .ui.basic.button {
33
34
  -webkit-box-shadow: 0px 0px 0px @basicBorderSize transparent inset !important;
@@ -42,11 +43,16 @@
42
43
  cursor: pointer;
43
44
  text-align: initial;
44
45
 
45
- &:focus {
46
+ &:focus:not(:focus-visible) {
46
47
  outline: none;
47
48
  }
48
49
  }
49
50
 
51
+ .ui.basic.buttons .button:focus-visible,
52
+ .ui.basic.button:focus-visible {
53
+ outline: revert;
54
+ }
55
+
50
56
  .ui.basic.primary.button,
51
57
  .ui.basic.secondary.button {
52
58
  box-shadow: none !important;
@@ -69,7 +75,7 @@
69
75
  cursor: pointer;
70
76
  text-align: initial;
71
77
 
72
- &:focus {
78
+ &:focus:not(:focus-visible) {
73
79
  outline: none;
74
80
  }
75
81
  }
@@ -85,3 +91,24 @@
85
91
  margin: 0;
86
92
  }
87
93
  }
94
+
95
+ .modals {
96
+ .modal {
97
+ .actions {
98
+ display: flex;
99
+ justify-content: flex-end;
100
+ gap: 0.5em;
101
+
102
+ .ui.basic.button {
103
+ display: flex;
104
+ justify-content: center;
105
+ padding: 0.3em;
106
+ margin: 0;
107
+
108
+ svg {
109
+ margin: 0;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
@@ -360,6 +360,7 @@ button {
360
360
  margin-left: 8px;
361
361
 
362
362
  h4 {
363
+ display: inline;
363
364
  margin-bottom: 0;
364
365
  font-weight: @bold;
365
366
  }
@@ -658,6 +659,21 @@ img.responsive {
658
659
  margin-top: 20px;
659
660
  }
660
661
 
662
+ // Accessibility
663
+ // This class is used to hide elements visually but keep them accessible for screen readers and assistive technologies.
664
+ // to not interfere with other 'visually-hidden' classes from other CSS frameworks (e.g. Semantic UI or TailwindCSS), we use a specific class name for Volto 18 (only).
665
+ .visually-hidden-volto {
666
+ position: absolute !important;
667
+ overflow: hidden !important;
668
+ width: 1px !important;
669
+ height: 1px !important;
670
+ padding: 0 !important;
671
+ border: 0 !important;
672
+ margin: -1px !important;
673
+ clip-path: inset(50%) !important;
674
+ white-space: nowrap !important;
675
+ }
676
+
661
677
  // Deprecated as per https://github.com/plone/volto/issues/1265
662
678
  // @import 'utils';
663
679
  @import (multiple) '../extras/fonts';
@@ -48,8 +48,6 @@
48
48
  /* This adjusts the default form input across all elements */
49
49
  @inputHorizontalPadding : 0;
50
50
 
51
- /* Input Text Color */
52
- @inputPlaceholderColor: #B8C6C8;
53
51
 
54
52
 
55
53
  /*-------------------
@@ -1,6 +1,2 @@
1
- export default UsersControlpanel;
2
- /**
3
- * UsersControlpanel functional component.
4
- * @function UsersControlpanel
5
- */
6
- declare function UsersControlpanel(): import("react/jsx-runtime").JSX.Element;
1
+ declare const _default: any;
2
+ export default _default;
@@ -4,7 +4,7 @@ export declare const RulesControlpanel: import("@loadable/component").LoadableCl
4
4
  export declare const AddRuleControlpanel: import("@loadable/component").LoadableClassComponent<any>;
5
5
  export declare const EditRuleControlpanel: import("@loadable/component").LoadableClassComponent<any>;
6
6
  export declare const ConfigureRuleControlpanel: import("@loadable/component").LoadableClassComponent<any>;
7
- export declare const UsersControlpanel: import("@loadable/component").LoadableComponent<unknown>;
7
+ export declare const UsersControlpanel: import("@loadable/component").LoadableClassComponent<any>;
8
8
  export declare const RenderUsers: import("@loadable/component").LoadableComponent<any>;
9
9
  export declare const UserGroupMembershipControlPanel: import("@loadable/component").LoadableComponent<unknown>;
10
10
  export declare const GroupsControlpanel: import("@loadable/component").LoadableClassComponent<any>;
@@ -143,7 +143,7 @@ module.exports = (userOptions = {}) => ({
143
143
  /packages\/volto\/theme/,
144
144
  /plone\.volto\/theme/,
145
145
  /node_modules\/semantic-ui-less/,
146
- ...Object.values(registry.getResolveAliases()),
146
+ ...Object.values(registry.packages).map((p) => p.modulePath),
147
147
  ],
148
148
  use: isServer
149
149
  ? [