@plone/volto 19.0.0-alpha.11 → 19.0.0-alpha.12

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 (58) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/locales/ca/LC_MESSAGES/volto.po +10 -0
  3. package/locales/de/LC_MESSAGES/volto.po +10 -0
  4. package/locales/en/LC_MESSAGES/volto.po +10 -0
  5. package/locales/es/LC_MESSAGES/volto.po +10 -0
  6. package/locales/eu/LC_MESSAGES/volto.po +10 -0
  7. package/locales/fi/LC_MESSAGES/volto.po +10 -0
  8. package/locales/fr/LC_MESSAGES/volto.po +10 -0
  9. package/locales/hi/LC_MESSAGES/volto.po +10 -0
  10. package/locales/it/LC_MESSAGES/volto.po +10 -0
  11. package/locales/ja/LC_MESSAGES/volto.po +10 -0
  12. package/locales/nl/LC_MESSAGES/volto.po +10 -0
  13. package/locales/pt/LC_MESSAGES/volto.po +10 -0
  14. package/locales/pt_BR/LC_MESSAGES/volto.po +10 -0
  15. package/locales/ro/LC_MESSAGES/volto.po +10 -0
  16. package/locales/ru/LC_MESSAGES/volto.po +10 -0
  17. package/locales/volto.pot +11 -1
  18. package/locales/zh_CN/LC_MESSAGES/volto.po +10 -0
  19. package/package.json +5 -4
  20. package/src/components/manage/Controlpanels/Relations/Relations.jsx +1 -1
  21. package/src/components/manage/Widgets/AlignWidget.stories.jsx +9 -0
  22. package/src/components/manage/Widgets/AlignWidget.test.tsx +95 -0
  23. package/src/components/manage/Widgets/{AlignWidget.jsx → AlignWidget.tsx} +23 -7
  24. package/src/components/manage/Widgets/BlockAlignment.stories.tsx +104 -0
  25. package/src/components/manage/Widgets/BlockAlignment.test.tsx +104 -0
  26. package/src/components/manage/Widgets/BlockAlignment.tsx +88 -0
  27. package/src/components/manage/Widgets/BlockWidth.stories.tsx +69 -0
  28. package/src/components/manage/Widgets/BlockWidth.test.tsx +62 -0
  29. package/src/components/manage/Widgets/BlockWidth.tsx +101 -0
  30. package/src/components/manage/Widgets/ButtonsWidget.stories.jsx +61 -0
  31. package/src/components/manage/Widgets/ButtonsWidget.test.tsx +138 -0
  32. package/src/components/manage/Widgets/ButtonsWidget.tsx +176 -0
  33. package/src/components/manage/Widgets/Size.stories.tsx +69 -0
  34. package/src/components/manage/Widgets/Size.test.tsx +59 -0
  35. package/src/components/manage/Widgets/Size.tsx +78 -0
  36. package/src/components/manage/Widgets/index.tsx +21 -0
  37. package/src/components/theme/App/App.jsx +2 -0
  38. package/src/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.tsx +7 -0
  39. package/src/config/Widgets.jsx +7 -0
  40. package/src/config/slots.js +19 -0
  41. package/theme/themes/pastanaga/extras/widgets.less +45 -0
  42. package/types/components/manage/Widgets/AlignWidget.d.ts +8 -10
  43. package/types/components/manage/Widgets/AlignWidget.stories.d.ts +1 -0
  44. package/types/components/manage/Widgets/BlockAlignment.d.ts +7 -0
  45. package/types/components/manage/Widgets/BlockAlignment.stories.d.ts +8 -0
  46. package/types/components/manage/Widgets/BlockWidth.d.ts +7 -0
  47. package/types/components/manage/Widgets/BlockWidth.stories.d.ts +6 -0
  48. package/types/components/manage/Widgets/ButtonsWidget.d.ts +48 -1
  49. package/types/components/manage/Widgets/ButtonsWidget.stories.d.ts +3 -0
  50. package/types/components/manage/Widgets/Size.d.ts +7 -0
  51. package/types/components/manage/Widgets/Size.stories.d.ts +6 -0
  52. package/types/components/manage/Widgets/index.d.ts +7 -2
  53. package/types/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS.d.ts +3 -0
  54. package/types/config/Widgets.d.ts +6 -0
  55. package/types/config/slots.d.ts +7 -0
  56. package/src/components/manage/Widgets/AlignWidget.test.jsx +0 -59
  57. package/src/components/manage/Widgets/ButtonsWidget.jsx +0 -41
  58. package/src/components/manage/Widgets/ButtonsWidget.test.jsx +0 -70
