Skip to content

Commit ca38ce3

Browse files
committed
feat(nested): add trunk select strategy
closes #6759
1 parent d120266 commit ca38ce3

File tree

4 files changed

+90
-2
lines changed

4 files changed

+90
-2
lines changed

packages/api-generator/src/locale/en/nested.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
"opened": "An array containing the values of currently opened groups. Can be two-way bound with `v-model:opened`.",
66
"openStrategy": "Affects how items with children behave when expanded.\n- **multiple:** Any number of groups can be open at once.\n- **single:** Only one group at each level can be open, opening a group will cause others to close.\n- **list:** Multiple, but all other groups will close when an item is selected.",
77
"selected": "An array containing the values of currently selected items. Can be two-way bound with `v-model:selected`.",
8-
"selectStrategy": "Affects how items with children behave when selected.\n- **leaf:** Only leaf nodes (items without children) can be selected.\n- **independent:** All nodes can be selected whether they have children or not.\n- **classic:** Selecting a parent node will cause all children to be selected, parent nodes will be displayed as selected if all their descendants are selected. Only leaf nodes will be added to the model."
8+
"selectStrategy": "Affects how items with children behave when selected.\n- **leaf:** Only leaf nodes (items without children) can be selected.\n- **independent:** All nodes can be selected whether they have children or not.\n- **classic:** Selecting a parent node will cause all children to be selected, parent nodes will be displayed as selected if all their descendants are selected. Only leaf nodes will be added to the model.\n- **trunk**: Same as classic but if all of a node's children are selected then only that node will be added to the model."
99
}
1010
}

packages/vuetify/src/composables/nested/__tests__/selectStrategies.spec.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
/* eslint-disable max-len */
22
/* eslint-disable sonarjs/no-identical-functions */
33
// Utilities
4-
import { classicSelectStrategy, independentSelectStrategy, independentSingleSelectStrategy, leafSelectStrategy, leafSingleSelectStrategy } from '../selectStrategies'
4+
import {
5+
classicSelectStrategy,
6+
independentSelectStrategy,
7+
independentSingleSelectStrategy,
8+
leafSelectStrategy,
9+
leafSingleSelectStrategy,
10+
trunkSelectStrategy,
11+
} from '../selectStrategies'
512

613
describe('selectStrategies', () => {
714
describe('independent', () => {
@@ -732,4 +739,56 @@ describe('selectStrategies', () => {
732739
]))
733740
})
734741
})
742+
743+
describe('trunk', () => {
744+
it('selects individual leaves', () => {
745+
const strategy = trunkSelectStrategy(false)
746+
747+
const value = new Map([
748+
['1', 'indeterminate'],
749+
['2', 'on'],
750+
['3', 'indeterminate'],
751+
['4', 'on'],
752+
] as const)
753+
754+
const children = new Map([
755+
['1', ['2', '3']],
756+
['3', ['4', '5']],
757+
])
758+
759+
const parents = new Map([
760+
['2', '1'],
761+
['3', '1'],
762+
['4', '3'],
763+
['5', '3'],
764+
])
765+
766+
expect(strategy.out(value, children, parents)).toEqual(['2', '4'])
767+
})
768+
769+
it('selects a parent node', () => {
770+
const strategy = trunkSelectStrategy(false)
771+
772+
const value = new Map([
773+
['1', 'indeterminate'],
774+
['3', 'on'],
775+
['4', 'on'],
776+
['5', 'on'],
777+
] as const)
778+
779+
const children = new Map([
780+
['1', ['2', '3']],
781+
['3', ['4', '5']],
782+
])
783+
784+
const parents = new Map([
785+
['2', '1'],
786+
['3', '1'],
787+
['4', '3'],
788+
['5', '3'],
789+
])
790+
791+
expect(strategy.out(value, children, parents)).toEqual(['3'])
792+
})
793+
})
735794
})

packages/vuetify/src/composables/nested/nested.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
independentSingleSelectStrategy,
2727
leafSelectStrategy,
2828
leafSingleSelectStrategy,
29+
trunkSelectStrategy,
2930
} from './selectStrategies'
3031
import { consoleError, getCurrentInstance, propsFactory } from '@/util'
3132

@@ -49,6 +50,7 @@ export type SelectStrategyProp =
4950
| 'independent'
5051
| 'single-independent'
5152
| 'classic'
53+
| 'trunk'
5254
| SelectStrategy
5355
| ((mandatory: boolean) => SelectStrategy)
5456
export type OpenStrategyProp = 'single' | 'multiple' | 'list' | OpenStrategy
@@ -154,6 +156,7 @@ export const useNested = (props: NestedProps) => {
154156
case 'leaf': return leafSelectStrategy(props.mandatory)
155157
case 'independent': return independentSelectStrategy(props.mandatory)
156158
case 'single-independent': return independentSingleSelectStrategy(props.mandatory)
159+
case 'trunk': return trunkSelectStrategy(props.mandatory)
157160
case 'classic':
158161
default: return classicSelectStrategy(props.mandatory)
159162
}

packages/vuetify/src/composables/nested/selectStrategies.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,29 @@ export const classicSelectStrategy = (mandatory?: boolean): SelectStrategy => {
209209

210210
return strategy
211211
}
212+
213+
export const trunkSelectStrategy = (mandatory?: boolean): SelectStrategy => {
214+
const parentStrategy = classicSelectStrategy(mandatory)
215+
216+
const strategy: SelectStrategy = {
217+
select: parentStrategy.select,
218+
in: parentStrategy.in,
219+
out: (v, children, parents) => {
220+
const arr = []
221+
222+
for (const [key, value] of v.entries()) {
223+
if (value === 'on') {
224+
if (parents.has(key)) {
225+
const parent = parents.get(key)
226+
if (v.get(parent) === 'on') continue
227+
}
228+
arr.push(key)
229+
}
230+
}
231+
232+
return arr
233+
},
234+
}
235+
236+
return strategy
237+
}

0 commit comments

Comments
 (0)