# DragonFlagon Module Buttons Library ![Forge Installs](https://img.shields.io/badge/dynamic/json?color=red&label=Forge%20Installs&query=package.installs&suffix=%25&url=https%3A%2F%2Fforge-vtt.com%2Fapi%2Fbazaar%2Fpackage%2Flib-df-buttons) ![Latest Version](https://img.shields.io/badge/dynamic/json?label=Latest%20Release&prefix=v&query=package.versions%5B0%5D&url=https%3A%2F%2Fforge-vtt.com%2Fapi%2Fbazaar%2Fpackage%2Flib-df-buttons) [![Foundry Hub Endorsements](https://img.shields.io/endpoint?logoColor=white&url=https%3A%2F%2Fwww.foundryvtt-hub.com%2Fwp-json%2Fhubapi%2Fv1%2Fpackage%2Flib-df-buttons%2Fshield%2Fendorsements)](https://www.foundryvtt-hub.com/package/lib-df-buttons/) Library for Foundry VTT module developers to use. It allows modules to register control buttons that appear on the right side of the screen. ![image-20211107113847436](../.assets/lib-df-buttons/cover.png) ##### [![become a patron](../.assets/patreon-image.png)](https://www.patreon.com/bePatron?u=46113583) If you want to support me or just help me buy doggy treats! Also, you can keep up to date on what I'm working on. I will be announcing any new modules or pre-releases there for anyone wanting to help me test things out! # For Module Developers ## How to Use All modules that wish to use the library should declare a dependency in their manifest as follows: ```json "dependencies": [ { "name": "lib-df-buttons" } ] ``` ## How to Register Buttons The library uses Hooks in the same way that the `SceneControls` class does. This Hook call receives a list of `ToolGroup` objects which can be appended to. ```JavaScript Hooks.on('getModuleToolGroups', (controlManager/*: ControlManager*/, groups /*: ToolGroup[]*/) => { groups.push({ name: 'my-tool-group',// Unique group ID icon: '',// HTMLElement to be used as an Icon title: 'My Tool Group',// Plain text or a localization key tools: [ { name: 'my-tool',// Unique tool ID within the scope of the parent Group title: 'My Special Tool',// Plain text or a localization key onClick: () => console.log("I've been clicked!"),// Click handler icon: '',// HTMLElement to be used as an Icon button: true // This tool is just a button }, ... ] }); }); ``` By default, all `ToolGroup` and `Tool` configurations use a Radial Behaviour. This can be changed by setting either `button: true` or `toggle: true`. ## Configuration Interfaces ```TypeScript /** Standard single parameter handler */ export type Handler = (value?: T) => (Promise | void); /** Standard boolean logic predicate */ export type Predicate = () => (Promise | boolean); /** * Tool Configuration for tools that appear on the secondary bar when their * parent group is active. */ export interface Tool { /** Unique name ID of the Tool */ name: string; /** Plain Text or a Localization Key */ title: string; /** HTMLElement to be used as an icon */ icon: string; /** * (default: false) If true, the tool will act as a simple button. * Must implement {@link onClick} */ button?: boolean | null; /** * (default: false) If true, the tool will act as a toggle button. * Must implement {@link onClick} */ toggle?: boolean | null; /** * (default: null) Used to add your own custom class name to the generated * control. */ class?: string | null; /** * (default: false) Indicates your button or {@link ToolGroup} should be * allowed to render when there is no game board canvas. */ noCanvas?: boolean; /** * (default: false) If {@link toggle} is true, this holds the toggle * button's state. If {@link toggle} and {@link button} are false, this * holds the activation state of the control and will be overridden by the * {@link ControlManager}. */ isActive?: Predicate | boolean | null; /** * (default: true) Sets the visibility of the tool. Can be a function or a * boolean value */ visible?: Predicate | boolean | null; /** * A click handler that is invoked when ever the tool is pressed. This * function is given an `active` state when either the default Radial or set * as a toggle button. * * If the Handler is unbound, it will be bound to the {@link Tool} instance it belongs to. * * - Radial Button (default): Invoked with `active:false` when deactivated, or `active:true` when activated. * - Toggle Button: Invoked with the new toggled state (true|false). * - Button: Invoked with no parameters. */ onClick?: Handler | null; } /** * A collection of Tools that appear on the main bar */ export interface ToolGroup extends Tool { /** {@link Tool} collection */ tools?: Tool[]; /** * {@link Tool.name} of tool to be active. Defaults to the first tool in * the {@link tools} list. */ activeTool?: string; } /** Manages the button UI, Hooks, and User Interactions. */ export interface ControlManager { /** Complete list of {@link ToolGroup} objects. */ get groups(): ToolGroup[]; /** Name of currently active {@link ToolGroup}. */ get activeGroupName(): string; /** Name of the currently active {@link Tool}. */ get activeToolName(): string; /** The currently active {@link ToolGroup} object. */ get activeGroup(): ToolGroup; /** The currently active {@link Tool} object. */ get activeTool(): Tool; /** * Activates a {@link ToolGroup} by its unique name. * @param groupName Name of the group to be activated. */ activateGroupByName(groupName: string): Promise; /** * Activates a {@link Tool} inside the given {@link ToolGroup} via their unique names. * @param groupName Name of group that contains the {@link Tool}. * @param toolName Name of the {@link Tool} to be activated. * @param activateGroup (Default true) Also activate the {@link ToolGroup}. */ activateToolByName(groupName: string, toolName: string, activateGroup?: boolean): Promise; /** Reload the module buttons bar by rebuilding the {@link ToolGroup}s and rerendering. */ reloadModuleButtons(): void; /** Refresh the button UI to reflect any external changes made */ refresh(): void; } ``` ## Hooks This library leverages the Hooks system for all of its interactions. This makes it easier for developers to register Tools/ToolGroups, or to listen to when groups or tools are activated. As well as to activate a Tool or ToolGroup programmatically. ### Hooks that are broadcast ```typescript /* Pre-ToolGroup populator. Invoked immediately before `getModuleToolGroups` */ Hooks.on('getModuleToolGroupsPre', (app: ControlManager, groups: ToolGroup[]) => {}); /* General request used to populate the list of Tool Groups and their collections of Tools */ Hooks.on('getModuleToolGroups', (app: ControlManager, groups: ToolGroup[]) => {}); /* Post-ToolGroup populator. Invoked immediately after `getModuleToolGroups` */ Hooks.on('getModuleToolGroupsPost', (app: ControlManager, groups: ToolGroup[]) => {}); /* Broadcast when a group has been activated, and the activated `ToolGroup` instance is passed to it */ Hooks.on('toolGroupActivated', (app: ControlManager, groups: ToolGroup[]) => {}); /* Broadcast when a Tool has been activated, and the parent `ToolGroup` and activated `Tool` instances are passed to it */ Hooks.on('toolActivated', (app: ControlManager, groups: ToolGroup[]) => {}); /* Broadcast when a request has been made to tear down and rebuild the module buttons. Called whenever `ControlManager.reloadModuleButtons()` is invoked */ Hooks.on('moduleButtonsReloading', (app: ControlManager) => {}); ``` ### Hooks that are monitored ```typescript /* Invoking this Hook will tell the ControlManager to activate the named ToolGroup */ Hooks.call('activateGroupByName', "my-group-name"); /* Invoking this Hook will tell the ControlManager to activate the named Tool that * belongs to the named ToolGroup. You can also pass `true` as a 3rd parameter to * have the ToolGroup also activated. (default: false) */ Hooks.call('activateToolByName', "my-group-name", "my-tool-name", true); /* Invoking this Hook will cause the ControlManager destroy the current ToolGroup * collection and re-build it, calling `getModuleToolGroupsPre`, `getModuleToolGroups`, * and `getModuleToolGroupsPost` as before. It then renders the new list of ToolGroups. */ Hooks.call('reloadModuleButtons'); /* Invoking this Hook will refresh the button UI to reflect any external changes made. */ Hooks.call('refreshModuleButtons'); ```