Skip to content

Commit b1daaef

Browse files
committed
feat: add aria live in dg footer
1 parent 57fa67f commit b1daaef

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 { useDatagridConfig, usePaginationService, useTexts } from "../model/hooks/injection-hooks";
@@ -14,6 +15,9 @@ export const WidgetFooter = observer(function WidgetFooter(): ReactElement {
1415

1516
return (
1617
<div className="widget-datagrid-footer table-footer">
18+
<If condition={config.selectionEnabled}>
19+
<SelectionAriaLive />
20+
</If>
1721
<div className="widget-datagrid-paging-bottom">
1822
<div className="widget-datagrid-pb-start">
1923
<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";
@@ -47,6 +48,14 @@ injected(selectedCountMultiAtom, CORE.mainGate);
4748
injected(selectionCounterTextsStore, CORE.mainGate, CORE.selection.selectedCount);
4849
injected(PageSizeStore, CORE.initPageSize.optional);
4950

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

@@ -82,6 +91,7 @@ export class RootContainer extends Container {
8291
this.bind(CORE.selection.selectedCounterTextsStore).toInstance(selectionCounterTextsStore).inTransientScope();
8392
this.bind(CORE.selection.isAllItemsSelected).toInstance(isAllItemsSelectedAtom).inTransientScope();
8493
this.bind(CORE.texts).toInstance(TextsService).inTransientScope();
94+
this.bind(CORE.selection.selectAllTexts).toInstance(selectAllTextsStore).inTransientScope();
8595

8696
// paging
8797
this.bind(CORE.atoms.pageSize).toInstance(pageSizeAtom).inTransientScope();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ export const [useClickActionHelper] = createInjectionHooks(DG.clickActionHelper)
2424
export const [useFocusService] = createInjectionHooks(DG.focusService);
2525
export const [useCheckboxEventsHandler] = createInjectionHooks(DG.checkboxEventsHandler);
2626
export const [useCellEventsHandler] = createInjectionHooks(DG.cellEventsHandler);
27+
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,
@@ -13,11 +14,7 @@ import {
1314
TaskProgressService
1415
} from "@mendix/widget-plugin-grid/main";
1516
import { SelectAllFeature } from "@mendix/widget-plugin-grid/select-all/select-all.feature";
16-
import {
17-
BarStore,
18-
ObservableSelectAllTexts,
19-
SelectAllEvents
20-
} from "@mendix/widget-plugin-grid/select-all/select-all.model";
17+
import { BarStore, SelectAllEvents } from "@mendix/widget-plugin-grid/select-all/select-all.model";
2118
import { SelectionCounterViewModel } from "@mendix/widget-plugin-grid/selection-counter/SelectionCounter.viewModel-atoms";
2219
import { ComputedAtom, DerivedPropsGate, Emitter } from "@mendix/widget-plugin-mobx-kit/main";
2320
import { token } from "brandi";
@@ -75,7 +72,8 @@ export const CORE_TOKENS = {
7572
selectedCounterTextsStore: token<{
7673
clearSelectionButtonLabel: string;
7774
selectedCountText: string;
78-
}>("@store:selectedCounterTextsStore")
75+
}>("@store:selectedCounterTextsStore"),
76+
selectAllTexts: token<ObservableSelectAllTexts>("@store:SelectAllTexts")
7977
},
8078

8179
setupService: token<DatagridSetupService>("DatagridSetupService"),
@@ -140,7 +138,6 @@ export const SA_TOKENS = {
140138
emitter: token<Emitter<SelectAllEvents>>("SelectAllEmitter"),
141139
gate: token<DerivedPropsGate<MainGateProps>>("MainGateForSelectAllContainer"),
142140
progressService: token<TaskProgressService>("SelectAllProgressService"),
143-
selectAllTextsStore: token<ObservableSelectAllTexts>("SelectAllTextsStore"),
144141
selectAllBarVM: token<SelectAllBarViewModel>("SelectAllBarViewModel"),
145142
selectAllService: token<SelectAllService>("SelectAllService"),
146143
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)