From d6ad5084f1e44c602838c33fd6b94b709da2e49a Mon Sep 17 00:00:00 2001 From: Henrik Giesel Date: Fri, 9 Apr 2021 00:51:20 +0200 Subject: [PATCH] Add a button / buttonGroup insertion API --- ts/editor-toolbar/identifiable.ts | 50 ++++++++++++++++ ts/editor-toolbar/index.ts | 97 +++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 ts/editor-toolbar/identifiable.ts diff --git a/ts/editor-toolbar/identifiable.ts b/ts/editor-toolbar/identifiable.ts new file mode 100644 index 000000000..b57f8a3cd --- /dev/null +++ b/ts/editor-toolbar/identifiable.ts @@ -0,0 +1,50 @@ +export interface Identifiable { + id?: string; +} + +function normalize( + values: T[], + idOrIndex: string | number +): number { + const normalizedIndex = + typeof idOrIndex === "string" + ? values.findIndex((value) => value.id === idOrIndex) + : idOrIndex >= 0 + ? idOrIndex + : values.length + idOrIndex; + + return normalizedIndex >= values.length ? -1 : normalizedIndex; +} + +export function search( + values: T[], + idOrIndex: string | number +): T | null { + const index = normalize(values, idOrIndex); + + return index >= 0 ? values[index] : null; +} + +export function insert( + values: T[], + value: T, + idOrIndex: string | number +): T[] { + const index = normalize(values, idOrIndex); + + return index >= 0 + ? [...values.slice(0, index), value, ...values.slice(index)] + : values; +} + +export function add( + values: T[], + value: T, + idOrIndex: string | number +): T[] { + const index = normalize(values, idOrIndex); + + return index >= 0 + ? [...values.slice(0, index + 1), value, ...values.slice(index + 1)] + : values; +} diff --git a/ts/editor-toolbar/index.ts b/ts/editor-toolbar/index.ts index 8f9696808..188c0dd86 100644 --- a/ts/editor-toolbar/index.ts +++ b/ts/editor-toolbar/index.ts @@ -1,9 +1,10 @@ import type { SvelteComponent } from "svelte"; import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent"; -import type ButtonGroup from "./ButtonGroup.svelte"; +import ButtonGroup from "./ButtonGroup.svelte"; import type { ButtonGroupProps } from "./ButtonGroup"; +import { dynamicComponent } from "sveltelib/dynamicComponent"; import { writable } from "svelte/store"; import EditorToolbarSvelte from "./EditorToolbar.svelte"; @@ -16,26 +17,12 @@ import { formatGroup } from "./format"; import { colorGroup } from "./color"; import { templateGroup, templateMenus } from "./template"; -// @ts-expect-error -export { updateActiveButtons, clearActiveButtons } from "./CommandIconButton.svelte"; -export { enableButtons, disableButtons } from "./EditorToolbar.svelte"; - -const defaultButtons = [notetypeGroup, formatGroup, colorGroup, templateGroup]; -const defaultMenus = [...templateMenus]; +import { Identifiable, search, add, insert } from "./identifiable"; interface Hideable { hidden?: boolean; } -function searchByIdOrIndex( - values: T[], - idOrIndex: string | number -): T | undefined { - return typeof idOrIndex === "string" - ? values.find((value) => value.id === idOrIndex) - : values[idOrIndex]; -} - function showComponent(component: Hideable) { component.hidden = false; } @@ -48,6 +35,9 @@ function toggleComponent(component: Hideable) { component.hidden = !component.hidden; } +const defaultButtons = [notetypeGroup, formatGroup, colorGroup, templateGroup]; +const defaultMenus = [...templateMenus]; + class EditorToolbar extends HTMLElement { component?: SvelteComponent; @@ -76,7 +66,7 @@ class EditorToolbar extends HTMLElement { buttonGroups: (DynamicSvelteComponent & ButtonGroupProps)[] ) => { - const foundGroup = searchByIdOrIndex(buttonGroups, group); + const foundGroup = search(buttonGroups, group); if (foundGroup) { update( @@ -103,6 +93,32 @@ class EditorToolbar extends HTMLElement { this.updateButtonGroup(toggleComponent, group); } + insertButtonGroup(newGroup: ButtonGroupProps, group: string | number = 0) { + const buttonGroup = dynamicComponent(ButtonGroup); + this.buttons.update( + ( + buttonGroups: (DynamicSvelteComponent & + ButtonGroupProps)[] + ) => { + const newButtonGroup = buttonGroup(newGroup, {}); + return insert(buttonGroups, newButtonGroup, group); + } + ); + } + + addButtonGroup(newGroup: ButtonGroupProps, group: string | number = -1) { + const buttonGroup = dynamicComponent(ButtonGroup); + this.buttons.update( + ( + buttonGroups: (DynamicSvelteComponent & + ButtonGroupProps)[] + ) => { + const newButtonGroup = buttonGroup(newGroup, {}); + return add(buttonGroups, newButtonGroup, group); + } + ); + } + updateButton( update: (component: DynamicSvelteComponent & T) => void, group: string | number, @@ -113,8 +129,8 @@ class EditorToolbar extends HTMLElement { foundGroup: DynamicSvelteComponent & ButtonGroupProps ) => { - const foundButton = searchByIdOrIndex( - foundGroup.buttons as (DynamicSvelteComponent & { id?: string })[], + const foundButton = search( + foundGroup.buttons as (DynamicSvelteComponent & Identifiable)[], button ); @@ -137,10 +153,53 @@ class EditorToolbar extends HTMLElement { toggleButton(group: string | number, button: string | number): void { this.updateButton(toggleComponent, group, button); } + + insertButton( + newButton: DynamicSvelteComponent & Identifiable, + group: string | number, + button: string | number = 0 + ) { + this.updateButtonGroup( + ( + component: DynamicSvelteComponent & ButtonGroupProps + ) => { + component.buttons = insert( + component.buttons as (DynamicSvelteComponent & Identifiable)[], + newButton, + button + ); + }, + group + ); + } + + addButton( + newButton: DynamicSvelteComponent & Identifiable, + group: string | number, + button: string | number = -1 + ) { + this.updateButtonGroup( + ( + component: DynamicSvelteComponent & ButtonGroupProps + ) => { + component.buttons = add( + component.buttons as (DynamicSvelteComponent & Identifiable)[], + newButton, + button + ); + }, + group + ); + } } customElements.define("anki-editor-toolbar", EditorToolbar); +/* Exports for editor + * @ts-expect-error */ +export { updateActiveButtons, clearActiveButtons } from "./CommandIconButton.svelte"; +export { enableButtons, disableButtons } from "./EditorToolbar.svelte"; + /* Exports for add-ons */ export { default as LabelButton } from "./LabelButton.svelte"; export { default as IconButton } from "./IconButton.svelte";