Skip to content

Commit 0079fe9

Browse files
committed
feat: add aria live in dg footer
1 parent be0f275 commit 0079fe9

11 files changed

Lines changed: 76 additions & 69 deletions

File tree

packages/pluggableWidgets/datagrid-web/src/components/WidgetFooter.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { If } from "@mendix/widget-plugin-component-kit/If";
22
import { observer } from "mobx-react-lite";
33
import { ReactElement } from "react";
4+
import { SelectionAriaLive } from "../features/selection-counter/SelectionAriaLive";
45
import { SelectionCounter } from "../features/selection-counter/SelectionCounter";
56
import { useSelectionCounterViewModel } from "../features/selection-counter/injection-hooks";
67
import { useCustomPagination, usePaginationConfig, usePaginationVM, useTexts } from "../model/hooks/injection-hooks";
@@ -25,6 +26,9 @@ export const WidgetFooter = observer(function WidgetFooter(): ReactElement | nul
2526

2627
return (
2728
<div className="widget-datagrid-footer table-footer">
29+
<If condition={config.selectionEnabled}>
30+
<SelectionAriaLive />
31+
</If>
2832
<div className="widget-datagrid-paging-bottom">
2933
<div className="widget-datagrid-pb-start">
3034
<If condition={selectionCounterVM.isBottomCounterVisible}>

packages/pluggableWidgets/datagrid-web/src/features/select-all/SelectAllModule.container.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-
44
import { Container, injected } from "brandi";
55

66
import { SelectAllFeature } from "@mendix/widget-plugin-grid/select-all/select-all.feature";
7-
import { selectAllEmitter, selectAllTextsStore } from "@mendix/widget-plugin-grid/select-all/select-all.model";
7+
import { selectAllEmitter } from "@mendix/widget-plugin-grid/select-all/select-all.model";
88
import { SelectAllBarStore } from "@mendix/widget-plugin-grid/select-all/SelectAllBar.store";
99
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main";
1010
import { MainGateProps } from "../../../typings/MainGateProps";
@@ -13,21 +13,12 @@ import { CORE_TOKENS as CORE, DG_TOKENS as DG, SA_TOKENS } from "../../model/tok
1313
import { SelectAllBarViewModel } from "./SelectAllBar.viewModel";
1414
import { SelectionProgressDialogViewModel } from "./SelectionProgressDialog.viewModel";
1515

16-
injected(
17-
selectAllTextsStore,
18-
SA_TOKENS.gate,
19-
CORE.selection.selectedCount,
20-
CORE.selection.selectedCounterTextsStore,
21-
CORE.atoms.totalCount,
22-
CORE.selection.isAllItemsSelected
23-
);
24-
2516
injected(
2617
SelectAllBarViewModel,
2718
SA_TOKENS.emitter,
2819
SA_TOKENS.barStore,
2920
CORE.selection.selectedCounterTextsStore,
30-
SA_TOKENS.selectAllTextsStore,
21+
CORE.selection.selectAllTexts,
3122
SA_TOKENS.enableSelectAll
3223
);
3324

@@ -62,7 +53,6 @@ export class SelectAllModule extends Container {
6253
this.bind(SA_TOKENS.emitter).toInstance(selectAllEmitter).inSingletonScope();
6354
this.bind(DG.query).toInstance(DatasourceService).inSingletonScope();
6455
this.bind(SA_TOKENS.selectAllService).toInstance(SelectAllService).inSingletonScope();
65-
this.bind(SA_TOKENS.selectAllTextsStore).toInstance(selectAllTextsStore).inSingletonScope();
6656
this.bind(SA_TOKENS.selectAllBarVM).toInstance(SelectAllBarViewModel).inSingletonScope();
6757
this.bind(SA_TOKENS.selectionDialogVM).toInstance(SelectionProgressDialogViewModel).inSingletonScope();
6858
this.bind(SA_TOKENS.feature).toInstance(SelectAllFeature).inSingletonScope();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { observer } from "mobx-react-lite";
2+
import { useSelectionCounterTexts } from "./injection-hooks";
3+
4+
export const SelectionAriaLive = observer(function SelectionAriaLive() {
5+
const texts = useSelectionCounterTexts();
6+
7+
return (
8+
<span className="sr-only" aria-live="polite" aria-atomic="true">
9+
{texts.selectedCountText}
10+
</span>
11+
);
12+
});

packages/pluggableWidgets/datagrid-web/src/features/selection-counter/SelectionCounter.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ export const SelectionCounter = observer(function SelectionCounter() {
88

99
return (
1010
<div className="widget-datagrid-selection-counter">
11-
<span className="widget-datagrid-selection-text" aria-live="polite" aria-atomic="true">
12-
{selectionCountStore.selectedCountText}
13-
</span>
11+
<span className="widget-datagrid-selection-text">{selectionCountStore.selectedCountText}</span>
1412
&nbsp;|&nbsp;
1513
<button className="widget-datagrid-btn-link" onClick={() => selectActions.clearSelection()}>
1614
{selectionCountStore.clearButtonLabel}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createInjectionHooks } from "brandi-react";
2-
import { DG_TOKENS } from "../../model/tokens";
2+
import { CORE_TOKENS, DG_TOKENS } from "../../model/tokens";
33

44
export const [useSelectionCounterViewModel] = createInjectionHooks(DG_TOKENS.selectionCounterVM);
5+
export const [useSelectionCounterTexts] = createInjectionHooks(CORE_TOKENS.selection.selectedCounterTextsStore);

packages/pluggableWidgets/datagrid-web/src/model/containers/Root.container.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
isAllItemsSelectedAtom,
1111
isCurrentPageSelectedAtom,
12+
selectAllTextsStore,
1213
selectedCountMultiAtom,
1314
selectionCounterTextsStore
1415
} from "@mendix/widget-plugin-grid/core/models/selection.model";
@@ -46,6 +47,14 @@ injected(selectedCountMultiAtom, CORE.mainGate);
4647
injected(selectionCounterTextsStore, CORE.mainGate, CORE.selection.selectedCount);
4748
injected(PageSizeStore, CORE.initPageSize.optional);
4849

50+
injected(
51+
selectAllTextsStore,
52+
CORE.mainGate,
53+
CORE.selection.selectedCount,
54+
CORE.selection.selectedCounterTextsStore,
55+
CORE.atoms.totalCount,
56+
CORE.selection.isAllItemsSelected
57+
);
4958
// other
5059
injected(TextsService, CORE.mainGate);
5160

@@ -81,6 +90,7 @@ export class RootContainer extends Container {
8190
this.bind(CORE.selection.selectedCounterTextsStore).toInstance(selectionCounterTextsStore).inTransientScope();
8291
this.bind(CORE.selection.isAllItemsSelected).toInstance(isAllItemsSelectedAtom).inTransientScope();
8392
this.bind(CORE.texts).toInstance(TextsService).inTransientScope();
93+
this.bind(CORE.selection.selectAllTexts).toInstance(selectAllTextsStore).inTransientScope();
8494

8595
// paging
8696
this.bind(CORE.pageSizeStore).toInstance(PageSizeStore).inSingletonScope();

packages/pluggableWidgets/datagrid-web/src/model/hooks/injection-hooks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ export const [useCheckboxEventsHandler] = createInjectionHooks(DG.checkboxEvents
2727
export const [useCellEventsHandler] = createInjectionHooks(DG.cellEventsHandler);
2828
export const [useCustomPagination] = createInjectionHooks(DG.customPagination);
2929
export const [usePaginationConfig] = createInjectionHooks(DG.paginationConfig);
30+
export const [useSelectAllTexts] = createInjectionHooks(CORE.selection.selectAllTexts);

packages/pluggableWidgets/datagrid-web/src/model/tokens.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ClickActionHelper } from "@mendix/widget-plugin-grid/helpers/ClickActio
55
import { FocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/FocusTargetController";
66
import { VirtualGridLayout } from "@mendix/widget-plugin-grid/keyboard-navigation/VirtualGridLayout";
77
import {
8+
ObservableSelectAllTexts,
89
QueryService,
910
SelectActionsService,
1011
SelectAllService,
@@ -14,11 +15,7 @@ import {
1415
TaskProgressService
1516
} from "@mendix/widget-plugin-grid/main";
1617
import { SelectAllFeature } from "@mendix/widget-plugin-grid/select-all/select-all.feature";
17-
import {
18-
BarStore,
19-
ObservableSelectAllTexts,
20-
SelectAllEvents
21-
} from "@mendix/widget-plugin-grid/select-all/select-all.model";
18+
import { BarStore, SelectAllEvents } from "@mendix/widget-plugin-grid/select-all/select-all.model";
2219
import { SelectionCounterViewModel } from "@mendix/widget-plugin-grid/selection-counter/SelectionCounter.viewModel-atoms";
2320
import { ComputedAtom, DerivedPropsGate, Emitter } from "@mendix/widget-plugin-mobx-kit/main";
2421
import { token } from "brandi";
@@ -79,7 +76,8 @@ export const CORE_TOKENS = {
7976
selectedCounterTextsStore: token<{
8077
clearSelectionButtonLabel: string;
8178
selectedCountText: string;
82-
}>("@store:selectedCounterTextsStore")
79+
}>("@store:selectedCounterTextsStore"),
80+
selectAllTexts: token<ObservableSelectAllTexts>("@store:SelectAllTexts")
8381
},
8482

8583
setupService: token<DatagridSetupService>("DatagridSetupService"),
@@ -155,7 +153,6 @@ export const SA_TOKENS = {
155153
emitter: token<Emitter<SelectAllEvents>>("SelectAllEmitter"),
156154
gate: token<DerivedPropsGate<MainGateProps>>("MainGateForSelectAllContainer"),
157155
progressService: token<TaskProgressService>("SelectAllProgressService"),
158-
selectAllTextsStore: token<ObservableSelectAllTexts>("SelectAllTextsStore"),
159156
selectAllBarVM: token<SelectAllBarViewModel>("SelectAllBarViewModel"),
160157
selectAllService: token<SelectAllService>("SelectAllService"),
161158
selectionDialogVM: token<SelectionProgressDialogViewModel>("SelectionProgressDialogViewModel"),

packages/shared/widget-plugin-grid/src/core/models/selection.model.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,40 @@ export function selectionCounterTextsStore(
105105
}
106106
});
107107
}
108+
109+
export interface ObservableSelectAllTexts {
110+
selectionStatus: string;
111+
selectAllLabel: string;
112+
}
113+
114+
/** @injectable */
115+
export function selectAllTextsStore(
116+
gate: DerivedPropsGate<{
117+
allSelectedText?: DynamicValue<string>;
118+
selectAllTemplate?: DynamicValue<string>;
119+
selectAllText?: DynamicValue<string>;
120+
}>,
121+
selectedCount: ComputedAtom<number>,
122+
selectedTexts: { selectedCountText: string },
123+
totalCount: ComputedAtom<number>,
124+
isAllItemsSelected: ComputedAtom<boolean>
125+
): ObservableSelectAllTexts {
126+
return observable({
127+
get selectAllLabel() {
128+
const selectAllFormat = gate.props.selectAllTemplate?.value || "Select all %d rows in the data source";
129+
const selectAllText = gate.props.selectAllText?.value || "Select all rows in the data source";
130+
const total = totalCount.get();
131+
if (total > 0) return selectAllFormat.replace("%d", `${total}`);
132+
return selectAllText;
133+
},
134+
get selectionStatus() {
135+
if (isAllItemsSelected.get()) return this.allSelectedText;
136+
return selectedTexts.selectedCountText;
137+
},
138+
get allSelectedText() {
139+
const str = gate.props.allSelectedText?.value ?? "All %d rows selected.";
140+
const count = selectedCount.get();
141+
return str.replace("%d", `${count}`);
142+
}
143+
});
144+
}

packages/shared/widget-plugin-grid/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { DatasourceService } from "./core/Datasource.service";
2+
export * from "./core/models/selection.model";
23
export { ProgressService } from "./core/Progress.service";
34
export { createClickActionHelper } from "./helpers/createClickActionHelper";
45
export type { QueryService } from "./interfaces/QueryService";

0 commit comments

Comments
 (0)