Add IterableToolbarItem interface for easier typing

This commit is contained in:
Henrik Giesel 2021-04-23 18:53:52 +02:00
parent 7cd779063f
commit bda99ee0f1
19 changed files with 55 additions and 84 deletions

View file

@ -175,7 +175,7 @@ class Editor:
f""" f"""
$editorToolbar.addButtonGroup({{ $editorToolbar.addButtonGroup({{
id: "addons", id: "addons",
buttons: [ {righttopbtns_defs} ] items: [ {righttopbtns_defs} ]
}}); }});
""" """
if righttopbtns_defs if righttopbtns_defs

View file

@ -5,5 +5,5 @@ import type { ToolbarItem } from "./types";
export interface ButtonDropdownProps { export interface ButtonDropdownProps {
id: string; id: string;
className?: string; className?: string;
buttons: ToolbarItem[]; items: ToolbarItem[];
} }

View file

@ -13,7 +13,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
return `dropdown-menu btn-dropdown-menu py-1 mb-0 ${className}`; return `dropdown-menu btn-dropdown-menu py-1 mb-0 ${className}`;
} }
export let buttons: ToolbarItem[]; export let items: ToolbarItem[];
</script> </script>
<style> <style>
@ -24,4 +24,4 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</style> </style>
<ButtonGroup {id} className={extendClassName(className)} {buttons} /> <ButtonGroup {id} className={extendClassName(className)} {items} />

View file

@ -5,5 +5,5 @@ import type { ToolbarItem } from "./types";
export interface ButtonGroupProps { export interface ButtonGroupProps {
id: string; id: string;
className?: string; className?: string;
buttons: ToolbarItem[]; items: ToolbarItem[];
} }

View file

