diff --git a/plugins/board-resources/src/components/KanbanView.svelte b/plugins/board-resources/src/components/KanbanView.svelte index 424f78a4d7..06df18d6e7 100644 --- a/plugins/board-resources/src/components/KanbanView.svelte +++ b/plugins/board-resources/src/components/KanbanView.svelte @@ -38,7 +38,6 @@ groupBy, ListSelectionProvider, SelectDirection, - selectionStore, setGroupByValues } from '@hcengineering/view-resources' import { onMount } from 'svelte' @@ -100,6 +99,8 @@ ;(document.activeElement as HTMLElement)?.blur() }) + const selection = listProvider.selection + const showMenu = async (ev: MouseEvent, object: Doc): Promise<void> => { ev.preventDefault() if (object._class !== board.class.Card) { @@ -156,7 +157,7 @@ }} {groupByDocs} {getUpdateProps} - checked={$selectionStore ?? []} + checked={$selection ?? []} on:check={(evt) => { listProvider.updateSelection(evt.detail.docs, evt.detail.value) }} diff --git a/plugins/task-resources/src/components/kanban/KanbanView.svelte b/plugins/task-resources/src/components/kanban/KanbanView.svelte index da2de5ba98..37d90bd1f0 100644 --- a/plugins/task-resources/src/components/kanban/KanbanView.svelte +++ b/plugins/task-resources/src/components/kanban/KanbanView.svelte @@ -56,7 +56,6 @@ Menu, noCategory, SelectDirection, - selectionStore, setGroupByValues } from '@hcengineering/view-resources' import view from '@hcengineering/view-resources/src/plugin' @@ -113,6 +112,8 @@ const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { kanbanUI?.select(offset, of, dir) }) + const selection = listProvider.selection + onMount(() => { ;(document.activeElement as HTMLElement)?.blur() }) @@ -248,7 +249,7 @@ listProvider.updateFocus(evt.detail) }} selection={listProvider.current($focusStore)} - checked={$selectionStore ?? []} + checked={$selection ?? []} on:check={(evt) => { listProvider.updateSelection(evt.detail.docs, evt.detail.value) }} diff --git a/plugins/tracker-resources/src/components/issues/KanbanView.svelte b/plugins/tracker-resources/src/components/issues/KanbanView.svelte index e2cb890ef3..02a8155425 100644 --- a/plugins/tracker-resources/src/components/issues/KanbanView.svelte +++ b/plugins/tracker-resources/src/components/issues/KanbanView.svelte @@ -66,7 +66,6 @@ noCategory, openDoc, SelectDirection, - selectionStore, setGroupByValues } from '@hcengineering/view-resources' import view from '@hcengineering/view-resources/src/plugin' @@ -149,6 +148,8 @@ const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { kanbanUI?.select(offset, of, dir) }) + const selection = listProvider.selection + onMount(() => { ;(document.activeElement as HTMLElement)?.blur() }) @@ -288,7 +289,7 @@ listProvider.updateFocus(evt.detail) }} selection={listProvider.current($focusStore)} - checked={$selectionStore ?? []} + checked={$selection ?? []} on:check={(evt) => { listProvider.updateSelection(evt.detail.docs, evt.detail.value) }} diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte index 48df6e3b62..e4a5db476b 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte @@ -1,5 +1,5 @@ <!-- -// Copyright © 2022 Hardcore Engineering Inc. +// Copyright © 2022, 2023 Hardcore Engineering Inc. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. You may @@ -19,7 +19,7 @@ import { Issue } from '@hcengineering/tracker' import { AnyComponent, AnySvelteComponent, registerFocus } from '@hcengineering/ui' import { ViewOptions, Viewlet, ViewletPreference } from '@hcengineering/view' - import { List, ListSelectionProvider, SelectDirection, selectionStore } from '@hcengineering/view-resources' + import { List, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources' import { createEventDispatcher } from 'svelte' import tracker from '../../../plugin' @@ -47,6 +47,7 @@ listProvider.updateFocus(docs[0]) list?.select(0, undefined) } + const selection = listProvider.selection // Focusable control with index let focused = false @@ -88,7 +89,8 @@ {createItemDialog} {createItemDialogProps} {createItemLabel} - selectedObjectIds={$selectionStore ?? []} + {listProvider} + selectedObjectIds={$selection ?? []} {compactMode} on:row-focus={(event) => { listProvider.updateFocus(event.detail ?? undefined) diff --git a/plugins/view-resources/src/actionImpl.ts b/plugins/view-resources/src/actionImpl.ts index 280eb091b1..74fff5abea 100644 --- a/plugins/view-resources/src/actionImpl.ts +++ b/plugins/view-resources/src/actionImpl.ts @@ -14,7 +14,14 @@ import { } from '@hcengineering/ui' import MoveView from './components/Move.svelte' import view from './plugin' -import { FocusSelection, SelectDirection, focusStore, previewDocument, selectionStore } from './selection' +import { + FocusSelection, + SelectDirection, + SelectionStore, + focusStore, + previewDocument, + selectionStore +} from './selection' import { deleteObjects, getObjectLinkFragment } from './utils' import contact from '@hcengineering/contact' @@ -107,6 +114,11 @@ contextStore.subscribe((it) => { $contextStore = it }) +let $selectionStore: SelectionStore +selectionStore.subscribe((it) => { + $selectionStore = it +}) + export function select ( evt: Event | undefined, offset: 1 | -1 | 0, @@ -128,8 +140,9 @@ export function select ( function SelectItem (doc: Doc | Doc[] | undefined, evt: Event): void { const focus = $focusStore.focus + const provider = $selectionStore.provider ?? $focusStore.provider if (focus !== undefined) { - selectionStore.update((selection) => { + provider?.selection.update((selection) => { const ind = selection.findIndex((it) => it._id === focus._id) if (ind === -1) { selection.push(focus) @@ -142,15 +155,21 @@ function SelectItem (doc: Doc | Doc[] | undefined, evt: Event): void { evt.preventDefault() } function SelectItemNone (doc: Doc | undefined, evt: Event): void { - selectionStore.set([]) - previewDocument.set(undefined) - evt.preventDefault() + const provider = $selectionStore.provider ?? $focusStore.provider + if (provider !== undefined) { + provider.selection.set([]) + previewDocument.set(undefined) + evt.preventDefault() + } } function SelectItemAll (doc: Doc | undefined, evt: Event): void { - const docs = $focusStore.provider?.docs() ?? [] - selectionStore.set(docs) - previewDocument.set(undefined) - evt.preventDefault() + const provider = $selectionStore.provider ?? $focusStore.provider + if (provider !== undefined) { + const docs = provider.docs() ?? [] + provider.selection.set(docs) + previewDocument.set(undefined) + evt.preventDefault() + } } const MoveUp = (doc: Doc | undefined, evt: Event): void => select(evt, -1, $focusStore.focus, 'vertical') diff --git a/plugins/view-resources/src/actions.ts b/plugins/view-resources/src/actions.ts index d950cd6ba1..9fec0ccbc6 100644 --- a/plugins/view-resources/src/actions.ts +++ b/plugins/view-resources/src/actions.ts @@ -27,17 +27,17 @@ import core, { import { getResource } from '@hcengineering/platform' import { Action, ActionGroup, ViewAction, ViewActionInput, ViewContextType } from '@hcengineering/view' import view from './plugin' -import { FocusSelection } from './selection' +import { FocusSelection, SelectionStore } from './selection' /** * @public */ -export function getSelection (focusStore: FocusSelection, selectionStore: Doc[]): Doc[] { +export function getSelection (focus: FocusSelection, selection: SelectionStore): Doc[] { let docs: Doc[] = [] - if (selectionStore.length > 0) { - docs = selectionStore - } else if (focusStore.focus !== undefined) { - docs = [focusStore.focus] + if (selection.docs.length > 0) { + docs = selection.docs + } else if (focus.focus !== undefined) { + docs = [focus.focus] } return docs } diff --git a/plugins/view-resources/src/components/ActionHandler.svelte b/plugins/view-resources/src/components/ActionHandler.svelte index 9bb14fb5f3..0d78e14233 100644 --- a/plugins/view-resources/src/components/ActionHandler.svelte +++ b/plugins/view-resources/src/components/ActionHandler.svelte @@ -20,7 +20,7 @@ import { Action, ViewContextType } from '@hcengineering/view' import { fly } from 'svelte/transition' import { getContextActions, getSelection } from '../actions' - import { focusStore, previewDocument, selectionStore } from '../selection' + import { ListSelectionProvider, SelectionStore, focusStore, previewDocument, selectionStore } from '../selection' import { getObjectPreview } from '../utils' const client = getClient() @@ -28,8 +28,9 @@ addTxListener((tx) => { if (tx._class === core.class.TxRemoveDoc) { const docId = (tx as TxRemoveDoc<Doc>).objectId - if ($selectionStore.find((it) => it._id === docId) !== undefined) { - selectionStore.update((old) => { + const provider = ListSelectionProvider.Find(docId) + if (provider !== undefined) { + provider.selection.update((old) => { return old.filter((it) => it._id !== docId) }) } @@ -47,13 +48,13 @@ application?: Ref<Doc> }, focus: Doc | undefined | null, - selection: Doc[] + selection: SelectionStore ): Promise<Action[]> { let docs: Doc | Doc[] = [] - if (selection.find((it) => it._id === focus?._id) === undefined && focus != null) { + if (selection.docs.find((it) => it._id === focus?._id) === undefined && focus != null) { docs = focus } else { - docs = selection + docs = selection.docs } return await getContextActions(client, docs, context) diff --git a/plugins/view-resources/src/components/ActionsPopup.svelte b/plugins/view-resources/src/components/ActionsPopup.svelte index 42585580cc..d2c1cbbee0 100644 --- a/plugins/view-resources/src/components/ActionsPopup.svelte +++ b/plugins/view-resources/src/components/ActionsPopup.svelte @@ -193,11 +193,11 @@ on:keydown={onKeydown} use:resizeObserver={() => dispatch('changeContent')} > - {#if $selectionStore.length > 0 || $focusStore.focus !== undefined || (activeAction && activeAction?.actionPopup !== undefined)} + {#if $selectionStore.docs.length > 0 || $focusStore.focus !== undefined || (activeAction && activeAction?.actionPopup !== undefined)} <div class="mt-2 ml-2 flex-between flex-no-shrink"> - {#if $selectionStore.length > 0} + {#if $selectionStore.docs.length > 0} <div class="item-box"> - <Label label={view.string.NumberItems} params={{ count: $selectionStore.length }} /> + <Label label={view.string.NumberItems} params={{ count: $selectionStore.docs.length }} /> </div> {:else if $focusStore.focus !== undefined} <div class="item-box"> diff --git a/plugins/view-resources/src/components/TableBrowser.svelte b/plugins/view-resources/src/components/TableBrowser.svelte index 7844e52602..2bb8e206c0 100644 --- a/plugins/view-resources/src/components/TableBrowser.svelte +++ b/plugins/view-resources/src/components/TableBrowser.svelte @@ -18,7 +18,7 @@ import { Scroller, tableSP, FadeOptions } from '@hcengineering/ui' import { BuildModelKey } from '@hcengineering/view' import { onMount } from 'svelte' - import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '../selection' + import { focusStore, ListSelectionProvider, SelectDirection } from '../selection' import { LoadingProps } from '../utils' import SourcePresenter from './inference/SourcePresenter.svelte' import Table from './Table.svelte' @@ -48,6 +48,7 @@ } } ) + const selection = listProvider.selection onMount(() => { ;(document.activeElement as HTMLElement)?.blur() @@ -101,7 +102,7 @@ highlightRows={true} {enableChecking} showFooter - checked={$selectionStore ?? []} + checked={$selection ?? []} {prefferedSorting} {tableId} selection={listProvider.current($focusStore)} diff --git a/plugins/view-resources/src/components/list/List.svelte b/plugins/view-resources/src/components/list/List.svelte index aec76cfaef..ce27308269 100644 --- a/plugins/view-resources/src/components/list/List.svelte +++ b/plugins/view-resources/src/components/list/List.svelte @@ -19,6 +19,7 @@ import { AnyComponent, AnySvelteComponent } from '@hcengineering/ui' import { BuildModelKey, ViewOptionModel, ViewOptions, ViewQueryOption, Viewlet } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' + import { SelectionFocusProvider } from '../../selection' import { buildConfigLookup } from '../../utils' import ListCategories from './ListCategories.svelte' @@ -40,6 +41,7 @@ export let props: Record<string, any> = {} export let selection: number | undefined = undefined export let compactMode: boolean = false + export let listProvider: SelectionFocusProvider const limiter = new RateLimitter(() => ({ rate: 10 })) @@ -189,6 +191,7 @@ {viewOptionsConfig} {selectedObjectIds} {limiter} + {listProvider} level={0} groupPersistKey={''} {createItemDialog} diff --git a/plugins/view-resources/src/components/list/ListCategories.svelte b/plugins/view-resources/src/components/list/ListCategories.svelte index 89cf48b71b..c66103f40b 100644 --- a/plugins/view-resources/src/components/list/ListCategories.svelte +++ b/plugins/view-resources/src/components/list/ListCategories.svelte @@ -37,6 +37,7 @@ ViewOptions } from '@hcengineering/view' import { createEventDispatcher, onDestroy, SvelteComponentTyped } from 'svelte' + import { SelectionFocusProvider } from '../../selection' import { buildModel, concatCategories, @@ -83,6 +84,7 @@ export let resultQuery: DocumentQuery<Doc> export let resultOptions: FindOptions<Doc> export let limiter: RateLimitter + export let listProvider: SelectionFocusProvider $: groupByKey = viewOptions.groupBy[level] ?? noCategory let categories: CategoryType[] = [] @@ -380,6 +382,7 @@ {resultQuery} {resultOptions} {limiter} + {listProvider} on:check on:uncheckAll on:row-focus diff --git a/plugins/view-resources/src/components/list/ListCategory.svelte b/plugins/view-resources/src/components/list/ListCategory.svelte index 977434b7e8..3df617cfe7 100644 --- a/plugins/view-resources/src/components/list/ListCategory.svelte +++ b/plugins/view-resources/src/components/list/ListCategory.svelte @@ -42,7 +42,7 @@ import { AttributeModel, BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' import { fade } from 'svelte/transition' - import { FocusSelection, focusStore } from '../../selection' + import { FocusSelection, SelectionFocusProvider, focusStore } from '../../selection' import Menu from '../Menu.svelte' import ListHeader from './ListHeader.svelte' import ListItem from './ListItem.svelte' @@ -87,6 +87,7 @@ export let resultOptions: FindOptions<Doc> export let parentCategories: number = 0 export let limiter: RateLimitter + export let listProvider: SelectionFocusProvider $: lastLevel = level + 1 >= viewOptions.groupBy.length @@ -432,6 +433,7 @@ limited={lastLevel ? limited.length : itemProj.length} itemsProj={itemProj} items={limited} + {listProvider} {headerComponent} {createItemDialog} {createItemDialogProps} diff --git a/plugins/view-resources/src/components/list/ListHeader.svelte b/plugins/view-resources/src/components/list/ListHeader.svelte index a7b9466f33..989dc97d1b 100644 --- a/plugins/view-resources/src/components/list/ListHeader.svelte +++ b/plugins/view-resources/src/components/list/ListHeader.svelte @@ -36,7 +36,7 @@ import { AttributeModel, ViewOptions } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' import view from '../../plugin' - import { selectionStore, selectionStoreMap } from '../../selection' + import { SelectionFocusProvider } from '../../selection' import { noCategory } from '../../viewOptions' export let groupByKey: string @@ -50,6 +50,7 @@ export let collapsed = false export let lastCat = false export let level: number + export let listProvider: SelectionFocusProvider export let createItemDialog: AnyComponent | AnySvelteComponent | undefined export let createItemDialogProps: Record<string, any> | undefined @@ -82,7 +83,10 @@ } let mouseOver = false - $: selected = items.filter((it) => $selectionStoreMap.has(it._id)) + const selection = listProvider.selection + + $: selectionIds = new Set($selection.map((it) => it._id)) + $: selected = items.filter((it) => selectionIds.has(it._id)) </script> {#if headerComponent || groupByKey === noCategory} @@ -177,18 +181,18 @@ kind={'ghost'} showTooltip={{ label: view.string.Select }} on:click={() => { - let newSelection = [...$selectionStore] + let newSelection = [...$selection] if (selected.length > 0) { const smap = new Map(selected.map((it) => [it._id, it])) newSelection = newSelection.filter((it) => !smap.has(it._id)) } else { for (const s of items) { - if (!$selectionStoreMap.has(s._id)) { + if (!selectionIds.has(s._id)) { newSelection.push(s) } } } - selectionStore.set(newSelection) + listProvider.selection.set(newSelection) }} /> </div> diff --git a/plugins/view-resources/src/components/list/ListView.svelte b/plugins/view-resources/src/components/list/ListView.svelte index 2481020532..a78d4e3eed 100644 --- a/plugins/view-resources/src/components/list/ListView.svelte +++ b/plugins/view-resources/src/components/list/ListView.svelte @@ -1,3 +1,17 @@ +<!-- +// Copyright © 2023 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +--> <script lang="ts"> import { Class, Doc, DocumentQuery, FindOptions, Ref, Space } from '@hcengineering/core' import { IntlString } from '@hcengineering/platform' @@ -5,7 +19,7 @@ import { BuildModelKey, Viewlet, ViewOptions } from '@hcengineering/view' import { onMount } from 'svelte' import { ActionContext } from '@hcengineering/presentation' - import { ListSelectionProvider, SelectDirection, focusStore, selectionStore } from '../..' + import { ListSelectionProvider, SelectDirection, focusStore } from '../..' import List from './List.svelte' @@ -37,6 +51,7 @@ } } ) + const selection = listProvider.selection onMount(() => { ;(document.activeElement as HTMLElement)?.blur() @@ -70,9 +85,10 @@ {createItemLabel} {viewOptions} {props} + {listProvider} compactMode={listWidth <= 800} viewOptionsConfig={viewlet.viewOptions?.other} - selectedObjectIds={$selectionStore ?? []} + selectedObjectIds={$selection ?? []} selection={listProvider.current($focusStore)} on:row-focus={(event) => { listProvider.updateFocus(event.detail ?? undefined) diff --git a/plugins/view-resources/src/selection.ts b/plugins/view-resources/src/selection.ts index cdcadc3758..ae25565149 100644 --- a/plugins/view-resources/src/selection.ts +++ b/plugins/view-resources/src/selection.ts @@ -1,7 +1,7 @@ import { Doc, Ref } from '@hcengineering/core' import { panelstore } from '@hcengineering/ui' import { onDestroy } from 'svelte' -import { Unsubscriber, derived, writable } from 'svelte/store' +import { Unsubscriber, Writable, writable } from 'svelte/store' /** * @public @@ -32,7 +32,11 @@ export interface SelectionFocusProvider { // Return all selectable documents docs: () => Doc[] + + // All selected documents + selection: Writable<Doc[]> } + /** * @public * @@ -46,6 +50,18 @@ export interface FocusSelection { provider?: SelectionFocusProvider } +/** + * @public + * + * Define document selection inside platform. + */ +export interface SelectionStore { + // Selected documents + docs: Doc[] + // Provider where documents are selected + provider?: SelectionFocusProvider +} + /** * @public */ @@ -54,18 +70,17 @@ export const focusStore = writable<FocusSelection>({}) /** * @public */ -export const selectionStore = writable<Doc[]>([]) +export const selectionStore = writable<SelectionStore>({ docs: [] }) /** * @public */ -export const selectionStoreMap = derived(selectionStore, (it) => new Set(it.map((it) => it._id))) - export const previewDocument = writable<Doc | undefined>() panelstore.subscribe((val) => { previewDocument.set(undefined) }) + /** * @public */ @@ -88,17 +103,23 @@ export function updateFocus (selection?: FocusSelection): void { return cur }) - - // We need to clear selection items not belong to passed provider. - if (selection?.provider !== undefined) { - const docs = new Set(selection?.provider.docs().map((it) => it._id)) - selectionStore.update((old) => { - return old.filter((it) => docs.has(it._id)) - }) - } } -const providers: ListSelectionProvider[] = [] +interface ProviderSelection { + docs: Doc[] + provider: ListSelectionProvider +} + +const providers: ProviderSelection[] = [] + +function updateSelection (selection: ProviderSelection): void { + const index = providers.findIndex((p) => p.provider === selection.provider) + if (index !== -1) { + providers[index] = selection + } + + selectionStore.set(selection) +} /** * @public @@ -108,15 +129,27 @@ const providers: ListSelectionProvider[] = [] export class ListSelectionProvider implements SelectionFocusProvider { private _docs: Doc[] = [] _current?: FocusSelection - private readonly unsubscribe: Unsubscriber + selection: Writable<Doc[]> = writable([]) + private readonly unsubscribe: Unsubscriber[] + constructor ( private readonly delegate: (offset: 1 | -1 | 0, of?: Doc, direction?: SelectDirection, noScroll?: boolean) => void, autoDestroy = true ) { - this.unsubscribe = focusStore.subscribe((doc) => { - this._current = doc - }) - providers.push(this) + this.unsubscribe = [ + // keep track of current focus + focusStore.subscribe((focus) => { + this._current = focus + }), + // update global selection when current changes + this.selection.subscribe((docs) => { + updateSelection({ docs, provider: this }) + }) + ] + + providers.push({ docs: [], provider: this }) + selectionStore.set({ docs: [], provider: this }) + if (autoDestroy) { onDestroy(() => { this.destroy() @@ -125,9 +158,11 @@ export class ListSelectionProvider implements SelectionFocusProvider { } static Find (_id: Ref<Doc>): ListSelectionProvider | undefined { - for (const provider of providers) { - if (provider.docs().findIndex((p) => p._id === _id) !== -1) { - return provider + for (const { provider } of providers) { + if (provider !== undefined) { + if (provider.docs().findIndex((p) => p._id === _id) !== -1) { + return provider + } } } } @@ -135,23 +170,35 @@ export class ListSelectionProvider implements SelectionFocusProvider { static Pop (): void { if (providers.length === 0) return const last = providers[providers.length - 1] - last.destroy() + last.provider.destroy() } destroy (): void { - const thisIndex = providers.findIndex((p) => p === this) + const thisIndex = providers.findIndex((p) => p.provider === this) providers.splice(thisIndex, 1) + + // switch selection to the last provider if lost selection if (thisIndex === providers.length) { if (providers.length > 0) { - const current = providers[providers.length - 1] - const index = current.current() - const target = index !== undefined ? current.docs()[index] : undefined - updateFocus({ focus: target, provider: current }) + const next = providers[providers.length - 1].provider + const index = next.current() + const target = index !== undefined ? next.docs()[index] : undefined + updateFocus({ focus: target, provider: next }) } else { updateFocus() } } - this.unsubscribe() + + // switch selection to the last provider if lost selection + selectionStore.update((selection) => { + if (selection.provider === this) { + const next = providers[providers.length - 1] + return next ?? { docs: selection.docs } + } + return selection + }) + + this.unsubscribe.forEach((p) => p()) } select (offset: 1 | -1 | 0, of?: Doc, direction?: SelectDirection, noScroll?: boolean): void { @@ -162,7 +209,8 @@ export class ListSelectionProvider implements SelectionFocusProvider { update (docs: Doc[]): void { this._docs = docs - selectionStore.update((docs) => { + // remove missing documents from selection + this.selection.update((docs) => { const ids = new Set(docs.map((it) => it._id)) return this._docs.filter((it) => ids.has(it._id)) }) @@ -174,6 +222,7 @@ export class ListSelectionProvider implements SelectionFocusProvider { // Check if we don't have object, we need to select first one. this.delegate(0, this._current?.focus, 'vertical', true) } + // focus current provider if nothing focused if (this._current?.focus === undefined) { updateFocus({ focus: this._current?.focus, provider: this }) } @@ -189,7 +238,7 @@ export class ListSelectionProvider implements SelectionFocusProvider { } updateSelection (docs: Doc[], value: boolean): void { - selectionStore.update((selection) => { + this.selection.update((selection) => { const docsSet = new Set(docs.map((it) => it._id)) const noDocs = selection.filter((it) => !docsSet.has(it._id)) return value ? [...noDocs, ...docs] : noDocs