@wener/console
Version:
Base console UI toolkit
123 lines (122 loc) • 4.02 kB
JavaScript
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