Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List: Add group header to focus order if collapsibleGroups is true #28293

Merged
merged 30 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f9c5c01
dirty
Nov 1, 2024
c561bad
List: Add group header to focus order if collapsibleGroups is true
Nov 1, 2024
be8f616
revert(list): Revert _itemElements()
Nov 1, 2024
adf8be2
feat(list): Spike tests
Nov 1, 2024
eb00a9b
feat(list): Add test
Nov 4, 2024
92a32e8
dirty
Nov 4, 2024
8166a6a
fix(list): Fix all solution
Nov 4, 2024
db7c26b
feat(list): Add styles for header states
Nov 4, 2024
ca3a5a3
feat(list): Fix focusing
Nov 4, 2024
43ca104
fix(list): Fix styles for states
Nov 4, 2024
911b62a
feat(list): Add TestCafe tests
Nov 4, 2024
cd3f560
feat(list): Add test for 1st focused header
Nov 4, 2024
723cc9a
refactor(list): Refactor attach click event method
Nov 4, 2024
71c0744
fix(list): Fix testcafe tests
Nov 5, 2024
c3a7d29
feat(list): Make headers accessible by enter key
Nov 5, 2024
190ee37
fix(list): Fix tests
Nov 5, 2024
3bc48a7
feat(list): Add tests
Nov 5, 2024
5722499
fix(list): Fix testcafe tests
Nov 5, 2024
24c31f7
feat(list): Add onItemClick test
Nov 5, 2024
3b26836
fix(list): Fix teasts
Nov 5, 2024
72034a5
feat(list): Add etalons
Nov 5, 2024
bcfd099
refactor(list): Rename
Nov 5, 2024
43deca4
feat(etalons): Update
Nov 5, 2024
7a3e920
revert(pg)
Nov 6, 2024
1f7de6e
fix(list): Update styles to fix TestCafe tests
Nov 6, 2024
10038c0
feat(list): Update _activeStateUnit in runtime
Nov 6, 2024
88dd969
feat(list): Add tests for runtime
Nov 6, 2024
723ddb9
feat(etalons): Remove etalons to get new
Nov 6, 2024
8bcd8c5
feat(list): Add etalons
Nov 6, 2024
991c5a8
revert(pg)
Nov 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 52 additions & 35 deletions e2e/testcafe-devextreme/tests/editors/list/grouping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@ test('Grouped list appearance', async (t) => {

const list = new List('#container');

await t.click(list.getGroup(0).header);
await t.click(list.getGroup(2).header);
await t
.click(list.getItem(2).element)
.pressKey('down');

await testScreenshot(t, takeScreenshot, 'Grouped list with focused header.png', { element: '#container' });

await t
.click(list.getGroup(0).header)
.click(list.getGroup(2).header)
.click(list.getItem(4).element)
.hover(list.getGroup(1).header);

await testScreenshot(t, takeScreenshot, 'Grouped list appearance.png', { element: '#container' });

Expand All @@ -55,23 +64,28 @@ test('Grouped list appearance', async (t) => {
}).before(async () => createWidget('dxList', {
width: 300,
height: 800,
dataSource: [{
key: 'group_1',
items: ['item_1_1', 'item_1_2', 'item_1_3'],
expanded: false,
}, {
key: 'group_2',
items: [
{ text: 'item_2_1', disabled: true },
{ text: 'item_2_2', icon: 'home' },
{ text: 'item_2_3', showChevron: true, badge: 'item_2_3' },
{ text: 'item_2_4', badge: 'item_2_4' },
'item_2_5'],
}, {
key: 'group_3',
items: ['item_3_1', 'item_3_2', 'item_3_3'],
expanded: false,
}],
dataSource: [
{
key: 'group_1',
items: ['item_1_1', 'item_1_2', 'item_1_3'],
expanded: false,
},
{
key: 'group_2',
items: [
{ text: 'item_2_1', disabled: true },
{ text: 'item_2_2', icon: 'home' },
{ text: 'item_2_3', showChevron: true, badge: 'item_2_3' },
{ text: 'item_2_4', badge: 'item_2_4' },
'item_2_5',
],
},
{
key: 'group_3',
items: ['item_3_1', 'item_3_2', 'item_3_3'],
expanded: false,
},
],
collapsibleGroups: true,
grouped: true,
allowItemDeleting: true,
Expand All @@ -89,7 +103,9 @@ test('Grouped list appearance', async (t) => {

await t
.click(list.getGroup(0).header)
.click(list.getGroup(2).header);
.click(list.getGroup(2).header)
.click(list.getItem(4).element)
.hover(list.getGroup(1).header);

await testScreenshot(t, takeScreenshot, `Grouped list appearance with template. rtlEnabled=${rtlEnabled}.png`, { element: '#container' });

Expand All @@ -102,24 +118,25 @@ test('Grouped list appearance', async (t) => {
groupTemplate(data) {
const wrapper = $('<div>');

$(`<span>${data.key}</span>`)
.appendTo(wrapper);

$('<div>second row</div>')
.appendTo(wrapper);
$(`<span>${data.key}</span>`).appendTo(wrapper);
$('<div>second row</div>').appendTo(wrapper);

return wrapper;
},
dataSource: [{
key: 'One',
items: ['1_1', '1_2', '1_3'],
}, {
key: 'Two',
items: ['2_1', '2_2', '2_3'],
}, {
key: 'Three',
items: ['3_1', '3_2', '3_3'],
}],
dataSource: [
{
key: 'One',
items: ['1_1', '1_2', '1_3'],
},
{
key: 'Two',
items: ['2_1', '2_2', '2_3'],
},
{
key: 'Three',
items: ['3_1', '3_2', '3_3'],
},
],
collapsibleGroups: true,
grouped: true,
rtlEnabled,
Expand Down
9 changes: 9 additions & 0 deletions packages/devextreme-scss/scss/widgets/fluent/list/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,15 @@ $fluent-list-item-border: $fluent-list-item-border-width solid $list-border-colo
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();

&.dx-state-hover {
background-color: $list-item-hover-bg;
color: $list-item-hover-color;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ $generic-list-search-editor-height: round($generic-base-line-height * $generic-b
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ $material-list-searchbox-padding-top: $material-list-searchbox-vertical-padding
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();

&.dx-state-hover {
background-color: $list-item-hover-bg;
color: $list-item-hover-color;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ const CollectionWidget = Widget.inherit({
});
},

_getHandlerExtendedParams(e, target) {
const params = extend({}, e, {
target: target.get(0),
currentTarget: target.get(0),
});

return params;
},

_enterKeyHandler(e) {
const $itemElement = $(this.option('focusedElement'));

Expand All @@ -99,10 +108,7 @@ const CollectionWidget = Widget.inherit({
});
}

this._itemClickHandler(extend({}, e, {
target: $itemElement.get(0),
currentTarget: $itemElement.get(0),
}));
this._itemClickHandler(this._getHandlerExtendedParams(e, $itemElement));
},

_getDefaultOptions() {
Expand Down
116 changes: 95 additions & 21 deletions packages/devextreme/js/__internal/ui/list/m_list.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,16 +286,40 @@ export const ListBase = CollectionWidget.inherit({
},

_refreshItemElements() {
if (!this.option('grouped')) {
this._itemElementsCache = this._getItemsContainer().children(this._itemSelector());
} else {
this._itemElementsCache = this._getItemsContainer()
const { grouped } = this.option();
const $itemsContainer = this._getItemsContainer();

if (grouped) {
this._itemElementsCache = $itemsContainer
.children(`.${LIST_GROUP_CLASS}`)
.children(`.${LIST_GROUP_BODY_CLASS}`)
.children(this._itemSelector());
} else {
this._itemElementsCache = $itemsContainer.children(this._itemSelector());
}
},

_getItemAndHeaderElements() {
const itemSelector = `> .${LIST_GROUP_BODY_CLASS} > ${this._itemSelector()}`;
const itemAndHeaderSelector = `${itemSelector}, > .${LIST_GROUP_HEADER_CLASS}`;

const $listGroup = this._getItemsContainer().children(`.${LIST_GROUP_CLASS}`);

const $items = $listGroup.find(itemAndHeaderSelector).filter(':visible');

return $items;
},

_getAvailableItems($itemElements) {
const { collapsibleGroups } = this.option();

if (collapsibleGroups) {
return this._getItemAndHeaderElements();
}

return this.callBase($itemElements);
},

_modifyByChanges() {
this.callBase.apply(this, arguments);

Expand Down Expand Up @@ -344,7 +368,23 @@ export const ListBase = CollectionWidget.inherit({
return true;
},

_updateActiveStateUnit(): void {
const { collapsibleGroups } = this.option();

const selectors = [
LIST_ITEM_SELECTOR,
SELECT_ALL_ITEM_SELECTOR,
];

if (collapsibleGroups) {
selectors.push(`.${LIST_GROUP_HEADER_CLASS}`);
}

this._activeStateUnit = selectors.join(',');
},

_init() {
this._updateActiveStateUnit();
this.callBase();
this._dataController.resetDataSourcePageIndex();
this._$container = this.$element();
Expand Down Expand Up @@ -605,31 +645,62 @@ export const ListBase = CollectionWidget.inherit({
},

_attachGroupCollapseEvent() {
const eventName = addNamespace(clickEventName, this.NAME);
const selector = `.${LIST_GROUP_HEADER_CLASS}`;
const { collapsibleGroups } = this.option();

const eventNameClick = addNamespace(clickEventName, this.NAME);
const headerSelector = `.${LIST_GROUP_HEADER_CLASS}`;

const $element = this.$element();
const collapsibleGroups = this.option('collapsibleGroups');

$element.toggleClass(LIST_COLLAPSIBLE_GROUPS_CLASS, collapsibleGroups);

eventsEngine.off($element, eventName, selector);
eventsEngine.off($element, eventNameClick, headerSelector);

if (collapsibleGroups) {
eventsEngine.on($element, eventName, selector, (e) => {
this._createAction((e) => {
const $group = $(e.event.currentTarget).parent();
this._collapseGroupHandler($group);
if (this.option('focusStateEnabled')) {
this.option('focusedElement', getPublicElement($group.find(`.${LIST_ITEM_CLASS}`).eq(0)));
}
}, {
validatingTargetName: 'element',
})({
event: e,
});
eventsEngine.on($element, eventNameClick, headerSelector, (e) => {
this._processGroupCollapse(e);
});
}
},

_processGroupCollapse(e): void {
const actionCallback = (e) => {
const { focusStateEnabled } = this.option();
const $group = $(e.event.currentTarget).parent();

this._collapseGroupHandler($group);

if (focusStateEnabled) {
const listItemElement = getPublicElement($group.find(`.${LIST_ITEM_CLASS}`).eq(0));

this.option({ focusedElement: listItemElement });
}
};

const actionParams = {
validatingTargetName: 'element',
};

const action = this._createAction(actionCallback, actionParams);

action({ event: e });
},

_enterKeyHandler(e): void {
const { collapsibleGroups, focusedElement } = this.option();
const isGroupHeader = $(focusedElement).hasClass(LIST_GROUP_HEADER_CLASS);
ksercs marked this conversation as resolved.
Show resolved Hide resolved

if (collapsibleGroups && isGroupHeader) {
const params = this._getHandlerExtendedParams(e, $(focusedElement));

this._processGroupCollapse(params);

return;
}

this.callBase(e);
},

_collapseGroupHandler($group, toggle) {
const deferred = Deferred();

Expand Down Expand Up @@ -978,10 +1049,13 @@ export const ListBase = CollectionWidget.inherit({
this._createScrollViewActions();
break;
case 'grouped':
case 'collapsibleGroups':
case 'groupTemplate':
this._invalidate();
break;
case 'collapsibleGroups':
this._updateActiveStateUnit();
this._invalidate();
break;
case 'wrapItemText':
this._toggleWrapItemText(args.value);
break;
Expand Down
Loading
Loading