add toolbar builder
This commit is contained in:
114
src/lib/Toolbar.ts
Normal file
114
src/lib/Toolbar.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { createAttachmentKey, type Attachment } from 'svelte/attachments';
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
|
||||
export type ToolbarToggleState = 'on' | 'off';
|
||||
|
||||
/**
|
||||
* Defines options that may be passed when creating a toggleable toolbar item.
|
||||
*/
|
||||
export type ToolbarToggleOptions = {
|
||||
state?: Writable<ToolbarToggleState>;
|
||||
};
|
||||
|
||||
/** toggleValue swaps a toolbar toggle state to on or off, based on current state. */
|
||||
const toggleValue = (current: ToolbarToggleState): ToolbarToggleState =>
|
||||
current === 'on' ? 'off' : 'on';
|
||||
|
||||
/** createGenericToggle creates a toggle. If a list of toggles is passed, the toggle is created as a group item */
|
||||
const createGenericToggle = (
|
||||
toggles: Writable<ToolbarToggleState>[] | null,
|
||||
opts: ToolbarToggleOptions = {}
|
||||
) => {
|
||||
const toggleState = opts.state ?? writable<ToolbarToggleState>('off');
|
||||
// If this is a group, add this toggle to it
|
||||
if (toggles !== null) toggles.push(toggleState);
|
||||
|
||||
return {
|
||||
state: toggleState,
|
||||
[createAttachmentKey()]: ((node) => {
|
||||
const el = node as HTMLElement;
|
||||
// Subscribe to store
|
||||
const unsubscribe = toggleState.subscribe((state) => {
|
||||
el.dataset.state = state;
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}) as Attachment,
|
||||
onclick: (e: MouseEvent) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
if (!target) return;
|
||||
|
||||
toggleState.update(toggleValue);
|
||||
|
||||
// If this is a group, turn off all other toggles
|
||||
if (toggles !== null) {
|
||||
toggles.forEach((toggle) => {
|
||||
if (toggle !== toggleState) {
|
||||
toggle.update(() => 'off');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* A group of toggles in a toolbar. Makes each toggle exclusive of the others, disabling all other
|
||||
* toggles when any given toggle is enabled.
|
||||
*/
|
||||
export class ToolbarGroup {
|
||||
private _name: string;
|
||||
private _toggles: Writable<ToolbarToggleState>[] = [];
|
||||
|
||||
constructor(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the toolbar group.
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new toolbar toogle item in the group.
|
||||
* @param opts
|
||||
* @returns object containing state and properties
|
||||
*/
|
||||
toggle(opts: ToolbarToggleOptions = {}) {
|
||||
return createGenericToggle(this._toggles, opts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the top-level toolbar groups.
|
||||
*/
|
||||
export class Toolbar {
|
||||
private _groups: ToolbarGroup[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Creates a new toolbar group.
|
||||
* @param name The name of the group.
|
||||
* @returns The newly created toolbar group.
|
||||
*/
|
||||
group(name: string) {
|
||||
if (this._groups.some((g) => g.name === name)) {
|
||||
throw new Error(`Toolbar group "${name}" already exists.`);
|
||||
}
|
||||
const g = new ToolbarGroup(name);
|
||||
this._groups.push(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new toolbar toggle item.
|
||||
* @param opts
|
||||
* @returns object containing state and properties
|
||||
*/
|
||||
toggle(opts: ToolbarToggleOptions = {}) {
|
||||
return createGenericToggle(null, opts);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user