@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
235 lines (234 loc) • 9.23 kB
TypeScript
import type { Context } from "../../engine_context.js";
import { NeedleLogoElement } from "../logo-element.js";
declare global {
interface HTMLElementTagNameMap {
"needle-logo-element": NeedleLogoElement;
}
}
/** This is the model for the postMessage event that the needle engine will send to create menu items */
export declare type NeedleMenuPostMessageModel = {
type: "needle:menu";
button?: {
label?: string;
/** Google icon name */
icon?: string;
/** currently only URLs are supported */
onclick?: string;
target?: "_blank" | "_self" | "_parent" | "_top";
/** Low priority is icon is on the left, high priority is icon is on the right. Default is 0 */
priority?: number;
};
};
/**
* Used by the NeedleMenuElement to create a button at {@link NeedleMenuElement#appendChild}
*/
export declare type ButtonInfo = {
/** Invoked when the button is clicked */
onClick: (evt: Event) => void;
/** Visible button text */
label: string;
/** Material icon name: https://fonts.google.com/icons */
icon?: string;
/** "left" or "right" to place the icon on the left or right side of the button. Default is "left" */
iconSide?: "left" | "right";
/**
* Priority controls the order of buttons in the menu.
* If not enough space is available to show all buttons - the highest priority elements will always be visible
*
* **Sorting**
* Low priority is icon is on the left,
* high priority is icon is on the right.
* @default undefined
*/
priority?: number;
/** Experimental. Allows to put two buttons in one row for the compact layout */
class?: "row2";
title?: string;
};
/**
* The NeedleMenu is a menu that can be displayed in the needle engine webcomponent or in VR/AR sessions.
*
* The menu can be used to add buttons to the needle engine that can be used to interact with the application.
*
* The menu can be positioned at the top or the bottom of the <needle-engine> webcomponent.
*
* @example Add a new button using the NeedleMenu
* ```typescript
* onStart(ctx => {
* ctx.menu.appendChild({
* label: "Open Google",
* icon: "google",
* onClick: () => { window.open("https://www.google.com", "_blank") }
* });
* })
* ```
*
* Buttons can be added to the menu using the {@link NeedleMenu#appendChild} method or by sending a postMessage event to the needle engine with the type "needle:menu". Use the {@link NeedleMenuPostMessageModel} model to create buttons with postMessage.
* @example Create a button using a postmessage
* ```javascript
* window.postMessage({
* type: "needle:menu",
* button: {
* label: "Open Google",
* icon: "google",
* onclick: "https://www.google.com",
* target: "_blank",
* }
* }, "*");
* ```
*
* @example Access the menu from a component
* ```typescript
* import { Behaviour, OnStart } from '@needle-tools/engine';
*
* export class MyComponent extends Behaviour {
*
* start() {
* this.context.menu.appendChild({ ... });
* }
* }
* ```
*
* @category HTML
*/
export declare class NeedleMenu {
static setElementPriority(button: HTMLElement, priority: number): void;
static getElementPriority(button: HTMLElement): number | undefined;
private readonly _context;
private readonly _menu;
private readonly _spatialMenu;
constructor(context: Context);
/** @ignore internal method */
onDestroy(): void;
private onPostMessage;
private onStartXR;
private onExitXR;
/** Experimental: Change the menu position to be at the top or the bottom of the needle engine webcomponent
* @param position "top" or "bottom"
*/
setPosition(position: "top" | "bottom"): void;
/**
* Call to show or hide the menu.
* NOTE: Hiding the menu is a PRO feature and requires a needle engine license. Hiding the menu will not work in production without a license.
*/
setVisible(visible: boolean): void;
/** When set to false, the Needle Engine logo will be hidden. Hiding the logo requires a needle engine license */
showNeedleLogo(visible: boolean): void;
/** @returns true if the logo is visible */
get logoIsVisible(): boolean;
/** When enabled=true the menu will be visible in VR/AR sessions */
showSpatialMenu(enabled: boolean): void;
setSpatialMenuVisible(display: boolean): void;
get spatialMenuIsVisible(): boolean | undefined;
/**
* Call to add or remove a button to the menu to show a QR code for the current page
* If enabled=true then a button will be added to the menu that will show a QR code for the current page when clicked.
*/
showQRCodeButton(enabled: boolean | "desktop-only"): HTMLButtonElement | null;
/** Call to add or remove a button to the menu to mute or unmute the application
* Clicking the button will mute or unmute the application
*/
showAudioPlaybackOption(visible: boolean): void;
private _muteButton?;
showFullscreenOption(visible: boolean): void;
private _fullscreenButton?;
appendChild(child: HTMLElement | ButtonInfo): HTMLElement;
}
/**
* `<needle-menu>` web component — lightweight menu used by Needle Engine.
*
* This element is intended as an internal UI primitive for hosting application
* menus and buttons. Use the higher-level `NeedleMenu` API from the engine
* code to manipulate it programmatically. Public DOM-facing methods are
* documented (appendChild / append / prepend / setPosition / setVisible).
*
* @element needle-menu
*/
export declare class NeedleMenuElement extends HTMLElement {
#private;
static create(): HTMLElement;
static getOrCreate(domElement: HTMLElement, context: Context): NeedleMenuElement;
private _domElement;
private _context;
private _didInitialize;
constructor();
private initializeDom;
ensureInitialized(): void;
private _sizeChangeInterval;
connectedCallback(): void;
disconnectedCallback(): void;
/** @private user preference for logo visibility */
private _userRequestedLogoVisible?;
showNeedleLogo(visible: boolean): void;
/** @returns true if the logo is visible */
get logoIsVisible(): boolean;
private ___onSetLogoVisible;
setPosition(position: "top" | "bottom"): void;
/** @private user preference for menu visibility */
private _userRequestedMenuVisible?;
setVisible(visible: boolean): void;
/**
* If the menu is in compact mode and the foldout is currently open (to show all menu options) then this will close the foldout
*/
closeFoldout(): void;
/** @private root container element inside shadow DOM */
private root;
/** @private wraps the whole content (internal layout) */
private wrapper;
/** @private contains the buttons and dynamic elements */
private options;
/** @private contains options visible when in compact mode */
private optionsCompactMode;
/** @private contains the needle-logo html element */
private logoContainer;
/** @private compact menu button element */
private compactMenuButton;
/** @private foldout container used in compact mode */
private foldout;
private readonly trackedElements;
private trackElement;
append(...nodes: (string | Node)[]): void;
/**
* Appends a button or HTML element to the needle-menu options.
* @param node a Node or ButtonInfo to create a button from
* @returns the appended Node
*
* @example Append a button
* ```javascript
* const button = document.createElement("button");
* button.textContent = "Click Me";
* needleMenu.appendChild(button);
* ```
* @example Append a button using ButtonInfo
* ```javascript
* needleMenu.appendChild({
* label: "Click Me",
* onClick: () => { alert("Button clicked!"); },
* icon: "info",
* title: "This is a button",
* });
* ```
*/
appendChild<T extends Node>(node: T | ButtonInfo): T;
prepend(...nodes: (string | Node)[]): void;
private _isHandlingChange;
/** During modification of options container (e.g. when moving items into the extra buttons container) the mutation observer should not trigger an update event immediately. This is a workaround for the total size required for all elements not being calculated reliably. */
private _pauseMutationObserverOptionsContainer;
/** Called when any change in the web component is detected (including in children and child attributes) */
private onChangeDetected;
private onOptionsChildrenChanged;
private _didSort;
/** checks if the menu has any content and should be rendered at all
* if we dont have any content and logo then we hide the menu
*/
private handleMenuVisible;
/** @returns true if we have any content OR a logo */
get hasAnyContent(): boolean;
get hasAnyVisibleOptions(): boolean;
private _lastAvailableWidthChange;
private _timeoutHandleSize;
private _timeoutHandleCompactItems;
private handleSizeChange;
private updateCompactFoldoutItem;
private ___insertDebugOptions;
}