@@ -0,0 +1,78 @@
1
+ import { defineMessages, useIntl } from 'react-intl';
2
+ import ButtonsWidget, {
3
+ type ActionInfo,
4
+ type ButtonsWidgetProps,
5
+ } from './ButtonsWidget';
6
+ import type { IntlShape } from 'react-intl';
7
+ import type { StyleDefinition } from '@plone/types';
8
+
9
+ const messages = defineMessages({
10
+ s: {
11
+ id: 'Small',
12
+ defaultMessage: 'Small',
13
+ },
14
+ m: {
15
+ id: 'Medium',
16
+ defaultMessage: 'Medium',
17
+ },
18
+ l: {
19
+ id: 'Large',
20
+ defaultMessage: 'Large',
21
+ },
22
+ });
23
+
24
+ export const defaultActionsInfo = ({
25
+ intl,
26
+ }: {
27
+ intl: IntlShape;
28
+ }): Record<string, ActionInfo> => ({
29
+ s: ['S', intl.formatMessage(messages.s)],
30
+ m: ['M', intl.formatMessage(messages.m)],
31
+ l: ['L', intl.formatMessage(messages.l)],
32
+ });
33
+
34
+ const DEFAULT_ACTIONS: StyleDefinition[] = [
35
+ {
36
+ name: 's',
37
+ label: 'Small',
38
+ style: undefined,
39
+ },
40
+ {
41
+ name: 'm',
42
+ label: 'Medium',
43
+ style: undefined,
44
+ },
45
+ {
46
+ name: 'l',
47
+ label: 'Large',
48
+ style: undefined,
49
+ },
50
+ ];
51
+
52
+ const SizeWidget = (props: ButtonsWidgetProps) => {
53
+ const intl = useIntl();
54
+
55
+ const { actions = DEFAULT_ACTIONS, actionsInfoMap, filterActions } = props;
56
+ const filteredActions =
57
+ filterActions && filterActions.length > 0
58
+ ? actions.filter((action) => {
59
+ const actionName = typeof action === 'string' ? action : action.name;
60
+ return filterActions.includes(actionName);
61
+ })
62
+ : actions;
63
+
64
+ const actionsInfo = {
65
+ ...defaultActionsInfo({ intl }),
66
+ ...actionsInfoMap,
67
+ };
68
+
69
+ return (
70
+ <ButtonsWidget
71
+ {...props}
72
+ actions={filteredActions}
73
+ actionsInfoMap={actionsInfo}
74
+ />
75
+ );
76
+ };
77
+
78
+ export default SizeWidget;
@@ -265,3 +265,24 @@ export const FormFieldWrapper = loadable(
265
265
  /* webpackChunkName: "Widgets" */ '@plone/volto/components/manage/Widgets/FormFieldWrapper'
266
266
  ),
267
267
  );
268
+
269
+ export const Size = loadable(
270
+ () =>
271
+ import(
272
+ /* webpackChunkName: "Widgets" */ '@plone/volto/components/manage/Widgets/Size'
273
+ ),
274
+ );
275
+
276
+ export const BlockAlignment = loadable(
277
+ () =>
278
+ import(
279
+ /* webpackChunkName: "Widgets" */ '@plone/volto/components/manage/Widgets/BlockAlignment'
280
+ ),
281
+ );
282
+
283
+ export const BlockWidth = loadable(
284
+ () =>
285
+ import(
286
+ /* webpackChunkName: "Widgets" */ '@plone/volto/components/manage/Widgets/BlockWidth'
287
+ ),
288
+ );
@@ -45,6 +45,7 @@ import MultilingualRedirector from '@plone/volto/components/theme/MultilingualRe
45
45
  import WorkingCopyToastsFactory from '@plone/volto/components/manage/WorkingCopyToastsFactory/WorkingCopyToastsFactory';
