-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathselection.model.ts
More file actions
144 lines (131 loc) · 4.86 KB
/
selection.model.ts
File metadata and controls
144 lines (131 loc) · 4.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { atomFactory, ComputedAtom, DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main";
import { DynamicValue } from "mendix";
import { computed, observable } from "mobx";
type Item = { id: string };
type Selection = { type: "Single" } | { type: "Multi"; selection: Item[] };
/**
* Returns selected count in multi-selection mode and -1 otherwise.
* @injectable
*/
export function selectedCountMultiAtom(
gate: DerivedPropsGate<{
itemSelection?: Selection;
}>
): ComputedAtom<number> {
return computed(() => {
const { itemSelection } = gate.props;
if (itemSelection?.type === "Multi") {
return itemSelection.selection.length;
}
return -1;
});
}
/** Returns true if all available items selected. */
export function isAllItemsSelected(
selectedCount: number,
itemCount: number,
totalCount: number,
isAllItemsPresent: boolean
): boolean {
if (selectedCount < 1) return false;
if (totalCount > 0) return selectedCount === totalCount;
if (isAllItemsPresent) return selectedCount === itemCount;
return false;
}
/** @injectable */
export const isAllItemsSelectedAtom = atomFactory(
(
selectedCount: ComputedAtom<number>,
itemCount: ComputedAtom<number>,
totalCount: ComputedAtom<number>,
isAllItemsPresent: ComputedAtom<boolean>
): Parameters<typeof isAllItemsSelected> => {
return [selectedCount.get(), itemCount.get(), totalCount.get(), isAllItemsPresent.get()];
},
isAllItemsSelected
);
/** Return true if all items on current page selected. */
export function isCurrentPageSelected(selection: Item[], items: Item[]): boolean {
const pageIds = new Set(items.map(item => item.id));
const selectionSubArray = selection.filter(item => pageIds.has(item.id));
return selectionSubArray.length === pageIds.size && pageIds.size > 0;
}
/**
* Atom returns true if all *loaded* items are selected.
* @injectable
*/
export function isCurrentPageSelectedAtom(
gate: DerivedPropsGate<{
itemSelection?: Selection;
datasource: { items?: Item[] };
}>
): ComputedAtom<boolean> {
return computed(() => {
// Read props first to track changes
const selection = gate.props.itemSelection;
const items = gate.props.datasource.items ?? [];
if (!selection || selection.type === "Single") return false;
return isCurrentPageSelected(selection.selection, items);
});
}
interface ObservableSelectorTexts {
clearSelectionButtonLabel: string;
selectedCountText: string;
}
export function selectionCounterTextsStore(
gate: DerivedPropsGate<{
clearSelectionButtonLabel?: DynamicValue<string>;
selectedCountTemplateSingular?: DynamicValue<string>;
selectedCountTemplatePlural?: DynamicValue<string>;
}>,
selectedCount: ComputedAtom<number>
): ObservableSelectorTexts {
return observable({
get clearSelectionButtonLabel() {
return gate.props.clearSelectionButtonLabel?.value || "Clear selection";
},
get selectedCountText() {
const formatSingular = gate.props.selectedCountTemplateSingular?.value || "%d item selected";
const formatPlural = gate.props.selectedCountTemplatePlural?.value || "%d items selected";
const count = selectedCount.get();
if (count > 1) return formatPlural.replace("%d", `${count}`);
if (count === 1) return formatSingular.replace("%d", "1");
return "";
}
});
}
export interface ObservableSelectAllTexts {
selectionStatus: string;
selectAllLabel: string;
}
/** @injectable */
export function selectAllTextsStore(
gate: DerivedPropsGate<{
allSelectedText?: DynamicValue<string>;
selectAllTemplate?: DynamicValue<string>;
selectAllText?: DynamicValue<string>;
}>,
selectedCount: ComputedAtom<number>,
selectedTexts: { selectedCountText: string },
totalCount: ComputedAtom<number>,
isAllItemsSelected: ComputedAtom<boolean>
): ObservableSelectAllTexts {
return observable({
get selectAllLabel() {
const selectAllFormat = gate.props.selectAllTemplate?.value || "Select all %d rows in the data source";
const selectAllText = gate.props.selectAllText?.value || "Select all rows in the data source";
const total = totalCount.get();
if (total > 0) return selectAllFormat.replace("%d", `${total}`);
return selectAllText;
},
get selectionStatus() {
if (isAllItemsSelected.get()) return this.allSelectedText;
return selectedTexts.selectedCountText;
},
get allSelectedText() {
const str = gate.props.allSelectedText?.value ?? "All %d rows selected.";
const count = selectedCount.get();
return str.replace("%d", `${count}`);
}
});
}