selection.ts 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Using '*' for uid will return true if anything is selected
  2. export type SelectionChecker = (kind: string, uid: string) => boolean;
  3. export type SelectionToggle = (kind: string, uid: string) => void;
  4. export interface SearchSelection {
  5. // Check if an item is selected
  6. isSelected: SelectionChecker;
  7. // Selected items by kind
  8. items: Map<string, Set<string>>;
  9. }
  10. export function newSearchSelection(): SearchSelection {
  11. // the check is called often, on potentially large (all) results so using Map/Set is better than simple array
  12. const items = new Map<string, Set<string>>();
  13. const isSelected = (kind: string, uid: string) => {
  14. return Boolean(items.get(kind)?.has(uid));
  15. };
  16. return {
  17. items,
  18. isSelected,
  19. };
  20. }
  21. export function updateSearchSelection(
  22. old: SearchSelection,
  23. selected: boolean,
  24. kind: string,
  25. uids: string[]
  26. ): SearchSelection {
  27. const items = old.items; // mutate! :/
  28. if (uids.length) {
  29. const k = items.get(kind);
  30. if (k) {
  31. for (const uid of uids) {
  32. if (selected) {
  33. k.add(uid);
  34. } else {
  35. k.delete(uid);
  36. }
  37. }
  38. if (k.size < 1) {
  39. items.delete(kind);
  40. }
  41. } else if (selected) {
  42. items.set(kind, new Set<string>(uids));
  43. }
  44. }
  45. return {
  46. items,
  47. isSelected: (kind: string, uid: string) => {
  48. if (uid === '*') {
  49. if (kind === '*') {
  50. for (const k of items.keys()) {
  51. if (items.get(k)?.size) {
  52. return true;
  53. }
  54. }
  55. return false;
  56. }
  57. return Boolean(items.get(kind)?.size);
  58. }
  59. return Boolean(items.get(kind)?.has(uid));
  60. },
  61. };
  62. }