mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 22:42:25 -04:00
Add a button / buttonGroup insertion API
This commit is contained in:
parent
8fd21661b4
commit
d6ad5084f1
2 changed files with 128 additions and 19 deletions
50
ts/editor-toolbar/identifiable.ts
Normal file
50
ts/editor-toolbar/identifiable.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
export interface Identifiable {
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize<T extends Identifiable>(
|
||||||
|
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<T extends Identifiable>(
|
||||||
|
values: T[],
|
||||||
|
idOrIndex: string | number
|
||||||
|
): T | null {
|
||||||
|
const index = normalize(values, idOrIndex);
|
||||||
|
|
||||||
|
return index >= 0 ? values[index] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function insert<T extends Identifiable>(
|
||||||
|
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<T extends Identifiable>(
|
||||||
|
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;
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import type { SvelteComponent } from "svelte";
|
import type { SvelteComponent } from "svelte";
|
||||||
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
|
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
|
||||||
|
|
||||||
import type ButtonGroup from "./ButtonGroup.svelte";
|
import ButtonGroup from "./ButtonGroup.svelte";
|
||||||
import type { ButtonGroupProps } from "./ButtonGroup";
|
import type { ButtonGroupProps } from "./ButtonGroup";
|
||||||
|
|
||||||
|
import { dynamicComponent } from "sveltelib/dynamicComponent";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
import EditorToolbarSvelte from "./EditorToolbar.svelte";
|
import EditorToolbarSvelte from "./EditorToolbar.svelte";
|
||||||
|
@ -16,26 +17,12 @@ import { formatGroup } from "./format";
|
||||||
import { colorGroup } from "./color";
|
import { colorGroup } from "./color";
|
||||||
import { templateGroup, templateMenus } from "./template";
|
import { templateGroup, templateMenus } from "./template";
|
||||||
|
|
||||||
// @ts-expect-error
|
import { Identifiable, search, add, insert } from "./identifiable";
|
||||||
export { updateActiveButtons, clearActiveButtons } from "./CommandIconButton.svelte";
|
|
||||||
export { enableButtons, disableButtons } from "./EditorToolbar.svelte";
|
|
||||||
|
|
||||||
const defaultButtons = [notetypeGroup, formatGroup, colorGroup, templateGroup];
|
|
||||||
const defaultMenus = [...templateMenus];
|
|
||||||
|
|
||||||
interface Hideable {
|
interface Hideable {
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchByIdOrIndex<T extends { id?: string }>(
|
|
||||||
values: T[],
|
|
||||||
idOrIndex: string | number
|
|
||||||
): T | undefined {
|
|
||||||
return typeof idOrIndex === "string"
|
|
||||||
? values.find((value) => value.id === idOrIndex)
|
|
||||||
: values[idOrIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
function showComponent(component: Hideable) {
|
function showComponent(component: Hideable) {
|
||||||
component.hidden = false;
|
component.hidden = false;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +35,9 @@ function toggleComponent(component: Hideable) {
|
||||||
component.hidden = !component.hidden;
|
component.hidden = !component.hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultButtons = [notetypeGroup, formatGroup, colorGroup, templateGroup];
|
||||||
|
const defaultMenus = [...templateMenus];
|
||||||
|
|
||||||
class EditorToolbar extends HTMLElement {
|
class EditorToolbar extends HTMLElement {
|
||||||
component?: SvelteComponent;
|
component?: SvelteComponent;
|
||||||
|
|
||||||
|
@ -76,7 +66,7 @@ class EditorToolbar extends HTMLElement {
|
||||||
buttonGroups: (DynamicSvelteComponent<typeof ButtonGroup> &
|
buttonGroups: (DynamicSvelteComponent<typeof ButtonGroup> &
|
||||||
ButtonGroupProps)[]
|
ButtonGroupProps)[]
|
||||||
) => {
|
) => {
|
||||||
const foundGroup = searchByIdOrIndex(buttonGroups, group);
|
const foundGroup = search(buttonGroups, group);
|
||||||
|
|
||||||
if (foundGroup) {
|
if (foundGroup) {
|
||||||
update(
|
update(
|
||||||
|
@ -103,6 +93,32 @@ class EditorToolbar extends HTMLElement {
|
||||||
this.updateButtonGroup<Hideable>(toggleComponent, group);
|
this.updateButtonGroup<Hideable>(toggleComponent, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insertButtonGroup(newGroup: ButtonGroupProps, group: string | number = 0) {
|
||||||
|
const buttonGroup = dynamicComponent(ButtonGroup);
|
||||||
|
this.buttons.update(
|
||||||
|
(
|
||||||
|
buttonGroups: (DynamicSvelteComponent<typeof ButtonGroup> &
|
||||||
|
ButtonGroupProps)[]
|
||||||
|
) => {
|
||||||
|
const newButtonGroup = buttonGroup<ButtonGroupProps>(newGroup, {});
|
||||||
|
return insert(buttonGroups, newButtonGroup, group);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addButtonGroup(newGroup: ButtonGroupProps, group: string | number = -1) {
|
||||||
|
const buttonGroup = dynamicComponent(ButtonGroup);
|
||||||
|
this.buttons.update(
|
||||||
|
(
|
||||||
|
buttonGroups: (DynamicSvelteComponent<typeof ButtonGroup> &
|
||||||
|
ButtonGroupProps)[]
|
||||||
|
) => {
|
||||||
|
const newButtonGroup = buttonGroup<ButtonGroupProps>(newGroup, {});
|
||||||
|
return add(buttonGroups, newButtonGroup, group);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
updateButton<T>(
|
updateButton<T>(
|
||||||
update: (component: DynamicSvelteComponent & T) => void,
|
update: (component: DynamicSvelteComponent & T) => void,
|
||||||
group: string | number,
|
group: string | number,
|
||||||
|
@ -113,8 +129,8 @@ class EditorToolbar extends HTMLElement {
|
||||||
foundGroup: DynamicSvelteComponent<typeof ButtonGroup> &
|
foundGroup: DynamicSvelteComponent<typeof ButtonGroup> &
|
||||||
ButtonGroupProps
|
ButtonGroupProps
|
||||||
) => {
|
) => {
|
||||||
const foundButton = searchByIdOrIndex(
|
const foundButton = search(
|
||||||
foundGroup.buttons as (DynamicSvelteComponent & { id?: string })[],
|
foundGroup.buttons as (DynamicSvelteComponent & Identifiable)[],
|
||||||
button
|
button
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -137,10 +153,53 @@ class EditorToolbar extends HTMLElement {
|
||||||
toggleButton(group: string | number, button: string | number): void {
|
toggleButton(group: string | number, button: string | number): void {
|
||||||
this.updateButton<Hideable>(toggleComponent, group, button);
|
this.updateButton<Hideable>(toggleComponent, group, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insertButton(
|
||||||
|
newButton: DynamicSvelteComponent & Identifiable,
|
||||||
|
group: string | number,
|
||||||
|
button: string | number = 0
|
||||||
|
) {
|
||||||
|
this.updateButtonGroup(
|
||||||
|
(
|
||||||
|
component: DynamicSvelteComponent<typeof ButtonGroup> & 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<typeof ButtonGroup> & ButtonGroupProps
|
||||||
|
) => {
|
||||||
|
component.buttons = add(
|
||||||
|
component.buttons as (DynamicSvelteComponent & Identifiable)[],
|
||||||
|
newButton,
|
||||||
|
button
|
||||||
|
);
|
||||||
|
},
|
||||||
|
group
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("anki-editor-toolbar", EditorToolbar);
|
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 */
|
/* Exports for add-ons */
|
||||||
export { default as LabelButton } from "./LabelButton.svelte";
|
export { default as LabelButton } from "./LabelButton.svelte";
|
||||||
export { default as IconButton } from "./IconButton.svelte";
|
export { default as IconButton } from "./IconButton.svelte";
|
||||||
|
|
Loading…
Reference in a new issue