46
46
  import LockingToastsFactory from '@plone/volto/components/manage/LockingToastsFactory/LockingToastsFactory';
47
47
  import RouteAnnouncer from '@plone/volto/components/theme/RouteAnnouncer/RouteAnnouncer';
48
+ import SlotRenderer from '@plone/volto/components/theme/SlotRenderer/SlotRenderer';
48
49
 
49
50
  /**
50
51
  * @export
@@ -159,6 +160,7 @@ export class App extends Component {
159
160
  'public-ui': !isCmsUI,
160
161
  })}
161
162
  />
163
+ <SlotRenderer name="aboveApp" content={this.props.content} />
162
164
  <SkipLinks />
163
165
  <Header pathname={path} />
164
166
  <Breadcrumbs pathname={path} />
@@ -0,0 +1,7 @@
1
+ import '@plone/components/dist/basic.css';
2
+
3
+ const InjectPloneComponentsCSS = () => {
4
+ return null;
5
+ };
6
+
7
+ export default InjectPloneComponentsCSS;
@@ -35,6 +35,9 @@ import {
35
35
  RecurrenceWidget,
36
36
  RadioGroupWidget,
37
37
  CheckboxGroupWidget,
38
+ Size,
39
+ BlockAlignment,
40
+ BlockWidth,
38
41
  } from '@plone/volto/components/manage/Widgets';
39
42
 
40
43
  import ArrayViewWidget from '@plone/volto/components/theme/Widgets/ArrayWidget';
@@ -102,6 +105,10 @@ export const widgetMapping = {
102
105
  hidden: HiddenWidget,
103
106
  radio_group: RadioGroupWidget,
104
107
  checkbox_group: CheckboxGroupWidget,
108
+ // SemanticUI Free widgets
109
+ blockAlignment: BlockAlignment,
110
+ blockWidth: BlockWidth,
111
+ size: Size,
105
112
  },
106
113
  vocabulary: {
107
114
  'plone.app.vocabularies.Catalog': ObjectBrowserWidget,
@@ -1,7 +1,26 @@
1
+ import loadable from '@loadable/component';
1
2
  import RelatedItems from '@plone/volto/components/theme/RelatedItems/RelatedItems';
2
3
  import Tags from '@plone/volto/components/theme/Tags/Tags';
4
+ import { isCmsUi } from '@plone/volto/helpers/Url/Url';
5
+
6
+ const InjectPloneComponentsCSS = loadable(
7
+ () =>
8
+ import(
9
+ '@plone/volto/components/theme/InjectPloneComponentsCSS/InjectPloneComponentsCSS'
10
+ ),
11
+ { fallback: null },
12
+ );
13
+
14
+ const onlyCMSUI = ({ location }) => isCmsUi(location?.pathname);
3
15
 
4
16
  const slots = {
17
+ aboveApp: [
18
+ {
19
+ name: 'plone-components-css',
20
+ component: InjectPloneComponentsCSS,
21
+ predicates: [onlyCMSUI],
22
+ },
23
+ ],
5
24
  belowContent: [
6
25
  {
7
26
  name: 'tags',
@@ -292,3 +292,48 @@ body.babel-view .field.language-independent-field {
292
292
  margin-left: 8px;
293
293
  }
294
294
  }
295
+
296
+ // ButtonsWidget and friends 2025
297
+ :root {
298
+ --border-color-hover: var(--quanta-sapphire);
299
+ --border-color-pressed: var(--quanta-sapphire);
300
+ --border-color-disabled: #d4d4d5;
301
+ --text-color-disabled: #a8a8a8;
302
+ }
303
+
304
+ .field.widget {
305
+ .buttons-widget {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 4px;
309
+
310
+ .buttons-widget-option {
311
+ padding: 5px;
312
+ border-radius: 3px;
313
+ aspect-ratio: 1/1;
314
+ font-size: 1em;
315
+ line-height: initial;
316
+
317
+ &[data-hovered='true'] {
318
+ box-shadow: inset 0 0 0 1px var(--border-color-hover, #2996da);
319
+ }
320
+
321
+ &[data-selected='true'] {
322
+ box-shadow: inset 0 0 0 1px var(--border-color-pressed, #2996da);
323
+ }
324
+
325
+ svg.icon {
326
+ margin: 0 !important;
327
+ opacity: 0.9;
328
+ vertical-align: top;
329
+ }
330
+ }
331
+ }
332
+ }
333
+
334
+ .buttons-widget-option {
335
+ &[data-disabled='true'] {
336
+ border-color: var(--border-color-disabled);
337
+ color: var(--text-color-disabled);
338
+ }
339
+ }
@@ -1,12 +1,10 @@
1
- export function defaultActionsInfo({ intl }: {
2
- intl: any;
3
- }): {
4
- left: any[];
5
- right: any[];
6
- center: any[];
7
- narrow: any[];
8
- wide: any[];
9
- full: any[];
1
+ import { type ActionInfo, type ButtonsWidgetProps } from './ButtonsWidget';
2
+ import type { IntlShape } from 'react-intl';
3
+ export declare const defaultActionsInfo: ({ intl, }: {
4
+ intl: IntlShape;
5
+ }) => Record<string, ActionInfo>;
6
+ type AlignWidgetProps = ButtonsWidgetProps & {
7
+ defaultAction?: string;
10
8
  };
9
+ declare const AlignWidget: (props: AlignWidgetProps) => import("react/jsx-runtime").JSX.Element;
11
10
  export default AlignWidget;
12
- declare function AlignWidget(props: any): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  export const Align: any;
2
+ export const AlignDefaultLeft: any;
2
3
  declare namespace _default {
3
4
  export let title: string;
4
5
  export { AlignWidget as component };
@@ -0,0 +1,7 @@
1
+ import { type ActionInfo, type ButtonsWidgetProps } from './ButtonsWidget';
2
+ import type { IntlShape } from 'react-intl';
3
+ export declare const defaultActionsInfo: ({ intl, }: {
4
+ intl: IntlShape;
5
+ }) => Record<string, ActionInfo>;
6
+ declare const BlockAlignmentWidget: (props: ButtonsWidgetProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default BlockAlignmentWidget;
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import BlockAlignment from './BlockAlignment';
3
+ declare const meta: Meta<typeof BlockAlignment>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof BlockAlignment>;
6
+ export declare const DefaultAlignment: Story;
7
+ export declare const CustomActions: Story;
8
+ export declare const FilteredActions: Story;
@@ -0,0 +1,7 @@
1
+ import type { IntlShape } from 'react-intl';
2
+ import { type ActionInfo, type ButtonsWidgetProps } from './ButtonsWidget';
3
+ export declare const defaultActionsInfo: ({ intl, }: {
4
+ intl: IntlShape;
5
+ }) => Record<string, ActionInfo>;
6
+ declare const BlockWidthWidget: (props: ButtonsWidgetProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default BlockWidthWidget;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import BlockWidth from './BlockWidth';
3
+ declare const meta: Meta<typeof BlockWidth>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof BlockWidth>;
6
+ export declare const DefaultWidth: Story;
@@ -1,2 +1,49 @@
1
+ import React from 'react';
2
+ import type { StyleDefinition } from '@plone/types';
3
+ /**
4
+ * A tuple that has an icon in the first element and a i18n string in the second.
5
+ */
6
+ export type ActionInfo = [React.ReactElement<any>, string] | [string, string];
7
+ type ActionValue = string | Record<`--${string}`, string>;
8
+ export type ButtonsWidgetProps = {
9
+ /**
10
+ * Unique identifier for the widget.
11
+ */
12
+ id: string;
13
+ /**
14
+ * Callback function to handle changes.
15
+ */
16
+ onChange: (id: string, value: ActionValue) => void;
17
+ /**
18
+ * List of actions available for the widget.
19
+ */
20
+ actions?: Array<StyleDefinition | string>;
21
+ /**
22
+ * Map containing additional the information (icon and i18n string) for each action.
23
+ */
24
+ actionsInfoMap?: Record<string, ActionInfo>;
25
+ /**
26
+ * List of actions to be filtered out. In case that we don't want the default ones
27
+ * we can filter them out.
28
+ */
29
+ filterActions?: string[];
30
+ /**
31
+ * Current value of the widget.
32
+ */
33
+ value?: ActionValue;
34
+ /**
35
+ * Default value of the widget.
36
+ */
37
+ default?: ActionValue;
38
+ /**
39
+ * Indicates if the widget is disabled.
40
+ */
41
+ disabled?: boolean;
42
+ /**
43
+ * Indicates if the widget is disabled (alternative flag for compatibility reasons).
44
+ */
45
+ isDisabled?: boolean;
46
+ [key: string]: any;
47
+ };
48
+ declare const ButtonsWidget: (props: ButtonsWidgetProps) => import("react/jsx-runtime").JSX.Element;
1
49
  export default ButtonsWidget;
