@instructure/ui-drilldown 8.32.1 → 8.32.2-snapshot-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,7 +57,6 @@ import { withStyle, jsx } from '@instructure/emotion'
57
57
 
58
58
  import { DrilldownSeparator } from './DrilldownSeparator'
59
59
  import { DrilldownOption } from './DrilldownOption'
60
- import type { DrilldownOptionValue } from './DrilldownOption/props'
61
60
  import { DrilldownGroup } from './DrilldownGroup'
62
61
  import type { DrilldownGroupProps, GroupChildren } from './DrilldownGroup/props'
63
62
  import { DrilldownPage } from './DrilldownPage'
@@ -66,7 +65,7 @@ import type { DrilldownPageProps, PageChildren } from './DrilldownPage/props'
66
65
  import generateStyle from './styles'
67
66
  import generateComponentTheme from './theme'
68
67
 
69
- import { propTypes, allowedProps } from './props'
68
+ import { propTypes, allowedProps, SelectedGroupOptionsMap } from './props'
70
69
 
71
70
  import type {
72
71
  DrilldownProps,
@@ -97,9 +96,6 @@ type MappedPage = DrilldownPageProps & {
97
96
  // An object with the mapped Pages with their id as keys
98
97
  type PageMap = Record<string, MappedPage>
99
98
 
100
- // A Map width the selected options in a group, with the id as key and their value
101
- type SelectedGroupOptionsMap = Map<string, DrilldownOptionValue>
102
-
103
99
  /**
104
100
  ---
105
101
  category: components
@@ -157,9 +153,6 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
157
153
  } = {}
158
154
 
159
155
  // Map of the selected options in groups (grouped by group id)
160
- _selectedGroupOptionsMap: {
161
- [groupId: string]: SelectedGroupOptionsMap
162
- } = {}
163
156
 
164
157
  ref: HTMLDivElement | Element | null = null
165
158
 
@@ -197,13 +190,11 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
197
190
  isShowingPopover: props.trigger ? !!props.show : false,
198
191
  activePageId: props.rootPageId,
199
192
  highlightedOptionId: undefined,
200
- lastSelectedId: undefined
193
+ lastSelectedId: undefined,
194
+ selectedGroupOptionsMap: this.setDefaultSelected()
201
195
  }
202
-
203
196
  this._pageHistory = [props.rootPageId]
204
197
 
205
- this.setDefaultSelected()
206
-
207
198
  this._id = props.id || props.deterministicId!()
208
199
  this._triggerId = props.deterministicId!('Drilldown-Trigger')
209
200
  this._headerBackId = props.deterministicId!('DrilldownHeader-Back')
@@ -358,6 +349,8 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
358
349
  }
359
350
 
360
351
  setDefaultSelected() {
352
+ const selectedGroupOptionsMap: SelectedGroupOptionsMap = {}
353
+
361
354
  this.pages.forEach((page) => {
362
355
  const { children } = page.props
363
356
 
@@ -374,6 +367,10 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
374
367
  return
375
368
  }
376
369
 
370
+ if (selectableType && !selectedGroupOptionsMap[groupId]) {
371
+ selectedGroupOptionsMap[groupId] = new Map()
372
+ }
373
+
377
374
  if (selectableType === 'single' && groupDefaultSelected.length > 1) {
378
375
  error(
379
376
  false,
@@ -385,7 +382,7 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
385
382
  return
386
383
  }
387
384
 
388
- this._selectedGroupOptionsMap[groupId] = new Map()
385
+ selectedGroupOptionsMap[groupId] = new Map()
389
386
 
390
387
  this.getChildrenArray(groupChildren)?.forEach((groupChild) => {
391
388
  if (
@@ -409,20 +406,18 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
409
406
  .includes(optionValue)
410
407
 
411
408
  if (optionDefaultSelected || isGroupDefaultSelected) {
412
- this._selectedGroupOptionsMap[groupId].set(
413
- optionId,
414
- optionValue
415
- )
409
+ selectedGroupOptionsMap[groupId].set(optionId, optionValue)
416
410
  }
417
411
  }
418
412
  })
419
413
  }
420
414
  })
421
415
  })
416
+ return selectedGroupOptionsMap
422
417
  }
423
418
 
424
419
  get selectedGroupOptionIdsArray() {
425
- return Object.values(this._selectedGroupOptionsMap)
420
+ return Object.values(this.state.selectedGroupOptionsMap)
426
421
  .map((groupIdMap) => Array.from(groupIdMap.keys()))
427
422
  .flat()
428
423
  }
@@ -718,54 +713,67 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
718
713
  event: React.SyntheticEvent,
719
714
  selectedOption: MappedOption
720
715
  ) {
721
- const { id: optionId, value } = selectedOption.props
722
- const {
723
- id: groupId,
724
- selectableType,
725
- onSelect: groupOnSelect
726
- } = selectedOption.groupProps!
727
-
728
- const { onSelect } = this.props
716
+ this.setState(
717
+ (oldState) => {
718
+ const { id: optionId, value } = selectedOption.props
719
+ const { id: groupId, selectableType } = selectedOption.groupProps!
720
+
721
+ let newState = new Map(oldState.selectedGroupOptionsMap[groupId])
722
+
723
+ if (
724
+ selectableType === 'multiple' &&
725
+ Boolean(oldState.selectedGroupOptionsMap[groupId]?.has(optionId))
726
+ ) {
727
+ // toggle off, if already selected
728
+ newState.delete(optionId)
729
+ } else {
730
+ if (selectableType === 'multiple') {
731
+ // "checkbox"
732
+ newState.set(optionId, value)
733
+ } else if (selectableType === 'single') {
734
+ // "radio"
735
+ newState = new Map()
736
+ newState.set(optionId, value)
737
+ }
738
+ }
739
+ return {
740
+ ...oldState,
741
+ selectedGroupOptionsMap: {
742
+ ...oldState.selectedGroupOptionsMap,
743
+ [groupId]: newState
744
+ }
745
+ }
746
+ },
747
+ () => {
748
+ const { value } = selectedOption.props
749
+ const { id: groupId, onSelect: groupOnSelect } =
750
+ selectedOption.groupProps!
751
+
752
+ const { onSelect } = this.props
753
+ const { groupProps, ...option } = selectedOption
754
+ const selectedOptionValuesInGroup = [
755
+ ...this.state.selectedGroupOptionsMap[groupId].values()
756
+ ]
757
+
758
+ if (typeof groupOnSelect === 'function') {
759
+ groupOnSelect(event, {
760
+ value: selectedOptionValuesInGroup,
761
+ isSelected: selectedOptionValuesInGroup.includes(value),
762
+ selectedOption: option,
763
+ drilldown: this
764
+ })
765
+ }
729
766
 
730
- if (this._selectedGroupOptionsMap[groupId].has(optionId)) {
731
- // toggle off, if already selected
732
- this._selectedGroupOptionsMap[groupId].delete(optionId)
733
- } else {
734
- if (selectableType === 'multiple') {
735
- // "checkbox"
736
- this._selectedGroupOptionsMap[groupId].set(optionId, value)
737
- } else if (selectableType === 'single') {
738
- // "radio"
739
- this._selectedGroupOptionsMap[groupId] = new Map()
740
- this._selectedGroupOptionsMap[groupId].set(optionId, value)
767
+ if (typeof onSelect === 'function') {
768
+ onSelect(event, {
769
+ value: selectedOptionValuesInGroup,
770
+ isSelected: selectedOptionValuesInGroup.includes(value),
771
+ selectedOption: option,
772
+ drilldown: this
773
+ })
774
+ }
741
775
  }
742
- }
743
-
744
- // needed for rerender
745
- this.setState({ lastSelectedId: optionId })
746
-
747
- const { groupProps, ...option } = selectedOption
748
- const selectedOptionValuesInGroup = Array.from(
749
- this._selectedGroupOptionsMap[groupId].values()
750
776
  )
751
-
752
- if (typeof groupOnSelect === 'function') {
753
- groupOnSelect(event, {
754
- value: selectedOptionValuesInGroup,
755
- isSelected: this._selectedGroupOptionsMap[groupId].has(optionId),
756
- selectedOption: option,
757
- drilldown: this
758
- })
759
- }
760
-
761
- if (typeof onSelect === 'function') {
762
- onSelect(event, {
763
- value: selectedOptionValuesInGroup,
764
- isSelected: this._selectedGroupOptionsMap[groupId].has(optionId),
765
- selectedOption: option,
766
- drilldown: this
767
- })
768
- }
769
777
  }
770
778
 
771
779
  handleOptionSelect = (
@@ -1092,8 +1100,15 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
1092
1100
  if (id === this._headerBackId) {
1093
1101
  optionProps.renderBeforeLabel = <IconArrowOpenStartSolid />
1094
1102
  }
1095
- if (groupProps?.selectableType) {
1096
- isSelected = this._selectedGroupOptionsMap[groupProps.id].has(id)
1103
+ const isOptionControlled = typeof option.props.selected === 'boolean'
1104
+ if ((groupProps?.selectableType || isOptionControlled) && groupProps) {
1105
+ if (!isOptionControlled) {
1106
+ isSelected = Boolean(
1107
+ this.state.selectedGroupOptionsMap[groupProps.id]?.has(id)
1108
+ )
1109
+ } else {
1110
+ isSelected = Boolean(option.props.selected)
1111
+ }
1097
1112
  optionProps['aria-checked'] = isSelected
1098
1113
 
1099
1114
  optionProps.renderBeforeLabel = (
@@ -1103,6 +1118,7 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
1103
1118
  }}
1104
1119
  />
1105
1120
  )
1121
+
1106
1122
  warn(
1107
1123
  !renderBeforeLabel,
1108
1124
  `The prop "renderBeforeLabel" is reserved on item with id: "${id}". When this option is a selectable member of a Drilldown.Group, selection indicator will render before the label.`
@@ -1116,7 +1132,6 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
1116
1132
  optionProps.role = customRole || 'menuitemcheckbox'
1117
1133
  }
1118
1134
  }
1119
-
1120
1135
  // display option as highlighted
1121
1136
  if (id === this.state.highlightedOptionId) {
1122
1137
  optionProps.variant = 'highlighted'
@@ -1243,7 +1258,6 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
1243
1258
  children,
1244
1259
  renderGroupTitle,
1245
1260
  themeOverride,
1246
- selectableType,
1247
1261
  role,
1248
1262
  as,
1249
1263
  elementRef
@@ -1263,10 +1277,6 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
1263
1277
  groupChildren.push(<Options.Separator />)
1264
1278
  }
1265
1279
 
1266
- if (selectableType && !this._selectedGroupOptionsMap[id]) {
1267
- this._selectedGroupOptionsMap[id] = new Map()
1268
- }
1269
-
1270
1280
  // create a sublist as a group
1271
1281
  // (a wrapping list item will be created by Options)
1272
1282
  groupChildren.push(
@@ -286,12 +286,17 @@ type DrilldownStyleProps = {
286
286
  hasHighlightedOption: boolean
287
287
  }
288
288
 
289
+ type SelectedGroupOptionsMap = {
290
+ [groupId: string]: Map<string, DrilldownOptionValue>
291
+ }
292
+
289
293
  type DrilldownState = {
290
294
  isShowingPopover: boolean
291
295
  activePageId: string
292
296
  highlightedOptionId?: string
293
297
  // needed for rerender
294
298
  lastSelectedId?: string
299
+ selectedGroupOptionsMap: SelectedGroupOptionsMap
295
300
  }
296
301
 
297
302
  const propTypes: PropValidators<PropKeys> = {
@@ -388,6 +393,7 @@ export type {
388
393
  PageChild,
389
394
  GroupChild,
390
395
  OptionChild,
391
- SeparatorChild
396
+ SeparatorChild,
397
+ SelectedGroupOptionsMap
392
398
  }
393
399
  export { propTypes, allowedProps }