@ -9,7 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let id: string | undefined = undefined; export let id: string | undefined = undefined;
export let className = ""; export let className = "";
export let buttons: ToolbarItem[]; export let items: ToolbarItem[];
function filterHidden({ hidden = false, ...props }) { function filterHidden({ hidden = false, ...props }) {
return props; return props;
@ -73,7 +73,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</style> </style>
<ul {id} class={className} class:border-overlap-group={!nightMode}> <ul {id} class={className} class:border-overlap-group={!nightMode}>
{#each buttons as button} {#each items as button}
{#if !button.hidden} {#if !button.hidden}
<li class:gap-item={nightMode}> <li class:gap-item={nightMode}>
<svelte:component this={button.component} {...filterHidden(button)} /> <svelte:component this={button.component} {...filterHidden(button)} />

View file

@ -4,5 +4,5 @@ import type { ToolbarItem } from "./types";
export interface DropdownMenuProps { export interface DropdownMenuProps {
id: string; id: string;
menuItems: ToolbarItem[]; items: ToolbarItem[];
} }

View file

@ -8,7 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { nightModeKey } from "./contextKeys"; import { nightModeKey } from "./contextKeys";
export let id: string; export let id: string;
export let menuItems: DynamicSvelteComponent[]; export let items: ToolbarItem[];
const nightMode = getContext<boolean>(nightModeKey); const nightMode = getContext<boolean>(nightModeKey);
</script> </script>
@ -27,7 +27,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</style> </style>
<ul {id} class="dropdown-menu" class:night-mode={nightMode}> <ul {id} class="dropdown-menu" class:night-mode={nightMode}>
{#each menuItems as menuItem} {#each items as menuItem}
<li> <li>
<svelte:component this={menuItem.component} {...menuItem} /> <svelte:component this={menuItem.component} {...menuItem} />
</li> </li>

View file

@ -19,16 +19,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript"> <script lang="typescript">
import type { Readable } from "svelte/store"; import type { Readable } from "svelte/store";
import type { ToolbarItem } from "./types"; import type { ToolbarItem, IterableToolbarItem } from "./types";
import { setContext } from "svelte"; import { setContext } from "svelte";
import { disabledKey, nightModeKey } from "./contextKeys"; import { disabledKey, nightModeKey } from "./contextKeys";
import ButtonGroup from "./ButtonGroup.svelte"; import ButtonGroup from "./ButtonGroup.svelte";
import type { ButtonGroupProps } from "./ButtonGroup"; import type { ButtonGroupProps } from "./ButtonGroup";
export let buttons: Readable< export let buttons: Readable<IterableToolbarItem>[];
(ToolbarItem<typeof ButtonGroup> & ButtonGroupProps)[]
>;
export let menus: Readable<ToolbarItem[]>; export let menus: Readable<ToolbarItem[]>;
$: _buttons = $buttons; $: _buttons = $buttons;
@ -77,5 +75,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</div> </div>
<nav {style}> <nav {style}>
<ButtonGroup buttons={_buttons} className="mt-0" /> <ButtonGroup items={_buttons} className="mt-0" />
</nav> </nav>

View file

@ -1,7 +1,5 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { ToolbarItem } from "./types";
export interface Option { export interface Option {
label: string; label: string;
value: string; value: string;
@ -12,7 +10,6 @@ export interface SelectButtonProps {
id: string; id: string;
className?: string; className?: string;
tooltip?: string; tooltip?: string;
buttons: ToolbarItem[];
disables: boolean; disables: boolean;
options: Option[]; options: Option[];
} }

View file

@ -12,11 +12,9 @@ function normalize<T extends Identifiable>(
if (typeof idOrIndex === "string") { if (typeof idOrIndex === "string") {
normalizedIndex = values.findIndex((value) => value.id === idOrIndex); normalizedIndex = values.findIndex((value) => value.id === idOrIndex);
} } else if (idOrIndex < 0) {
else if (idOrIndex < 0) {
normalizedIndex = values.length + idOrIndex; normalizedIndex = values.length + idOrIndex;
} } else {
else {
normalizedIndex = idOrIndex; normalizedIndex = idOrIndex;
} }

View file

@ -134,7 +134,7 @@ export class EditorToolbar extends HTMLElement {
button: string | number button: string | number
): void { ): void {
this.updateButtonGroup((foundGroup) => { this.updateButtonGroup((foundGroup) => {
const foundButton = search(foundGroup.buttons, button); const foundButton = search(foundGroup.items, button);
if (foundButton) { if (foundButton) {
update(foundButton); update(foundButton);
@ -160,8 +160,8 @@ export class EditorToolbar extends HTMLElement {
button: string | number = 0 button: string | number = 0
): void { ): void {
this.updateButtonGroup((component) => { this.updateButtonGroup((component) => {
component.buttons = insert( component.items = insert(
component.buttons as (ToolbarItem & Identifiable)[], component.items as (ToolbarItem & Identifiable)[],
newButton, newButton,
button button
); );
@ -174,8 +174,8 @@ export class EditorToolbar extends HTMLElement {
button: string | number = -1 button: string | number = -1
): void { ): void {
this.updateButtonGroup((component) => { this.updateButtonGroup((component) => {
component.buttons = add( component.items = add(
component.buttons as (ToolbarItem & Identifiable)[], component.items as (ToolbarItem & Identifiable)[],
newButton, newButton,
button button
); );

View file

@ -3,8 +3,15 @@
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent"; import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import type { SvelteComponentDev } from "svelte/internal"; import type { SvelteComponentDev } from "svelte/internal";
interface ToolbarItem<T extends typeof SvelteComponentDev = typeof SvelteComponentDev> export interface ToolbarItem<
extends DynamicSvelteComponent<T> { T extends typeof SvelteComponentDev = typeof SvelteComponentDev
> extends DynamicSvelteComponent<T> {
id?: string; id?: string;
hidden?: boolean; hidden?: boolean;
} }
export interface IterableToolbarItem<
T extends typeof SvelteComponentDev = typeof SvelteComponentDev
> extends ToolbarItem<T> {
items: ToolbarItem[];
}

View file

@ -1,8 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type WithShortcut from "editor-toolbar/WithShortcut.svelte"; import type { ToolbarItem } from "editor-toolbar/types";
import type { WithShortcutProps } from "editor-toolbar/WithShortcut";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
import { iconButton, withShortcut } from "editor-toolbar/dynamicComponents"; import { iconButton, withShortcut } from "editor-toolbar/dynamicComponents";
@ -40,8 +38,7 @@ function onCloze(event: KeyboardEvent | MouseEvent): void {
wrap(`{{c${highestCloze}::`, "}}"); wrap(`{{c${highestCloze}::`, "}}");
} }
export function getClozeButton(): DynamicSvelteComponent<typeof WithShortcut> & export function getClozeButton(): ToolbarItem {
WithShortcutProps {
return withShortcut({ return withShortcut({
id: "cloze", id: "cloze",
shortcut: "Control+Shift+KeyC", shortcut: "Control+Shift+KeyC",

View file

@ -1,8 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte"; import type { IterableToolbarItem } from "editor-toolbar/types";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import { import {
iconButton, iconButton,
@ -29,8 +27,7 @@ function wrapWithForecolor(color: string): void {
document.execCommand("forecolor", false, color); document.execCommand("forecolor", false, color);
} }
export function getColorGroup(): DynamicSvelteComponent<typeof ButtonGroup> & export function getColorGroup(): IterableToolbarItem {
ButtonGroupProps {
const forecolorButton = withShortcut({ const forecolorButton = withShortcut({
shortcut: "F7", shortcut: "F7",
button: iconButton({ button: iconButton({
@ -52,6 +49,6 @@ export function getColorGroup(): DynamicSvelteComponent<typeof ButtonGroup> &
return buttonGroup({ return buttonGroup({
id: "color", id: "color",
buttons: [forecolorButton, colorpickerButton], items: [forecolorButton, colorpickerButton],
}); });
} }

View file

@ -1,11 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte"; import type { IterableToolbarItem } from "editor-toolbar/types";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type ButtonDropdown from "editor-toolbar/ButtonDropdown.svelte";
import type { ButtonDropdownProps } from "editor-toolbar/ButtonDropdown";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import type { EditingArea } from "./editingArea"; import type { EditingArea } from "./editingArea";
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
@ -45,8 +40,7 @@ const indentListItem = () => {
} }
}; };
export function getFormatBlockMenus(): (DynamicSvelteComponent<typeof ButtonDropdown> & export function getFormatBlockMenus(): IterableToolbarItem[] {
ButtonDropdownProps)[] {
const justifyLeftButton = commandIconButton({ const justifyLeftButton = commandIconButton({
icon: justifyLeftIcon, icon: justifyLeftIcon,
command: "justifyLeft", command: "justifyLeft",
@ -73,7 +67,7 @@ export function getFormatBlockMenus(): (DynamicSvelteComponent<typeof ButtonDrop
const justifyGroup = buttonGroup({ const justifyGroup = buttonGroup({
id: "justify", id: "justify",
buttons: [ items: [
justifyLeftButton, justifyLeftButton,
justifyCenterButton, justifyCenterButton,
justifyRightButton, justifyRightButton,
@ -95,19 +89,18 @@ export function getFormatBlockMenus(): (DynamicSvelteComponent<typeof ButtonDrop
const indentationGroup = buttonGroup({ const indentationGroup = buttonGroup({
id: "indentation", id: "indentation",
buttons: [outdentButton, indentButton], items: [outdentButton, indentButton],
}); });
const formattingOptions = buttonDropdown({ const formattingOptions = buttonDropdown({
id: "listFormatting", id: "listFormatting",
buttons: [justifyGroup, indentationGroup], items: [justifyGroup, indentationGroup],
}); });
return [formattingOptions]; return [formattingOptions];
} }
export function getFormatBlockGroup(): DynamicSvelteComponent<typeof ButtonGroup> & export function getFormatBlockGroup(): IterableToolbarItem {
ButtonGroupProps {
const ulButton = commandIconButton({ const ulButton = commandIconButton({
icon: ulIcon, icon: ulIcon,
command: "insertUnorderedList", command: "insertUnorderedList",
@ -131,6 +124,6 @@ export function getFormatBlockGroup(): DynamicSvelteComponent<typeof ButtonGroup
return buttonGroup({ return buttonGroup({
id: "blockFormatting", id: "blockFormatting",
buttons: [ulButton, olButton, listFormatting], items: [ulButton, olButton, listFormatting],
}); });
} }

View file

@ -1,8 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte"; import type { IterableToolbarItem } from "editor-toolbar/types";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
import { import {
@ -19,8 +17,7 @@ import superscriptIcon from "./format-superscript.svg";
import subscriptIcon from "./format-subscript.svg"; import subscriptIcon from "./format-subscript.svg";
import eraserIcon from "./eraser.svg"; import eraserIcon from "./eraser.svg";
export function getFormatInlineGroup(): DynamicSvelteComponent<typeof ButtonGroup> & export function getFormatInlineGroup(): IterableToolbarItem {
ButtonGroupProps {
const boldButton = withShortcut({ const boldButton = withShortcut({
shortcut: "Control+KeyB", shortcut: "Control+KeyB",
button: commandIconButton({ button: commandIconButton({
@ -79,7 +76,7 @@ export function getFormatInlineGroup(): DynamicSvelteComponent<typeof ButtonGrou
return buttonGroup({ return buttonGroup({
id: "inlineFormatting", id: "inlineFormatting",
buttons: [ items: [
boldButton, boldButton,
italicButton, italicButton,
underlineButton, underlineButton,

View file

@ -1,8 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte"; import type { IterableToolbarItem } from "editor-toolbar/types";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import { bridgeCommand } from "lib/bridgecommand"; import { bridgeCommand } from "lib/bridgecommand";
import * as tr from "lib/i18n"; import * as tr from "lib/i18n";
@ -12,8 +10,7 @@ import {
withShortcut, withShortcut,
} from "editor-toolbar/dynamicComponents"; } from "editor-toolbar/dynamicComponents";
export function getNotetypeGroup(): DynamicSvelteComponent<typeof ButtonGroup> & export function getNotetypeGroup(): IterableToolbarItem {
ButtonGroupProps {
const fieldsButton = labelButton({ const fieldsButton = labelButton({
onClick: () => bridgeCommand("fields"), onClick: () => bridgeCommand("fields"),
disables: false, disables: false,
@ -33,6 +30,6 @@ export function getNotetypeGroup(): DynamicSvelteComponent<typeof ButtonGroup> &
return buttonGroup({ return buttonGroup({
id: "notetype", id: "notetype",
buttons: [fieldsButton, cardsButton], items: [fieldsButton, cardsButton],
}); });
} }

View file

@ -1,10 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type DropdownMenu from "editor-toolbar/DropdownMenu.svelte"; import type { IterableToolbarItem } from "editor-toolbar/types";
import type { DropdownMenuProps } from "editor-toolbar/DropdownMenu";
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type { DynamicSvelteComponent } from "sveltelib/dynamicComponent";
import { bridgeCommand } from "lib/bridgecommand"; import { bridgeCommand } from "lib/bridgecommand";
import { import {
@ -40,8 +36,7 @@ function onHtmlEdit(): void {
const mathjaxMenuId = "mathjaxMenu"; const mathjaxMenuId = "mathjaxMenu";
export function getTemplateGroup(): DynamicSvelteComponent<typeof ButtonGroup> & export function getTemplateGroup(): IterableToolbarItem {
ButtonGroupProps {
const attachmentButton = withShortcut({ const attachmentButton = withShortcut({
shortcut: "F3", shortcut: "F3",
button: iconButton({ button: iconButton({
@ -80,7 +75,7 @@ export function getTemplateGroup(): DynamicSvelteComponent<typeof ButtonGroup> &
return buttonGroup({ return buttonGroup({
id: "template", id: "template",
buttons: [ items: [
attachmentButton, attachmentButton,
recordButton, recordButton,
getClozeButton(), getClozeButton(),
@ -90,8 +85,7 @@ export function getTemplateGroup(): DynamicSvelteComponent<typeof ButtonGroup> &
}); });
} }
export function getTemplateMenus(): (DynamicSvelteComponent<typeof DropdownMenu> & export function getTemplateMenus(): IterableToolbarItem[] {
DropdownMenuProps)[] {
const mathjaxMenuItems = [ const mathjaxMenuItems = [
withShortcut({ withShortcut({
shortcut: "Control+KeyM, KeyM", shortcut: "Control+KeyM, KeyM",
@ -142,7 +136,7 @@ export function getTemplateMenus(): (DynamicSvelteComponent<typeof DropdownMenu>
const mathjaxMenu = dropdownMenu({ const mathjaxMenu = dropdownMenu({
id: mathjaxMenuId, id: mathjaxMenuId,
menuItems: [...mathjaxMenuItems, ...latexMenuItems], items: [...mathjaxMenuItems, ...latexMenuItems],
}); });
return [mathjaxMenu]; return [mathjaxMenu];

View file

@ -1,8 +1,6 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { ToolbarItem } from "editor-toolbar/types"; import type { ToolbarItem, IterableToolbarItem } from "editor-toolbar/types";
import type ButtonGroup from "editor-toolbar/ButtonGroup.svelte";
import type { ButtonGroupProps } from "editor-toolbar/ButtonGroup";
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store";
import { getNotetypeGroup } from "./notetype"; import { getNotetypeGroup } from "./notetype";
@ -16,10 +14,8 @@ export function initToolbar(i18n: Promise<void>): void {
i18n.then(() => { i18n.then(() => {
globalThis.$editorToolbar.buttonsPromise.then( globalThis.$editorToolbar.buttonsPromise.then(
( (
buttons: Writable< buttons: Writable<IterableToolbarItem[]>
(ToolbarItem<typeof ButtonGroup> & ButtonGroupProps)[] ): Writable<IterableToolbarItem[]> => {
>
): Writable<(ToolbarItem<typeof ButtonGroup> & ButtonGroupProps)[]> => {
buttons.update(() => [ buttons.update(() => [
getNotetypeGroup(), getNotetypeGroup(),
getFormatInlineGroup(), getFormatInlineGroup(),