Add ButtonToolbarItem as interface for modifying button groups

This commit is contained in:
Henrik Giesel 2021-05-06 19:26:50 +02:00
parent 4a6b3b3786
commit 928f486867
11 changed files with 145 additions and 14 deletions

View file

@ -63,7 +63,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const hideButton = (id: Identifier) => const hideButton = (id: Identifier) =>
updateRegistration(({ detach }) => detach.set(true), id); updateRegistration(({ detach }) => detach.set(true), id);
const toggleButton = (id: Identifier) => const toggleButton = (id: Identifier) =>
updateRegistration(({ detach }) => detach.update((old) => !old), id); updateRegistration(
({ detach }) => detach.update((old: boolean): boolean => !old),
id
);
Object.assign(api, { Object.assign(api, {
insertButton, insertButton,

View file

@ -3,13 +3,76 @@ 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
--> -->
<script lang="typescript"> <script lang="typescript">
import { setContext } from "svelte";
import { writable } from "svelte/store";
import ButtonToolbarItem from "./ButtonToolbarItem.svelte";
import type { ButtonGroupRegistration } from "./buttons";
import { buttonToolbarKey } from "./contextKeys";
import type { Identifier } from "./identifier";
import { insert, add } from "./identifier";
import type { SvelteComponent } from "./registration";
import { makeInterface } from "./registration";
export let id: string | undefined = undefined; export let id: string | undefined = undefined;
let className: string | undefined; let className: string = "";
export { className as class }; export { className as class };
export let nowrap = false; export let nowrap = false;
function makeRegistration(): ButtonGroupRegistration {
const detach = writable(false);
return { detach };
}
const { registerComponent, dynamicItems, getDynamicInterface } = makeInterface(
makeRegistration
);
setContext(buttonToolbarKey, registerComponent);
export let api = {};
let buttonToolbarRef: HTMLDivElement;
$: if (buttonToolbarRef) {
const { addComponent, updateRegistration } = getDynamicInterface(
buttonToolbarRef
);
const insertGroup = (button: SvelteComponent, position: Identifier = 0) =>
addComponent(button, (added, parent) => insert(added, parent, position));
const appendGroup = (button: SvelteComponent, position: Identifier = -1) =>
addComponent(button, (added, parent) => add(added, parent, position));
const showGroup = (id: Identifier) =>
updateRegistration(({ detach }) => detach.set(false), id);
const hideGroup = (id: Identifier) =>
updateRegistration(({ detach }) => detach.set(true), id);
const toggleGroup = (id: Identifier) =>
updateRegistration(
({ detach }) => detach.update((old: boolean): boolean => !old),
id
);
Object.assign(api, {
insertGroup,
appendGroup,
showGroup,
hideGroup,
toggleGroup,
});
}
</script> </script>
<div {id} class={`btn-toolbar ${className}`} class:flex-nowrap={nowrap} role="toolbar"> <div
bind:this={buttonToolbarRef}
{id}
class={`btn-toolbar ${className}`}
class:flex-nowrap={nowrap}
role="toolbar">
<slot /> <slot />
{#each $dynamicItems as item}
<ButtonToolbarItem id={item[0].id} registration={item[1]}>
<svelte:component this={item[0].component} {...item[0].props} />
</ButtonToolbarItem>
{/each}
</div> </div>

View file

@ -0,0 +1,44 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import Detachable from "components/Detachable.svelte";
import type { ButtonGroupRegistration } from "./buttons";
import type { Register } from "./registration";
import { getContext, hasContext } from "svelte";
import { buttonToolbarKey } from "./contextKeys";
export let id: string | undefined = undefined;
export let registration: ButtonGroupRegistration | undefined = undefined;
let detach_: boolean;
if (registration) {
const { detach } = registration;
detach.subscribe((value: boolean) => (detach_ = value));
} else if (hasContext(buttonToolbarKey)) {
const registerComponent = getContext<Register<ButtonGroupRegistration>>(
buttonToolbarKey
);
const { detach } = registerComponent();
detach.subscribe((value: boolean) => (detach_ = value));
} else {
detach_ = false;
}
</script>
<style lang="scss">
div {
display: contents;
}
</style>
<!-- div is necessary to preserve item position -->
<div {id}>
<Detachable detach={detach_}>
<slot />
</Detachable>
</div>

View file

@ -13,3 +13,7 @@ export interface ButtonRegistration {
detach: Writable<boolean>; detach: Writable<boolean>;
position: Writable<ButtonPosition>; position: Writable<ButtonPosition>;
} }
export interface ButtonGroupRegistration {
detach: Writable<boolean>;
}

View file

@ -3,5 +3,6 @@
export const nightModeKey = Symbol("nightMode"); export const nightModeKey = Symbol("nightMode");
export const disabledKey = Symbol("disabled"); export const disabledKey = Symbol("disabled");
export const buttonToolbarKey = Symbol("buttonToolbar");
export const buttonGroupKey = Symbol("buttonGroup"); export const buttonGroupKey = Symbol("buttonGroup");
export const dropdownKey = Symbol("dropdown"); export const dropdownKey = Symbol("dropdown");

View file

@ -34,7 +34,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</script> </script>
<ButtonGroup id="color" {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<WithShortcut shortcut="F7" let:createShortcut let:shortcutLabel> <WithShortcut shortcut="F7" let:createShortcut let:shortcutLabel>
<IconButton <IconButton

View file

@ -48,6 +48,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import WithTheming from "components/WithTheming.svelte"; import WithTheming from "components/WithTheming.svelte";
import StickyBar from "components/StickyBar.svelte"; import StickyBar from "components/StickyBar.svelte";
import ButtonToolbar from "components/ButtonToolbar.svelte"; import ButtonToolbar from "components/ButtonToolbar.svelte";
import ButtonToolbarItem from "components/ButtonToolbarItem.svelte";
import NoteTypeButtons from "./NoteTypeButtons.svelte"; import NoteTypeButtons from "./NoteTypeButtons.svelte";
import FormatInlineButtons from "./FormatInlineButtons.svelte"; import FormatInlineButtons from "./FormatInlineButtons.svelte";
@ -55,6 +56,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import ColorButtons from "./ColorButtons.svelte"; import ColorButtons from "./ColorButtons.svelte";
import TemplateButtons from "./TemplateButtons.svelte"; import TemplateButtons from "./TemplateButtons.svelte";
export const toolbar = {};
export const notetypeButtons = {}; export const notetypeButtons = {};
export const formatInlineButtons = {}; export const formatInlineButtons = {};
export const formatBlockButtons = {}; export const formatBlockButtons = {};
@ -76,12 +78,26 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<WithTheming {style}> <WithTheming {style}>
<StickyBar> <StickyBar>
<ButtonToolbar> <ButtonToolbar api={toolbar}>
<NoteTypeButtons api={notetypeButtons} /> <ButtonToolbarItem id="notetype">
<FormatInlineButtons api={formatInlineButtons} /> <NoteTypeButtons api={notetypeButtons} />
<FormatBlockButtons api={formatBlockButtons} /> </ButtonToolbarItem>
<ColorButtons api={colorButtons} />
<TemplateButtons api={templateButtons} /> <ButtonToolbarItem id="inlineFormatting">
<FormatInlineButtons api={formatInlineButtons} />
</ButtonToolbarItem>
<ButtonToolbarItem id="blockFormatting">
<FormatBlockButtons api={formatBlockButtons} />
</ButtonToolbarItem>
<ButtonToolbarItem id="color">
<ColorButtons api={colorButtons} />
</ButtonToolbarItem>
<ButtonToolbarItem id="template">
<TemplateButtons api={templateButtons} />
</ButtonToolbarItem>
</ButtonToolbar> </ButtonToolbar>
</StickyBar> </StickyBar>
</WithTheming> </WithTheming>

View file

@ -43,7 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</script> </script>
<ButtonGroup id="blockFormatting" {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<WithState <WithState
key="insertUnorderedList" key="insertUnorderedList"

View file

@ -24,7 +24,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let api = {}; export let api = {};
</script> </script>
<ButtonGroup id="notetype" {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<WithShortcut shortcut="Control+KeyB" let:createShortcut let:shortcutLabel> <WithShortcut shortcut="Control+KeyB" let:createShortcut let:shortcutLabel>
<WithState <WithState

View file

@ -14,7 +14,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let api = {}; export let api = {};
</script> </script>
<ButtonGroup id="notetype" {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<LabelButton <LabelButton
disables={false} disables={false}

View file

@ -34,7 +34,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</script> </script>
<ButtonGroup id="template" {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<WithShortcut shortcut="F3" let:createShortcut let:shortcutLabel> <WithShortcut shortcut="F3" let:createShortcut let:shortcutLabel>
<IconButton <IconButton