diff --git a/package.json b/package.json index 9a6d033..8e9b346 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,14 @@ "./virtual-grid": { "types": "./dist/virtual-grid.d.ts", "svelte": "./dist/virtual-grid.js" + }, + "./selection-js": { + "types": "./dist/selection-js.d.ts", + "svelte": "./dist/selection-js.js" + }, + "./selection-svelte": { + "types": "./dist/selection-svelte.d.ts", + "svelte": "./dist/selection-svelte.js" } }, "peerDependencies": { diff --git a/src/lib/index.ts b/src/lib/index.ts index 1a72bb9..b9e7e90 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1,3 @@ export { check_shortcut, check_mouse_shortcut, check_modifiers, is_mac } from './shortcuts.ts' export { auto_snapshot } from './auto-snapshot.ts' +export { KSelection } from './selection-js.ts' diff --git a/src/lib/selection.ts b/src/lib/selection-js.ts similarity index 79% rename from src/lib/selection.ts rename to src/lib/selection-js.ts index cfe8009..888067d 100644 --- a/src/lib/selection.ts +++ b/src/lib/selection-js.ts @@ -1,12 +1,11 @@ -import { writable, type Writable } from 'svelte/store' import { check_mouse_shortcut, check_shortcut } from './shortcuts.ts' -type SelectionOptions = { +export type SelectionOptions = { scroll_to: (target: { item: T; index: number }) => void on_contextmenu?: (items: Set) => void } -class Selection { +export class KSelection { /** Currently selected items. Disallowing assignment * prevents the Svelte store from getting out of sync */ readonly items = new Set() @@ -357,89 +356,3 @@ class Selection { e.preventDefault() } } - -export class SvelteSelection { - readonly #selection: Selection - readonly #store: Writable> - readonly subscribe: Writable>['subscribe'] - readonly items: Set - constructor(all_items: T[], options: SelectionOptions) { - this.#selection = new Selection(all_items, options) - this.#store = writable(this.#selection.items) - this.subscribe = this.#store.subscribe - this.items = this.#selection.items - } - - find_first_index() { - return this.#selection.find_first_index() - } - find_first() { - return this.#selection.find_first() - } - items_as_array() { - return this.#selection.items_as_array() - } - get_selected_indexes() { - return this.#selection.get_selected_indexes() - } - - add_index(index: number) { - this.#selection.add_index(index) - } - - clear() { - this.#selection.clear() - this.#store.set(this.#selection.items) - } - update_all_items(all: T[]) { - this.#selection.update_all_items(all) - this.#store.set(this.#selection.items) - } - handle_mousedown(e: MouseEvent, index: number) { - this.#selection.handle_mouse_down(e, index) - this.#store.set(this.#selection.items) - } - handle_contextmenu(e: MouseEvent, index: number) { - this.#selection.handle_contextmenu(e, index) - this.#store.set(this.#selection.items) - } - handle_click(e: MouseEvent, index: number) { - this.#selection.handle_click(e, index) - this.#store.set(this.#selection.items) - } - handle_keydown(e: KeyboardEvent) { - this.#selection.handle_keydown(e) - this.#store.set(this.#selection.items) - } - /** This adds all row events, and keydown. - * The listener should return row index. - * Returns an unlisten function. */ - add_events(element: HTMLElement, listener: (e: MouseEvent | KeyboardEvent) => number | null) { - const handler = (e: MouseEvent | KeyboardEvent) => { - const index = listener(e) - if (Number.isInteger(index)) { - this.#selection.handle_events(e, index as number) - this.#store.set(this.#selection.items) - } - } - element.addEventListener('mousedown', handler) - element.addEventListener('contextmenu', handler) - element.addEventListener('click', handler) - element.addEventListener('keydown', handler) - return () => { - element.removeEventListener('mousedown', handler) - element.removeEventListener('contextmenu', handler) - element.removeEventListener('click', handler) - element.removeEventListener('keydown', handler) - } - } - /** This adds all row events, and keydown. The listener should return row index. */ - attach_events(listener: (e: MouseEvent | KeyboardEvent) => number | null) { - return (element: HTMLElement) => { - const unlisten = this.add_events(element, (e) => { - return listener(e) - }) - return unlisten - } - } -} diff --git a/src/lib/selection-svelte.ts b/src/lib/selection-svelte.ts new file mode 100644 index 0000000..d7df3e6 --- /dev/null +++ b/src/lib/selection-svelte.ts @@ -0,0 +1,92 @@ +import { writable, type Writable } from 'svelte/store' +import { KSelection as KSelectionJS, type SelectionOptions } from './selection-js.ts' + +export class KSelection { + readonly #selection: KSelectionJS + readonly #store: Writable> + readonly subscribe: Writable>['subscribe'] + readonly items: Set + constructor(all_items: T[], options: SelectionOptions) { + this.#selection = new KSelectionJS(all_items, options) + this.#store = writable(this.#selection.items) + this.subscribe = this.#store.subscribe + this.items = this.#selection.items + } + + find_first_index() { + return this.#selection.find_first_index() + } + find_first() { + return this.#selection.find_first() + } + items_as_array() { + return this.#selection.items_as_array() + } + get_selected_indexes() { + return this.#selection.get_selected_indexes() + } + + add_index(index: number) { + this.#selection.add_index(index) + } + + clear() { + this.#selection.clear() + this.#store.set(this.#selection.items) + } + update_all_items(all: T[]) { + this.#selection.update_all_items(all) + this.#store.set(this.#selection.items) + } + handle_mousedown(e: MouseEvent, index: number) { + this.#selection.handle_mouse_down(e, index) + this.#store.set(this.#selection.items) + } + handle_contextmenu(e: MouseEvent, index: number) { + this.#selection.handle_contextmenu(e, index) + this.#store.set(this.#selection.items) + } + handle_click(e: MouseEvent, index: number) { + this.#selection.handle_click(e, index) + this.#store.set(this.#selection.items) + } + handle_keydown(e: KeyboardEvent) { + this.#selection.handle_keydown(e) + this.#store.set(this.#selection.items) + } + /** This adds all row events, and keydown. + * The listener should return row index. + * Returns an unlisten function. */ + add_event_listeners( + element: HTMLElement, + listener: (e: MouseEvent | KeyboardEvent) => number | null, + ) { + const handler = (e: MouseEvent | KeyboardEvent) => { + const index = listener(e) + const is_row_event = e instanceof MouseEvent + if (Number.isInteger(index) || !is_row_event) { + this.#selection.handle_events(e, index as number) + this.#store.set(this.#selection.items) + } + } + element.addEventListener('mousedown', handler) + element.addEventListener('contextmenu', handler) + element.addEventListener('click', handler) + element.addEventListener('keydown', handler) + return () => { + element.removeEventListener('mousedown', handler) + element.removeEventListener('contextmenu', handler) + element.removeEventListener('click', handler) + element.removeEventListener('keydown', handler) + } + } + /** This adds all row events, and keydown. The listener should return row index. */ + attach_events(listener: (e: MouseEvent | KeyboardEvent) => number | null) { + return (element: HTMLElement) => { + const unlisten = this.add_event_listeners(element, (e) => { + return listener(e) + }) + return unlisten + } + } +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 941151c..38ec593 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,5 +1,5 @@
@@ -60,15 +59,16 @@
-
+ +
{ + return virtual_grid.get_row_index_from_event(e) + })} + > -
{ - return virtual_grid.get_row_index_from_event(e) - })} - >
+