2
- declare function ButtonsWidget(props: any): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,7 @@
1
1
  export const Buttons: any;
2
+ export const ButtonsWithDefaultValue: any;
3
+ export const ButtonsWithStyleDefinitions: any;
4
+ export const ButtonsFiltered: any;
2
5
  declare namespace _default {
3
6
  export let title: string;
4
7
  export { ButtonsWidget as component };
@@ -0,0 +1,7 @@
1
+ import { type ActionInfo, type ButtonsWidgetProps } from './ButtonsWidget';
2
+ import type { IntlShape } from 'react-intl';
3
+ export declare const defaultActionsInfo: ({ intl, }: {
4
+ intl: IntlShape;
5
+ }) => Record<string, ActionInfo>;
6
+ declare const SizeWidget: (props: ButtonsWidgetProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default SizeWidget;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import Size from './Size';
3
+ declare const meta: Meta<typeof Size>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Size>;
6
+ export declare const DefaultSize: Story;
@@ -1,5 +1,7 @@
1
- export declare const AlignWidget: import("@loadable/component").LoadableComponent<any>;
2
- export declare const ButtonsWidget: import("@loadable/component").LoadableComponent<any>;
1
+ export declare const AlignWidget: import("@loadable/component").LoadableComponent<import("@plone/volto/components/manage/Widgets/ButtonsWidget").ButtonsWidgetProps & {
2
+ defaultAction?: string;
3
+ }>;
4
+ export declare const ButtonsWidget: import("@loadable/component").LoadableComponent<import("@plone/volto/components/manage/Widgets/ButtonsWidget").ButtonsWidgetProps>;
3
5
  export declare const ArrayWidget: import("@loadable/component").LoadableClassComponent<any>;
4
6
  export declare const CheckboxWidget: import("@loadable/component").LoadableComponent<import("react-intl").WithIntlProps<any>>;
5
7
  export declare const CheckboxGroupWidget: import("@loadable/component").LoadableClassComponent<any>;
@@ -122,3 +124,6 @@ export declare const DatetimeWidget: import("@loadable/component").LoadableClass
122
124
  export declare const TimeWidget: import("@loadable/component").LoadableClassComponent<any>;
123
125
  export declare const RecurrenceWidget: import("@loadable/component").LoadableClassComponent<any>;
124
126
  export declare const FormFieldWrapper: import("@loadable/component").LoadableComponent<import("react-intl").WithIntlProps<any>>;
127
+ export declare const Size: import("@loadable/component").LoadableComponent<import("@plone/volto/components/manage/Widgets/ButtonsWidget").ButtonsWidgetProps>;
128
+ export declare const BlockAlignment: import("@loadable/component").LoadableComponent<import("@plone/volto/components/manage/Widgets/ButtonsWidget").ButtonsWidgetProps>;
129
+ export declare const BlockWidth: import("@loadable/component").LoadableComponent<import("@plone/volto/components/manage/Widgets/ButtonsWidget").ButtonsWidgetProps>;
@@ -0,0 +1,3 @@
1
+ import '@plone/components/dist/basic.css';
2
+ declare const InjectPloneComponentsCSS: () => any;
3
+ export default InjectPloneComponentsCSS;
@@ -41,6 +41,9 @@ export namespace widgetMapping {
41
41
  export { HiddenWidget as hidden };
42
42
  export { RadioGroupWidget as radio_group };
43
43
  export { CheckboxGroupWidget as checkbox_group };
44
+ export { BlockAlignment as blockAlignment };
45
+ export { BlockWidth as blockWidth };
46
+ export { Size as size };
44
47
  }
45
48
  export let vocabulary: {
46
49
  'plone.app.vocabularies.Catalog': import("@loadable/component").LoadableComponent<Omit<import("react-intl").WithIntlProps<import("react-intl").WrappedComponentProps<string>>, "ref"> & import("react").RefAttributes<import("react").ComponentType<import("react-intl").WrappedComponentProps<string>>>>;
@@ -141,6 +144,9 @@ import { StaticTextWidget } from '@plone/volto/components/manage/Widgets';
141
144
  import { HiddenWidget } from '@plone/volto/components/manage/Widgets';
142
145
  import { RadioGroupWidget } from '@plone/volto/components/manage/Widgets';
143
146
  import { CheckboxGroupWidget } from '@plone/volto/components/manage/Widgets';
147
+ import { BlockAlignment } from '@plone/volto/components/manage/Widgets';
148
+ import { BlockWidth } from '@plone/volto/components/manage/Widgets';
149
+ import { Size } from '@plone/volto/components/manage/Widgets';
144
150
  import { CheckboxWidget } from '@plone/volto/components/manage/Widgets';
145
151
  import { NumberWidget } from '@plone/volto/components/manage/Widgets';
146
152
  import { getWidgetView } from '@plone/volto/helpers/Widget/widget';
@@ -1,5 +1,12 @@
1
1
  export default slots;
2
2
  declare namespace slots {
3
+ let aboveApp: {
4
+ name: string;
5
+ component: import("@loadable/component").LoadableComponent<any>;
6
+ predicates: (({ location }: {
7
+ location: any;
8
+ }) => boolean)[];
9
+ }[];
3
10
  let belowContent: ({
4
11
  name: string;
5
12
  component: {
@@ -1,59 +0,0 @@
1
- import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import configureStore from 'redux-mock-store';
4
- import { Provider } from 'react-intl-redux';
5
- import imageFullSVG from '@plone/volto/icons/image-full.svg';
6
-
7
- import AlignWidget from './AlignWidget';
8
-
9
- const mockStore = configureStore();
10
-
11
- describe('renders an align widget component', () => {
12
- it('basic', () => {
13
- const store = mockStore({
14
- intl: {
15
- locale: 'en',
16
- messages: {},
17
- },
18
- });
19
-
20
- const { asFragment } = render(
21
- <Provider store={store}>
22
- <AlignWidget
23
- id="align"
24
- title="Alignment"
25
- fieldSet="default"
26
- onChange={() => {}}
27
- />
28
- </Provider>,
29
- );
30
-
31
- expect(asFragment()).toMatchSnapshot();
32
- });
33
-
34
- it('extended with actions and actionsInfoMap props', () => {
35
- const store = mockStore({
36
- intl: {
37
- locale: 'en',
38
- messages: {},
39
- },
40
- });
41
-
42
- const { asFragment } = render(
43
- <Provider store={store}>
44
- <AlignWidget
45
- id="align"
46
- title="Alignment"
47
- fieldSet="default"
48
- onChange={() => {}}
49
- actions={['additional']}
50
- actionsInfoMap={{
51
- additional: [imageFullSVG, 'Additional action title'],
52
- }}
53
- />
54
- </Provider>,
55
- );
56
-
57
- expect(asFragment()).toMatchSnapshot();
58
- });
59
- });
@@ -1,41 +0,0 @@
1
- import React from 'react';
2
- import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
3
- import Icon from '@plone/volto/components/theme/Icon/Icon';
4
- import { Button } from 'semantic-ui-react';
5
-
6
- // The ButtonsWidget
7
- const ButtonsWidget = (props) => {
8
- const { id, onChange, actions, actionsInfoMap, defaultAction, value } = props;
9
-
10
- React.useEffect(() => {
11
- if (!props.value && props.default) {
12
- props.onChange(props.id, props.default);
13
- }
14
- });
15
-
16
- return (
17
- <FormFieldWrapper {...props} className="align-widget">
18
- <div className="align-buttons">
19
- {actions.map((action) => (
20
- <Button.Group key={action}>
21
- <Button
22
- icon
23
- basic
24
- aria-label={actionsInfoMap[action][1]}
25
- onClick={() => onChange(id, action)}
26
- active={(action === defaultAction && !value) || value === action}
27
- >
28
- <Icon
29
- name={actionsInfoMap[action][0]}
30
- title={actionsInfoMap[action][1] || action}
31
- size="24px"
32
- />
33
- </Button>
34
- </Button.Group>
35
- ))}
36
- </div>
37
- </FormFieldWrapper>
38
- );
39
- };
40
-
41
- export default ButtonsWidget;
@@ -1,70 +0,0 @@
1
- import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import configureStore from 'redux-mock-store';
4
- import { Provider } from 'react-intl-redux';
5
- import imageFullSVG from '@plone/volto/icons/image-full.svg';
6
- import textJustifiedSVG from '@plone/volto/icons/align-justify.svg';
7
- import textCenteredSVG from '@plone/volto/icons/align-center.svg';
8
- import textLeftSVG from '@plone/volto/icons/align-left.svg';
9
- import textRightSVG from '@plone/volto/icons/align-right.svg';
10
-
11
- import ButtonsWidget from './ButtonsWidget';
12
-
13
- const mockStore = configureStore();
14
-
15
- describe('renders an align widget component', () => {
16
- it('basic', () => {
17
- const store = mockStore({
18
- intl: {
19
- locale: 'en',
20
- messages: {},
21
- },
22
- });
23
-
24
- const { asFragment } = render(
25
- <Provider store={store}>
26
- <ButtonsWidget
27
- id="align"
28
- title="Alignment"
29
- fieldSet="default"
30
- onChange={() => {}}
31
- actions={['left', 'right', 'centered', 'justified']}
32
- actionsInfoMap={{
33
- left: [textLeftSVG, 'Text Left'],
34
- right: [textRightSVG, 'Text Right'],
35
- justified: [textJustifiedSVG, 'Text Justified'],
36
- centered: [textCenteredSVG, 'Text Centered'],
37
- }}
38
- />
39
- </Provider>,
40
- );
41
-
42
- expect(asFragment()).toMatchSnapshot();
43
- });
44
-
45
- it('extended with actions and actionsInfoMap props', () => {
46
- const store = mockStore({
47
- intl: {
48
- locale: 'en',
49
- messages: {},
50
- },
51
- });
52
-
53
- const { asFragment } = render(
54
- <Provider store={store}>
55
- <ButtonsWidget
56
- id="align"
57
- title="Alignment"
58
- fieldSet="default"
59
- onChange={() => {}}
60
- actions={['additional']}
61
- actionsInfoMap={{
62
- additional: [imageFullSVG, 'Additional action title'],
63
- }}
64
- />
65
- </Provider>,
66
- );
67
-
68
- expect(asFragment()).toMatchSnapshot();
69
- });
70
- });