UNPKG

@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
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; }