@frontify/guideline-blocks-settings 0.32.0 → 0.32.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/components/Attachments/AttachmentItem.es.js +128 -109
- package/dist/components/Attachments/AttachmentItem.es.js.map +1 -1
- package/dist/components/Attachments/Attachments.es.js +9 -1
- package/dist/components/Attachments/Attachments.es.js.map +1 -1
- package/dist/components/Attachments/AttachmentsButtonTrigger.es.js +17 -9
- package/dist/components/Attachments/AttachmentsButtonTrigger.es.js.map +1 -1
- package/dist/components/BlockItemWrapper/BlockItemWrapper.es.js +37 -39
- package/dist/components/BlockItemWrapper/BlockItemWrapper.es.js.map +1 -1
- package/dist/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButton.es.js +33 -0
- package/dist/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButtonTrigger.es.js +26 -0
- package/dist/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButtonTrigger.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/BaseToolbarButton.es.js +28 -0
- package/dist/components/BlockItemWrapper/Toolbar/BaseToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/DragHandleToolbarButton/DragHandleToolbarButton.es.js +35 -0
- package/dist/components/BlockItemWrapper/Toolbar/DragHandleToolbarButton/DragHandleToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/FlyoutToolbarButton/FlyoutToolbarButton.es.js +44 -0
- package/dist/components/BlockItemWrapper/Toolbar/FlyoutToolbarButton/FlyoutToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/MenuToolbarButton/MenuToolbarButton.es.js +25 -0
- package/dist/components/BlockItemWrapper/Toolbar/MenuToolbarButton/MenuToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/MenuToolbarButton/ToolbarFlyoutMenu.es.js +29 -0
- package/dist/components/BlockItemWrapper/Toolbar/MenuToolbarButton/ToolbarFlyoutMenu.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/Toolbar.es.js +13 -110
- package/dist/components/BlockItemWrapper/Toolbar/Toolbar.es.js.map +1 -1
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarButton/ToolbarButton.es.js +12 -0
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarButton/ToolbarButton.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarButtonTooltip.es.js +20 -0
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarButtonTooltip.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/context/DragPreviewContext.es.js +11 -0
- package/dist/components/BlockItemWrapper/Toolbar/context/DragPreviewContext.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/context/MultiFlyoutContext.es.js +18 -0
- package/dist/components/BlockItemWrapper/Toolbar/context/MultiFlyoutContext.es.js.map +1 -0
- package/dist/components/BlockItemWrapper/Toolbar/helpers.es.js +1 -1
- package/dist/components/BlockItemWrapper/Toolbar/helpers.es.js.map +1 -1
- package/dist/components/BlockItemWrapper/Toolbar/hooks/useMultiFlyoutState.es.js +18 -0
- package/dist/components/BlockItemWrapper/Toolbar/hooks/useMultiFlyoutState.es.js.map +1 -0
- package/dist/helpers/mapColorPalettes.es.js +20 -8
- package/dist/helpers/mapColorPalettes.es.js.map +1 -1
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +57 -23
- package/dist/index.es.js +195 -185
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +3 -3
- package/dist/index.umd.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -2
- package/setupTests.ts +7 -2
- package/src/components/Attachments/AttachmentItem.tsx +21 -0
- package/src/components/Attachments/Attachments.spec.ct.tsx +20 -1
- package/src/components/Attachments/Attachments.tsx +8 -4
- package/src/components/Attachments/AttachmentsButtonTrigger.tsx +11 -3
- package/src/components/Attachments/types.ts +4 -2
- package/src/components/BlockItemWrapper/BlockItemWrapper.tsx +47 -47
- package/src/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButton.spec.tsx +96 -0
- package/src/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButton.tsx +42 -0
- package/src/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButtonTrigger.spec.tsx +44 -0
- package/src/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/AttachmentsToolbarButtonTrigger.tsx +24 -0
- package/src/components/BlockItemWrapper/Toolbar/AttachmentsToolbarButton/index.ts +3 -0
- package/src/components/BlockItemWrapper/Toolbar/BaseToolbarButton.spec.tsx +40 -0
- package/src/components/BlockItemWrapper/Toolbar/BaseToolbarButton.tsx +37 -0
- package/src/components/BlockItemWrapper/Toolbar/DragHandleToolbarButton/DragHandleToolbarButton.spec.tsx +89 -0
- package/src/components/BlockItemWrapper/Toolbar/DragHandleToolbarButton/DragHandleToolbarButton.tsx +39 -0
- package/src/components/BlockItemWrapper/Toolbar/DragHandleToolbarButton/index.ts +3 -0
- package/src/components/BlockItemWrapper/Toolbar/FlyoutToolbarButton/FlyoutToolbarButton.spec.tsx +140 -0
- package/src/components/BlockItemWrapper/Toolbar/FlyoutToolbarButton/FlyoutToolbarButton.tsx +61 -0
- package/src/components/BlockItemWrapper/Toolbar/FlyoutToolbarButton/index.ts +3 -0
- package/src/components/BlockItemWrapper/Toolbar/MenuToolbarButton/MenuToolbarButton.spec.tsx +77 -0
- package/src/components/BlockItemWrapper/Toolbar/MenuToolbarButton/MenuToolbarButton.tsx +30 -0
- package/src/components/BlockItemWrapper/Toolbar/MenuToolbarButton/ToolbarFlyoutMenu.spec.tsx +63 -0
- package/src/components/BlockItemWrapper/Toolbar/MenuToolbarButton/ToolbarFlyoutMenu.tsx +40 -0
- package/src/components/BlockItemWrapper/Toolbar/MenuToolbarButton/index.ts +3 -0
- package/src/components/BlockItemWrapper/Toolbar/Toolbar.spec.tsx +50 -53
- package/src/components/BlockItemWrapper/Toolbar/Toolbar.tsx +24 -126
- package/src/components/BlockItemWrapper/Toolbar/ToolbarButton/ToolbarButton.spec.tsx +70 -0
- package/src/components/BlockItemWrapper/Toolbar/ToolbarButton/ToolbarButton.tsx +19 -0
- package/src/components/BlockItemWrapper/Toolbar/ToolbarButton/index.ts +3 -0
- package/src/components/BlockItemWrapper/Toolbar/ToolbarButtonTooltip.tsx +25 -0
- package/src/components/BlockItemWrapper/Toolbar/context/DragPreviewContext.tsx +15 -0
- package/src/components/BlockItemWrapper/Toolbar/context/MultiFlyoutContext.tsx +25 -0
- package/src/components/BlockItemWrapper/Toolbar/helpers.ts +1 -1
- package/src/components/BlockItemWrapper/Toolbar/hooks/useMultiFlyoutState.spec.tsx +59 -0
- package/src/components/BlockItemWrapper/Toolbar/hooks/useMultiFlyoutState.ts +24 -0
- package/src/components/BlockItemWrapper/Toolbar/index.ts +4 -0
- package/src/components/BlockItemWrapper/Toolbar/types.ts +8 -27
- package/src/helpers/mapColorPalettes.spec.ts +14 -113
- package/src/helpers/mapColorPalettes.ts +51 -8
- package/src/hooks/useAttachments.spec.tsx +1 -0
- package/tsconfig.json +1 -1
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarAttachments.es.js +0 -27
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarAttachments.es.js.map +0 -1
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarAttachmentsTrigger.es.js +0 -12
- package/dist/components/BlockItemWrapper/Toolbar/ToolbarAttachmentsTrigger.es.js.map +0 -1
- package/src/components/BlockItemWrapper/Toolbar/ToolbarAttachments.tsx +0 -29
- package/src/components/BlockItemWrapper/Toolbar/ToolbarAttachmentsTrigger.tsx +0 -14
|
@@ -7,6 +7,9 @@ import { beforeAll, describe, expect, it, vi } from 'vitest';
|
|
|
7
7
|
import { AttachmentsProvider } from '../../../hooks/useAttachments';
|
|
8
8
|
|
|
9
9
|
import { Toolbar } from './Toolbar';
|
|
10
|
+
import { MultiFlyoutContextProvider } from './context/MultiFlyoutContext';
|
|
11
|
+
import { DEFAULT_ATTACHMENTS_BUTTON_ID, DEFAULT_MENU_BUTTON_ID } from '.';
|
|
12
|
+
import { DragPreviewContextProvider } from './context/DragPreviewContext';
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* @vitest-environment happy-dom
|
|
@@ -31,25 +34,13 @@ describe('Toolbar', () => {
|
|
|
31
34
|
|
|
32
35
|
it('should not throw error if toolbar does not have attachments enabled', () => {
|
|
33
36
|
expect(() =>
|
|
34
|
-
render(
|
|
35
|
-
<Toolbar
|
|
36
|
-
items={[]}
|
|
37
|
-
flyoutMenu={{ items: [], isOpen: false, onOpenChange: vi.fn() }}
|
|
38
|
-
attachments={{ isEnabled: false, isOpen: false, onOpenChange: vi.fn() }}
|
|
39
|
-
/>,
|
|
40
|
-
),
|
|
37
|
+
render(<Toolbar items={[]} flyoutMenu={{ items: [] }} attachments={{ isEnabled: false }} />),
|
|
41
38
|
).not.toThrowError();
|
|
42
39
|
});
|
|
43
40
|
|
|
44
41
|
it('should throw error if toolbar does have attachments enabled without provider', () => {
|
|
45
42
|
expect(() =>
|
|
46
|
-
render(
|
|
47
|
-
<Toolbar
|
|
48
|
-
items={[]}
|
|
49
|
-
flyoutMenu={{ items: [], isOpen: false, onOpenChange: vi.fn() }}
|
|
50
|
-
attachments={{ isEnabled: true, isOpen: false, onOpenChange: vi.fn() }}
|
|
51
|
-
/>,
|
|
52
|
-
),
|
|
43
|
+
render(<Toolbar items={[]} flyoutMenu={{ items: [] }} attachments={{ isEnabled: true }} />),
|
|
53
44
|
).toThrowError();
|
|
54
45
|
});
|
|
55
46
|
|
|
@@ -61,26 +52,28 @@ describe('Toolbar', () => {
|
|
|
61
52
|
});
|
|
62
53
|
|
|
63
54
|
const ToolbarWithAttachments = () => (
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
<MultiFlyoutContextProvider
|
|
56
|
+
openFlyoutIds={[DEFAULT_ATTACHMENTS_BUTTON_ID, DEFAULT_MENU_BUTTON_ID]}
|
|
57
|
+
setOpenFlyoutIds={vi.fn()}
|
|
58
|
+
>
|
|
59
|
+
<AttachmentsProvider appBridge={STUB_WITH_NO_ASSETS} assetId={MOCK_ASSET_FIELD_ID}>
|
|
60
|
+
<Toolbar
|
|
61
|
+
items={[]}
|
|
62
|
+
flyoutMenu={{
|
|
63
|
+
items: [
|
|
64
|
+
[
|
|
65
|
+
{
|
|
66
|
+
title: 'Replace with upload',
|
|
67
|
+
icon: <div></div>,
|
|
68
|
+
onClick: vi.fn(),
|
|
69
|
+
},
|
|
70
|
+
],
|
|
75
71
|
],
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
isDragging={false}
|
|
82
|
-
/>
|
|
83
|
-
</AttachmentsProvider>
|
|
72
|
+
}}
|
|
73
|
+
attachments={{ isEnabled: true }}
|
|
74
|
+
/>
|
|
75
|
+
</AttachmentsProvider>
|
|
76
|
+
</MultiFlyoutContextProvider>
|
|
84
77
|
);
|
|
85
78
|
|
|
86
79
|
const { baseElement } = render(<ToolbarWithAttachments />, { container: document.body });
|
|
@@ -98,26 +91,30 @@ describe('Toolbar', () => {
|
|
|
98
91
|
});
|
|
99
92
|
|
|
100
93
|
const ToolbarWithAttachments = () => (
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
<MultiFlyoutContextProvider
|
|
95
|
+
openFlyoutIds={[DEFAULT_ATTACHMENTS_BUTTON_ID, DEFAULT_MENU_BUTTON_ID]}
|
|
96
|
+
setOpenFlyoutIds={vi.fn()}
|
|
97
|
+
>
|
|
98
|
+
<DragPreviewContextProvider isDragPreview>
|
|
99
|
+
<AttachmentsProvider appBridge={STUB_WITH_NO_ASSETS} assetId={MOCK_ASSET_FIELD_ID}>
|
|
100
|
+
<Toolbar
|
|
101
|
+
items={[]}
|
|
102
|
+
flyoutMenu={{
|
|
103
|
+
items: [
|
|
104
|
+
[
|
|
105
|
+
{
|
|
106
|
+
title: 'Replace with upload',
|
|
107
|
+
icon: <div></div>,
|
|
108
|
+
onClick: vi.fn(),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
],
|
|
112
|
+
}}
|
|
113
|
+
attachments={{ isEnabled: true }}
|
|
114
|
+
/>
|
|
115
|
+
</AttachmentsProvider>
|
|
116
|
+
</DragPreviewContextProvider>
|
|
117
|
+
</MultiFlyoutContextProvider>
|
|
121
118
|
);
|
|
122
119
|
|
|
123
120
|
const { baseElement } = render(<ToolbarWithAttachments />, { container: document.body });
|
|
@@ -1,133 +1,31 @@
|
|
|
1
1
|
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
ActionMenu,
|
|
5
|
-
Flyout,
|
|
6
|
-
IconDotsHorizontal16,
|
|
7
|
-
MenuItemContentSize,
|
|
8
|
-
LegacyTooltip as Tooltip,
|
|
9
|
-
TooltipPosition,
|
|
10
|
-
} from '@frontify/fondue';
|
|
11
|
-
|
|
12
|
-
import { DEFAULT_DRAGGING_TOOLTIP, DEFAULT_DRAG_TOOLTIP } from '../constants';
|
|
13
|
-
|
|
14
3
|
import { ToolbarSegment } from './ToolbarSegment';
|
|
15
|
-
import {
|
|
16
|
-
import { getToolbarButtonClassNames } from './helpers';
|
|
4
|
+
import { AttachmentsToolbarButton } from './AttachmentsToolbarButton';
|
|
17
5
|
import { type ToolbarProps } from './types';
|
|
6
|
+
import { ToolbarButton } from './ToolbarButton';
|
|
7
|
+
import { DragHandleToolbarButton } from './DragHandleToolbarButton';
|
|
8
|
+
import { MenuToolbarButton } from './MenuToolbarButton';
|
|
18
9
|
|
|
19
|
-
export const Toolbar = ({ items, flyoutMenu, attachments
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{attachments.isEnabled && (
|
|
26
|
-
<ToolbarSegment>
|
|
27
|
-
<ToolbarAttachments
|
|
28
|
-
isOpen={attachments.isOpen && !isDragging}
|
|
29
|
-
onOpenChange={attachments.onOpenChange}
|
|
30
|
-
/>
|
|
31
|
-
</ToolbarSegment>
|
|
32
|
-
)}
|
|
10
|
+
export const Toolbar = ({ items, flyoutMenu, attachments }: ToolbarProps) => (
|
|
11
|
+
<div
|
|
12
|
+
data-test-id="block-item-wrapper-toolbar"
|
|
13
|
+
className="tw-rounded-md tw-bg-base tw-border tw-border-line-strong tw-divide-x tw-divide-line-strong tw-shadow-lg tw-flex tw-flex-none tw-items-center tw-isolate"
|
|
14
|
+
>
|
|
15
|
+
{attachments.isEnabled && (
|
|
33
16
|
<ToolbarSegment>
|
|
34
|
-
|
|
35
|
-
'draggableProps' in item ? (
|
|
36
|
-
<Tooltip
|
|
37
|
-
key={i}
|
|
38
|
-
withArrow
|
|
39
|
-
hoverDelay={0}
|
|
40
|
-
enterDelay={300}
|
|
41
|
-
open={isDragging}
|
|
42
|
-
position={TooltipPosition.Top}
|
|
43
|
-
content={
|
|
44
|
-
<div>
|
|
45
|
-
{isDragging ? DEFAULT_DRAGGING_TOOLTIP : item.tooltip ?? DEFAULT_DRAG_TOOLTIP}
|
|
46
|
-
</div>
|
|
47
|
-
}
|
|
48
|
-
triggerElement={
|
|
49
|
-
<button
|
|
50
|
-
ref={item.setActivatorNodeRef}
|
|
51
|
-
data-test-id="block-item-wrapper-toolbar-btn"
|
|
52
|
-
{...item.draggableProps}
|
|
53
|
-
className={getToolbarButtonClassNames('grab', isDragging)}
|
|
54
|
-
>
|
|
55
|
-
{item.icon}
|
|
56
|
-
</button>
|
|
57
|
-
}
|
|
58
|
-
/>
|
|
59
|
-
) : (
|
|
60
|
-
<Tooltip
|
|
61
|
-
key={i}
|
|
62
|
-
withArrow
|
|
63
|
-
enterDelay={300}
|
|
64
|
-
hoverDelay={0}
|
|
65
|
-
disabled={isDragging}
|
|
66
|
-
position={TooltipPosition.Top}
|
|
67
|
-
content={<div>{item.tooltip ?? ''}</div>}
|
|
68
|
-
triggerElement={
|
|
69
|
-
<button
|
|
70
|
-
data-test-id="block-item-wrapper-toolbar-btn"
|
|
71
|
-
onClick={item.onClick}
|
|
72
|
-
className={getToolbarButtonClassNames('pointer')}
|
|
73
|
-
>
|
|
74
|
-
{item.icon}
|
|
75
|
-
</button>
|
|
76
|
-
}
|
|
77
|
-
/>
|
|
78
|
-
),
|
|
79
|
-
)}
|
|
80
|
-
{flyoutMenu.items.length > 0 && (
|
|
81
|
-
<Tooltip
|
|
82
|
-
withArrow
|
|
83
|
-
hoverDelay={0}
|
|
84
|
-
enterDelay={300}
|
|
85
|
-
disabled={isDragging || flyoutMenu.isOpen}
|
|
86
|
-
position={TooltipPosition.Top}
|
|
87
|
-
content={<div>Options</div>}
|
|
88
|
-
triggerElement={
|
|
89
|
-
<div className="tw-flex tw-flex-shrink-0 tw-flex-1 tw-h-6 tw-relative">
|
|
90
|
-
<Flyout
|
|
91
|
-
isOpen={flyoutMenu.isOpen && !isDragging}
|
|
92
|
-
legacyFooter={false}
|
|
93
|
-
fitContent
|
|
94
|
-
hug={false}
|
|
95
|
-
onOpenChange={flyoutMenu.onOpenChange}
|
|
96
|
-
trigger={
|
|
97
|
-
<div
|
|
98
|
-
data-test-id="block-item-wrapper-toolbar-flyout"
|
|
99
|
-
className={getToolbarButtonClassNames(
|
|
100
|
-
'pointer',
|
|
101
|
-
flyoutMenu.isOpen && !isDragging,
|
|
102
|
-
)}
|
|
103
|
-
>
|
|
104
|
-
<IconDotsHorizontal16 />
|
|
105
|
-
</div>
|
|
106
|
-
}
|
|
107
|
-
>
|
|
108
|
-
<ActionMenu
|
|
109
|
-
menuBlocks={flyoutMenu.items.map((block, blockIndex) => ({
|
|
110
|
-
id: blockIndex.toString(),
|
|
111
|
-
menuItems: block.map((item, itemIndex) => ({
|
|
112
|
-
id: blockIndex.toString() + itemIndex.toString(),
|
|
113
|
-
size: MenuItemContentSize.XSmall,
|
|
114
|
-
title: item.title,
|
|
115
|
-
style: item.style,
|
|
116
|
-
onClick: () => {
|
|
117
|
-
flyoutMenu.onOpenChange(false);
|
|
118
|
-
item.onClick();
|
|
119
|
-
},
|
|
120
|
-
initialValue: true,
|
|
121
|
-
decorator: <div className="tw-mr-2">{item.icon}</div>,
|
|
122
|
-
})),
|
|
123
|
-
}))}
|
|
124
|
-
/>
|
|
125
|
-
</Flyout>
|
|
126
|
-
</div>
|
|
127
|
-
}
|
|
128
|
-
/>
|
|
129
|
-
)}
|
|
17
|
+
<AttachmentsToolbarButton />
|
|
130
18
|
</ToolbarSegment>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
19
|
+
)}
|
|
20
|
+
<ToolbarSegment>
|
|
21
|
+
{items.map((item, i) =>
|
|
22
|
+
'draggableProps' in item ? (
|
|
23
|
+
<DragHandleToolbarButton key={i} {...item} />
|
|
24
|
+
) : (
|
|
25
|
+
<ToolbarButton key={i} {...item} />
|
|
26
|
+
),
|
|
27
|
+
)}
|
|
28
|
+
{flyoutMenu.items.length > 0 && <MenuToolbarButton {...flyoutMenu} />}
|
|
29
|
+
</ToolbarSegment>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, waitFor } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { ToolbarButton } from './ToolbarButton';
|
|
6
|
+
import { IconAdobeCreativeCloud } from '@frontify/fondue';
|
|
7
|
+
import { DragPreviewContextProvider } from '../context/DragPreviewContext';
|
|
8
|
+
|
|
9
|
+
const TOOLBAR_BUTTON_ID = 'block-item-wrapper-toolbar-btn';
|
|
10
|
+
const TOOLTIP_ID = 'toolbar-button-tooltip';
|
|
11
|
+
|
|
12
|
+
const TOOLTIP_CONTENT = 'content';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @vitest-environment happy-dom
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
describe('ToolbarButton', () => {
|
|
19
|
+
it('should disable tooltip when item is in drag preview context', async () => {
|
|
20
|
+
const { getByTestId } = render(
|
|
21
|
+
<DragPreviewContextProvider isDragPreview>
|
|
22
|
+
<ToolbarButton onClick={vi.fn()} tooltip={TOOLTIP_CONTENT} icon={<IconAdobeCreativeCloud />} />
|
|
23
|
+
</DragPreviewContextProvider>,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
expect(getByTestId(TOOLTIP_ID)).toHaveClass('tw-opacity-0');
|
|
27
|
+
|
|
28
|
+
getByTestId(TOOLTIP_ID).focus();
|
|
29
|
+
|
|
30
|
+
await waitFor(() => {
|
|
31
|
+
expect(getByTestId(TOOLTIP_ID)).toHaveClass('tw-opacity-0');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should show tooltip when item is focused', async () => {
|
|
36
|
+
const { getByTestId } = render(
|
|
37
|
+
<ToolbarButton onClick={vi.fn()} tooltip={TOOLTIP_CONTENT} icon={<IconAdobeCreativeCloud />} />,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(getByTestId(TOOLTIP_ID)).toHaveClass('tw-opacity-0');
|
|
41
|
+
expect(getByTestId(TOOLTIP_ID)).toHaveTextContent(TOOLTIP_CONTENT);
|
|
42
|
+
|
|
43
|
+
getByTestId(TOOLTIP_ID).focus();
|
|
44
|
+
|
|
45
|
+
await waitFor(() => {
|
|
46
|
+
expect(getByTestId(TOOLTIP_ID)).not.toHaveClass('tw-opacity-0');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should trigger onClick', async () => {
|
|
51
|
+
const onClickStub = vi.fn();
|
|
52
|
+
const { getByTestId } = render(
|
|
53
|
+
<ToolbarButton onClick={onClickStub} tooltip={TOOLTIP_CONTENT} icon={<IconAdobeCreativeCloud />} />,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
await fireEvent.click(getByTestId(TOOLBAR_BUTTON_ID));
|
|
57
|
+
|
|
58
|
+
expect(onClickStub).toHaveBeenCalledOnce();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should display icon', async () => {
|
|
62
|
+
const { getByTestId } = render(
|
|
63
|
+
<ToolbarButton onClick={vi.fn()} tooltip={TOOLTIP_CONTENT} icon={<IconAdobeCreativeCloud />} />,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const icons = [...getByTestId(TOOLBAR_BUTTON_ID).querySelectorAll('svg')];
|
|
67
|
+
expect(icons).toHaveLength(1);
|
|
68
|
+
expect(icons[0].outerHTML).toMatch('IconAdobeCreativeCloud');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useDragPreviewContext } from '../context/DragPreviewContext';
|
|
4
|
+
import { BaseToolbarButton } from '../BaseToolbarButton';
|
|
5
|
+
import { ToolbarButtonTooltip } from '../ToolbarButtonTooltip';
|
|
6
|
+
|
|
7
|
+
export type ToolbarButtonProps = { icon: JSX.Element; tooltip?: string; onClick: () => void };
|
|
8
|
+
|
|
9
|
+
export const ToolbarButton = ({ tooltip, icon, onClick }: ToolbarButtonProps) => {
|
|
10
|
+
const isDragPreview = useDragPreviewContext();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<ToolbarButtonTooltip disabled={isDragPreview} content={tooltip ?? ''}>
|
|
14
|
+
<BaseToolbarButton data-test-id="block-item-wrapper-toolbar-btn" onClick={onClick}>
|
|
15
|
+
{icon}
|
|
16
|
+
</BaseToolbarButton>
|
|
17
|
+
</ToolbarButtonTooltip>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { LegacyTooltip as Tooltip, TooltipPosition } from '@frontify/fondue';
|
|
4
|
+
import { ReactElement, ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
type ToolbarButtonTooltipProps = {
|
|
7
|
+
content: ReactNode;
|
|
8
|
+
children: ReactElement;
|
|
9
|
+
open?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const ToolbarButtonTooltip = ({ open, content, children, disabled }: ToolbarButtonTooltipProps) => (
|
|
14
|
+
<Tooltip
|
|
15
|
+
withArrow
|
|
16
|
+
hoverDelay={0}
|
|
17
|
+
enterDelay={300}
|
|
18
|
+
open={open}
|
|
19
|
+
disabled={disabled}
|
|
20
|
+
position={TooltipPosition.Top}
|
|
21
|
+
content={<div>{content}</div>}
|
|
22
|
+
triggerElement={children}
|
|
23
|
+
data-test-id="toolbar-button-tooltip"
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { type ReactNode, createContext, useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
const DragPreviewContext = createContext(false);
|
|
6
|
+
|
|
7
|
+
export const DragPreviewContextProvider = ({
|
|
8
|
+
children,
|
|
9
|
+
isDragPreview,
|
|
10
|
+
}: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
isDragPreview: boolean;
|
|
13
|
+
}) => <DragPreviewContext.Provider value={isDragPreview}>{children}</DragPreviewContext.Provider>;
|
|
14
|
+
|
|
15
|
+
export const useDragPreviewContext = () => useContext(DragPreviewContext);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { Dispatch, ReactNode, SetStateAction, createContext, useContext, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
export type MultiFlyoutContextType = {
|
|
6
|
+
openFlyoutIds: string[];
|
|
7
|
+
setOpenFlyoutIds: Dispatch<SetStateAction<string[]>>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const MultiFlyoutContext = createContext<MultiFlyoutContextType>({
|
|
11
|
+
openFlyoutIds: [],
|
|
12
|
+
setOpenFlyoutIds: () => console.error('No MultiFlyoutContext Provider found'),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const MultiFlyoutContextProvider = ({
|
|
16
|
+
children,
|
|
17
|
+
openFlyoutIds,
|
|
18
|
+
setOpenFlyoutIds,
|
|
19
|
+
}: { children: ReactNode } & MultiFlyoutContextType) => {
|
|
20
|
+
const memoizedContext = useMemo(() => ({ openFlyoutIds, setOpenFlyoutIds }), [openFlyoutIds, setOpenFlyoutIds]);
|
|
21
|
+
|
|
22
|
+
return <MultiFlyoutContext.Provider value={memoizedContext}>{children}</MultiFlyoutContext.Provider>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const useMultiFlyoutContext = () => useContext(MultiFlyoutContext);
|
|
@@ -25,7 +25,7 @@ export const getToolbarButtonClassNames = (cursor: 'grab' | 'pointer', forceActi
|
|
|
25
25
|
classNames.push(
|
|
26
26
|
'hover:tw-bg-box-neutral-hover active:tw-bg-box-neutral-pressed',
|
|
27
27
|
'tw-text-text-weak hover:tw-text-box-neutral-inverse-hover active:tw-text-box-neutral-inverse-pressed',
|
|
28
|
-
cursor === 'grab' ? 'tw-cursor-grab active:tw-cursor-grabbing' : 'tw-cursor-pointer',
|
|
28
|
+
cursor === 'grab' ? '!tw-cursor-grab active:tw-cursor-grabbing' : 'tw-cursor-pointer',
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { renderHook } from '@testing-library/react';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { useMultiFlyoutState } from './useMultiFlyoutState';
|
|
6
|
+
import { MultiFlyoutContextProvider, MultiFlyoutContextType } from '../context/MultiFlyoutContext';
|
|
7
|
+
|
|
8
|
+
const FLYOUT_ID = 'flyout';
|
|
9
|
+
|
|
10
|
+
const renderMultiFlyoutState = ({ openFlyoutIds, setOpenFlyoutIds }: MultiFlyoutContextType) =>
|
|
11
|
+
renderHook(() => useMultiFlyoutState(FLYOUT_ID), {
|
|
12
|
+
wrapper: ({ children }) => (
|
|
13
|
+
<MultiFlyoutContextProvider openFlyoutIds={openFlyoutIds} setOpenFlyoutIds={setOpenFlyoutIds}>
|
|
14
|
+
{children}
|
|
15
|
+
</MultiFlyoutContextProvider>
|
|
16
|
+
),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('useMultiFlyoutState', () => {
|
|
20
|
+
it('should be open when flyout id in context array', () => {
|
|
21
|
+
const { result } = renderMultiFlyoutState({ openFlyoutIds: [FLYOUT_ID], setOpenFlyoutIds: vi.fn() });
|
|
22
|
+
expect(result.current.isOpen).toEqual(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should be closed when flyout id is not in context array', () => {
|
|
26
|
+
const { result } = renderMultiFlyoutState({ openFlyoutIds: [], setOpenFlyoutIds: vi.fn() });
|
|
27
|
+
expect(result.current.isOpen).toEqual(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should add id to array when opening', () => {
|
|
31
|
+
const setOpenFlyoutIdsStub = vi.fn();
|
|
32
|
+
const { result } = renderMultiFlyoutState({ openFlyoutIds: [], setOpenFlyoutIds: setOpenFlyoutIdsStub });
|
|
33
|
+
|
|
34
|
+
result.current.onOpenChange(true);
|
|
35
|
+
const dispatchedResult = setOpenFlyoutIdsStub.mock.lastCall[0]([]);
|
|
36
|
+
|
|
37
|
+
expect(dispatchedResult).toEqual([FLYOUT_ID]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should remove id from array when closing', () => {
|
|
41
|
+
const setOpenFlyoutIdsStub = vi.fn();
|
|
42
|
+
const { result } = renderMultiFlyoutState({ openFlyoutIds: [], setOpenFlyoutIds: setOpenFlyoutIdsStub });
|
|
43
|
+
|
|
44
|
+
result.current.onOpenChange(false);
|
|
45
|
+
const dispatchedResult = setOpenFlyoutIdsStub.mock.lastCall[0]([FLYOUT_ID]);
|
|
46
|
+
|
|
47
|
+
expect(dispatchedResult).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should remove duplicates from array', () => {
|
|
51
|
+
const setOpenFlyoutIdsStub = vi.fn();
|
|
52
|
+
const { result } = renderMultiFlyoutState({ openFlyoutIds: [], setOpenFlyoutIds: setOpenFlyoutIdsStub });
|
|
53
|
+
|
|
54
|
+
result.current.onOpenChange(true);
|
|
55
|
+
const dispatchedResult = setOpenFlyoutIdsStub.mock.lastCall[0]([FLYOUT_ID, FLYOUT_ID, FLYOUT_ID]);
|
|
56
|
+
|
|
57
|
+
expect(dispatchedResult).toEqual([FLYOUT_ID]);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { useMultiFlyoutContext } from '../context/MultiFlyoutContext';
|
|
5
|
+
|
|
6
|
+
export const useMultiFlyoutState = (flyoutId: string) => {
|
|
7
|
+
const { openFlyoutIds, setOpenFlyoutIds } = useMultiFlyoutContext();
|
|
8
|
+
|
|
9
|
+
const onOpenChange = useCallback(
|
|
10
|
+
(isFlyoutOpen: boolean) => {
|
|
11
|
+
setOpenFlyoutIds((currentIds) => {
|
|
12
|
+
const filteredIds = currentIds.filter((id) => id !== flyoutId);
|
|
13
|
+
if (!isFlyoutOpen) {
|
|
14
|
+
return filteredIds;
|
|
15
|
+
} else {
|
|
16
|
+
return [...filteredIds, flyoutId];
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
[flyoutId, setOpenFlyoutIds],
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
return { isOpen: openFlyoutIds.includes(flyoutId), onOpenChange };
|
|
24
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
2
|
|
|
3
3
|
export * from './Toolbar';
|
|
4
|
+
export * from './AttachmentsToolbarButton';
|
|
5
|
+
export * from './DragHandleToolbarButton';
|
|
6
|
+
export * from './FlyoutToolbarButton';
|
|
7
|
+
export * from './MenuToolbarButton';
|
|
4
8
|
export * from './types';
|
|
@@ -1,38 +1,19 @@
|
|
|
1
1
|
/* (c) Copyright Frontify Ltd., all rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { type
|
|
3
|
+
import { type ToolbarButtonProps } from './ToolbarButton';
|
|
4
|
+
import { type ToolbarFlyoutMenuItem } from './MenuToolbarButton/ToolbarFlyoutMenu';
|
|
5
|
+
import { DragHandleToolbarButtonProps } from '.';
|
|
4
6
|
|
|
5
7
|
export type ToolbarProps = {
|
|
6
8
|
items: ToolbarItem[];
|
|
7
|
-
flyoutMenu:
|
|
8
|
-
attachments:
|
|
9
|
-
isDragging?: boolean;
|
|
9
|
+
flyoutMenu: { items: ToolbarFlyoutMenuItem[][] };
|
|
10
|
+
attachments: { isEnabled: boolean };
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export type
|
|
13
|
-
isOpen: boolean;
|
|
14
|
-
onOpenChange: (isOpen: boolean) => void;
|
|
15
|
-
};
|
|
13
|
+
export type DraghandleToolbarItem = DragHandleToolbarButtonProps;
|
|
16
14
|
|
|
17
|
-
type
|
|
18
|
-
icon: JSX.Element;
|
|
19
|
-
tooltip?: string;
|
|
20
|
-
};
|
|
15
|
+
export type ButtonToolbarItem = ToolbarButtonProps;
|
|
21
16
|
|
|
22
|
-
type
|
|
23
|
-
draggableProps: Record<string, unknown>;
|
|
24
|
-
setActivatorNodeRef?: (node: HTMLElement | null) => void;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type ButtonToolbarItem = BaseToolbarItem & {
|
|
28
|
-
onClick: () => void;
|
|
29
|
-
};
|
|
17
|
+
export type FlyoutToolbarItem = ToolbarFlyoutMenuItem;
|
|
30
18
|
|
|
31
19
|
export type ToolbarItem = DraghandleToolbarItem | ButtonToolbarItem;
|
|
32
|
-
|
|
33
|
-
export type FlyoutToolbarItem = {
|
|
34
|
-
title: string;
|
|
35
|
-
onClick: () => void;
|
|
36
|
-
icon: JSX.Element;
|
|
37
|
-
style?: MenuItemStyle;
|
|
38
|
-
};
|