Skip to content

Commit 81c0875

Browse files
authored
CardView: Add human readable story for toolbar (aqaMoxJ3) (DevExpress#29802)
1 parent f6db675 commit 81c0875

File tree

3 files changed

+198
-8
lines changed

3 files changed

+198
-8
lines changed

apps/react-storybook/stories/card_view/Card.stories.tsx renamed to apps/react-storybook/stories/card_view/parts/Card.stories.tsx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {Meta, StoryObj} from "@storybook/react";
22

33
import dxCardView from "devextreme/ui/card_view";
4-
import {wrapDxWithReact} from "../utils";
4+
import { wrapDxWithReact } from "../../utils";
55
import Button from "devextreme/ui/button";
66

77
const CardView = wrapDxWithReact(dxCardView);
@@ -15,6 +15,8 @@ interface HumanReadableProps {
1515
headerShowDeleteButton: boolean;
1616
headerShowCardTitle: boolean;
1717
image: ImageType;
18+
imageRatio: string;
19+
imageMaxHeight: number;
1820
cardFields: Record<string, string>,
1921
showCardFooterTemplate: boolean,
2022
}
@@ -61,21 +63,35 @@ const CARD_FOOTER_TEMPLATE = () => {
6163
const setImageProps = (
6264
props: Record<string, any>,
6365
image: ImageType,
66+
ratio: string,
67+
maxHeight: number,
6468
): void => {
69+
const baseCardCoverOptions = {aspectRatio: ratio, maxHeight};
70+
6571
switch (image) {
6672
case 'placeholder':
67-
props.cardCover = {imageExpr: 'image'};
73+
props.cardCover = {
74+
imageExpr: 'image',
75+
...baseCardCoverOptions,
76+
};
6877
return;
6978
case 'small':
70-
props.cardCover = {imageExpr: () => 'images/card_view/cat_small_crop.jpg'};
79+
props.cardCover = {
80+
imageExpr: () => 'images/card_view/cat_small_crop.jpg',
81+
...baseCardCoverOptions,
82+
};
7183
return;
7284
case 'wide':
7385
props.cardCover = {
7486
imageExpr: () => 'images/card_view/cat_wide.jpg',
87+
...baseCardCoverOptions,
7588
};
7689
return;
7790
case 'tall':
78-
props.cardCover = {imageExpr: () => 'images/card_view/cat_tall.jpg'};
91+
props.cardCover = {
92+
imageExpr: () => 'images/card_view/cat_tall.jpg',
93+
...baseCardCoverOptions,
94+
};
7995
return;
8096
case 'none':
8197
default:
@@ -95,6 +111,8 @@ const mergeProps = (
95111
headerShowDeleteButton,
96112
headerShowCardTitle,
97113
image,
114+
imageRatio,
115+
imageMaxHeight,
98116
cardFields,
99117
showCardFooterTemplate
100118
} = humanReadableProps;
@@ -121,7 +139,7 @@ const mergeProps = (
121139
}
122140
: undefined;
123141

124-
setImageProps(result, image);
142+
setImageProps(result, image, imageRatio, imageMaxHeight);
125143

126144
result.cardFooterTemplate = showCardFooterTemplate
127145
? CARD_FOOTER_TEMPLATE
@@ -138,7 +156,7 @@ const CardViewHumanReadableWrapper = (
138156
}
139157

140158
const meta: Meta<typeof CardView> = {
141-
title: "Grids/CardView/Card",
159+
title: "Grids/CardView/Parts",
142160
component: CardViewHumanReadableWrapper,
143161
argTypes: {
144162
headerShowCheckBox: {
@@ -157,6 +175,12 @@ const meta: Meta<typeof CardView> = {
157175
control: 'select',
158176
options: imageTypes,
159177
},
178+
imageRatio: {
179+
control: 'text',
180+
},
181+
imageMaxHeight: {
182+
control: 'number',
183+
},
160184
cardFields: {
161185
control: 'object',
162186
},
@@ -170,13 +194,15 @@ export default meta;
170194

171195
type Story = StoryObj<typeof CardView>;
172196

173-
export const Playground: Story = {
197+
export const Card: Story = {
174198
args: {
175199
headerShowCheckBox: true,
176200
headerShowEditingButton: true,
177201
headerShowDeleteButton: true,
178202
headerShowCardTitle: true,
179203
image: 'none',
204+
imageRatio: '1/1',
205+
imageMaxHeight: 0,
180206
cardFields: {
181207
id: 0,
182208
firstName: 'John',
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import type {Meta, StoryObj} from "@storybook/react";
2+
3+
import dxCardView from "devextreme/ui/card_view";
4+
import { wrapDxWithReact } from "../../utils";
5+
import {generatedData} from "../generatedData";
6+
import Button from "devextreme/ui/button";
7+
8+
const CardView = wrapDxWithReact(dxCardView);
9+
10+
interface HumanReadableProps {
11+
showToolbar: boolean;
12+
disableToolbar: boolean;
13+
multilineToolbar: boolean;
14+
showCustomToolbarButton: boolean;
15+
showSelectionButtons: boolean;
16+
showSearch: boolean;
17+
showColumnChooser: boolean;
18+
showAddCardButton: boolean;
19+
}
20+
21+
const DEFAULT_PROPS = {
22+
keyExpr: 'id',
23+
dataSource: generatedData,
24+
}
25+
26+
const TOOLBAR_CUSTOM_BUTTON_TEMPLATE = () => {
27+
const button = document.createElement('div');
28+
new Button(button, {text: 'Custom button', icon: 'edit' });
29+
30+
return button;
31+
}
32+
33+
const TOOLBAR_CUSTOM_BUTTON_ITEM = {
34+
location: 'before',
35+
template: TOOLBAR_CUSTOM_BUTTON_TEMPLATE,
36+
}
37+
38+
const setToolbarProps = (
39+
props: Record<string, any>,
40+
humanReadableProps: HumanReadableProps,
41+
): void => {
42+
const {
43+
showToolbar,
44+
disableToolbar,
45+
multilineToolbar,
46+
showCustomToolbarButton,
47+
showSelectionButtons,
48+
showSearch,
49+
showColumnChooser,
50+
showAddCardButton,
51+
} = humanReadableProps;
52+
53+
props.toolbar = {
54+
visible: showToolbar,
55+
disabled: disableToolbar,
56+
multiline: multilineToolbar,
57+
items: null,
58+
};
59+
60+
if (showCustomToolbarButton) {
61+
const customItems: any[] = [];
62+
63+
showSelectionButtons
64+
&& customItems.push('selectAllButton')
65+
&& customItems.push('clearSelectionButton');
66+
showSearch && customItems.push('searchPanel');
67+
showColumnChooser && customItems.push('columnChooserButton');
68+
showAddCardButton && customItems.push('addCardButton');
69+
showCustomToolbarButton && customItems.push(TOOLBAR_CUSTOM_BUTTON_ITEM);
70+
71+
props.toolbar.items = customItems;
72+
}
73+
}
74+
75+
const mergeProps = (
76+
humanReadableProps: HumanReadableProps,
77+
defaultProps: Record<PropertyKey, any>,
78+
): Record<PropertyKey, any> => {
79+
const result = {...defaultProps};
80+
const {
81+
showSelectionButtons,
82+
showSearch,
83+
showColumnChooser,
84+
showAddCardButton,
85+
} = humanReadableProps;
86+
87+
setToolbarProps(result, humanReadableProps);
88+
89+
result.selection = showSelectionButtons
90+
? { mode: 'multiple' }
91+
: undefined;
92+
93+
result.searchPanel = showSearch
94+
? { visible: true }
95+
: undefined;
96+
97+
result.columnChooser = showColumnChooser
98+
? { enabled: true }
99+
: undefined;
100+
101+
result.editing = showAddCardButton
102+
? { allowAdding: true }
103+
: undefined;
104+
105+
return result;
106+
}
107+
108+
const CardViewHumanReadableWrapper = (
109+
humanReadableProps: HumanReadableProps,
110+
) => {
111+
const props = mergeProps(humanReadableProps, DEFAULT_PROPS);
112+
return CardView(props);
113+
}
114+
115+
const meta: Meta<typeof CardView> = {
116+
title: "Grids/CardView/Parts",
117+
component: CardViewHumanReadableWrapper,
118+
argTypes: {
119+
showToolbar: {
120+
control: 'boolean',
121+
},
122+
disableToolbar: {
123+
control: 'boolean',
124+
},
125+
multilineToolbar: {
126+
control: 'boolean',
127+
},
128+
// TODO Toolbar: Custom items bug -> uncomment after fix
129+
showCustomToolbarButton: {
130+
control: 'boolean',
131+
},
132+
showSelectionButtons: {
133+
control: 'boolean',
134+
},
135+
showSearch: {
136+
control: 'boolean',
137+
},
138+
showColumnChooser: {
139+
control: 'boolean',
140+
},
141+
showAddCardButton: {
142+
control: 'boolean',
143+
}
144+
}
145+
};
146+
147+
export default meta;
148+
149+
type Story = StoryObj<typeof CardView>;
150+
151+
export const Toolbar: Story = {
152+
args: {
153+
showToolbar: true,
154+
disableToolbar: false,
155+
multilineToolbar: false,
156+
showCustomToolbarButton: false,
157+
showSelectionButtons: true,
158+
showSearch: true,
159+
showColumnChooser: false,
160+
showAddCardButton: true,
161+
}
162+
}
163+

packages/devextreme/js/__internal/grids/new/grid_core/inferno_wrappers/toolbar.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export class Toolbar extends InfernoWrapper<ToolbarProps, dxToolbar> {
3232
const prevOptions = prevItem[key];
3333
const currentOptions = item[key];
3434
Object.keys(currentOptions).forEach((option) => {
35-
const isOptionChanged = currentOptions[option] !== prevOptions[option];
35+
const isOptionChanged = !prevOptions?.[option]
36+
|| currentOptions?.[option] !== prevOptions[option];
3637
const isExcludedOption = excludedStateOptions.includes(option);
3738
if (isOptionChanged && !isExcludedOption) {
3839
this.component?.option(`items[${index}].${key}.${option}`, props.items![index][key][option]);

0 commit comments

Comments
 (0)