UNPKG

@wener/console

Version:

Base console UI toolkit

123 lines (122 loc) 4.02 kB
import React, { cloneElement, isValidElement, useEffect, useRef } from "react"; import { createPortal } from "react-dom"; import { PiBrowser } from "react-icons/pi"; import { getGlobalStates } from "@wener/utils"; import { uniqBy } from "es-toolkit"; import { createStore, useStore } from "zustand"; import { mutative } from "zustand-mutative"; import { ConsoleEvents, getConsoleContext } from "../context.js"; function createLauncherStore() { return createStore(mutative(() => { return { open: false, items: [] }; })); } function LauncherHost() { const emitter = getConsoleContext().getEmitter(); useEffect(() => { return emitter.on(ConsoleEvents.LauncherToggle, ({ open }) => { Launcher.toggle(open); }); }, [ emitter ]); let store = Launcher.useStore(); let open = useStore(store, (s) => s.open); if (!open) { return null; } return /*#__PURE__*/ createPortal(/*#__PURE__*/ React.createElement(LauncherContent, { onLaunch: (v) => { v.onLaunch?.(); } }), document.body, "Launcher"); } /** * @deprecated use {@link Launcher.Host} instead */ export const ConsoleLauncher = LauncherHost; const LauncherContent = ({ onLaunch }) => { let store = Launcher.useStore(); const { items } = store.getState(); const ref = useRef(null); useEffect(() => { ref.current?.focus(); }, [ ref.current ]); // note 左侧留出来 dock 的位置 // dismiss layer // esc to close // 初次渲染自动获取 focus return /*#__PURE__*/ React.createElement("div", { className: "absolute inset-0 z-[100]", onClick: () => { store.setState({ open: false }); }, tabIndex: -1, onKeyDown: (e) => { if (e.key === "Escape") { store.setState({ open: false }); } }, ref: ref }, /*#__PURE__*/ React.createElement("div", { className: "absolute inset-0 left-14 bg-base-300/20 backdrop-blur" }, /*#__PURE__*/ React.createElement("div", { className: "flex flex-wrap gap-10 px-20 py-10" }, items.map((v) => { const { key, title, icon } = v; let ico = icon || /*#__PURE__*/ React.createElement(PiBrowser, null); if ( /*#__PURE__*/isValidElement(ico)) { ico = /*#__PURE__*/ cloneElement(ico, { className: "w-24 h-24 drop-shadow-lg" }); } return /*#__PURE__*/ React.createElement("button", { key: key, type: "button", className: "flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-300/0 p-2 pt-1 transition-all hover:bg-gray-300/40", onClick: () => { onLaunch?.(v); } }, /*#__PURE__*/ React.createElement("div", null, ico), /*#__PURE__*/ React.createElement("div", { className: "text-sm" }, title)); })))); }; (function (Launcher) { let _getStore = () => getGlobalStates("LauncherStore", createLauncherStore); function setStoreProvider(provider) { _getStore = provider; } Launcher.setStoreProvider = setStoreProvider; function getStore() { return _getStore(); } Launcher.getStore = getStore; function useStore() { return getStore(); } Launcher.useStore = useStore; Launcher.Host = LauncherHost; function toggle(open) { getStore().setState((s) => { s.open = open ?? !s.open; }); } Launcher.toggle = toggle; function addItems(items) { getStore().setState((s) => { s.items = uniqBy(s.items.concat(items), (v) => v.key).sort((a, b) => a.title.localeCompare(b.title)); }); } Launcher.addItems = addItems; })(Launcher || (Launcher = {})); export var Launcher; //# sourceMappingURL=Launcher.js.map