portal is the answer I was looking for
This commit is contained in:
parent
2ec83e2ccb
commit
4b3d91d6cd
3 changed files with 76 additions and 80 deletions
|
@ -1,9 +1,9 @@
|
||||||
import { Component, JSX, ParentComponent, children, createContext, createRenderEffect, createUniqueId, mergeProps, onCleanup, useContext } from "solid-js";
|
import { Accessor, Component, For, JSX, ParentComponent, Setter, Show, children, createContext, createRenderEffect, createSignal, createUniqueId, mergeProps, onCleanup, useContext } from "solid-js";
|
||||||
import { isServer, ssr, useAssets } from "solid-js/web";
|
import { Portal, isServer, ssr, useAssets } from "solid-js/web";
|
||||||
|
|
||||||
export interface MenuContextType {
|
export interface MenuContextType {
|
||||||
add(item: Item): number;
|
ref(): JSX.Element|undefined;
|
||||||
remove(index: number): void;
|
// setRef(ref: JSX.Element|undefined): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Item {
|
export interface Item {
|
||||||
|
@ -15,35 +15,48 @@ export interface Item {
|
||||||
|
|
||||||
const MenuContext = createContext<MenuContextType>();
|
const MenuContext = createContext<MenuContextType>();
|
||||||
|
|
||||||
const initClientProvider = () => {
|
// const initClientProvider = (): MenuContextType => {
|
||||||
console.log(document.querySelector('[data-app-menu="root"]'));
|
// const root = document.querySelector('[data-app-menu="root"]');
|
||||||
console.log(document.querySelector('[data-app-menu="ssr-items"]'));
|
// const items = JSON.parse(document.querySelector('[data-app-menu="ssr-items"]')?.textContent ?? '[]');
|
||||||
|
|
||||||
return {
|
// console.log(items);
|
||||||
add(item: Item) {
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
remove(index: number) {},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const initServerProvider = () => {
|
// let _ref!: JSX.Element;
|
||||||
const items: Item[] = [];
|
|
||||||
|
|
||||||
useAssets(() => ssr(`<div data-app-menu="ssr-items">${JSON.stringify(items)}</div>`) as any);
|
// // useAssets(() => ssr(`<script type="application/json" data-app-menu="ssr-items">${JSON.stringify(items)}</script>`) as any);
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
add(item: Item) {
|
// ref() {
|
||||||
return items.push(item);
|
// return _ref;
|
||||||
},
|
// },
|
||||||
remove(index: number) {},
|
// setRef(ref: JSX.Element) {
|
||||||
};
|
// _ref = ref;
|
||||||
};
|
// },
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
export const MenuProvider: ParentComponent = (props) => {
|
// const initServerProvider = (): MenuContextType => {
|
||||||
const ctx = isServer ? initServerProvider() : initClientProvider();
|
// let _ref!: JSX.Element;
|
||||||
|
|
||||||
return <MenuContext.Provider value={ctx}>{props.children}</MenuContext.Provider>;
|
// // useAssets(() => ssr(`<script type="application/json" data-app-menu="ssr-items">${JSON.stringify(items)}</script>`) as any);
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// ref() {
|
||||||
|
// return _ref;
|
||||||
|
// },
|
||||||
|
// setRef(ref: JSX.Element) {
|
||||||
|
// _ref = ref;
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const MenuProvider: ParentComponent<{ root?: JSX.Element }> = (props) => {
|
||||||
|
// const ctx = isServer ? initServerProvider() : initClientProvider();
|
||||||
|
|
||||||
|
// const [ ref, setRef ] = createSignal<JSX.Element>();
|
||||||
|
// const ctx = {ref, setRef};
|
||||||
|
|
||||||
|
return <MenuContext.Provider value={{ ref: () => props.root }}>{props.children}</MenuContext.Provider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useMenu = () => {
|
const useMenu = () => {
|
||||||
|
@ -56,7 +69,7 @@ const useMenu = () => {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MenuItem: ParentComponent<{ label: string }> = (props) => {
|
const Item: ParentComponent<{ label: string }> = (props) => {
|
||||||
const childItems = children(() => props.children);
|
const childItems = children(() => props.children);
|
||||||
|
|
||||||
return mergeProps(props, {
|
return mergeProps(props, {
|
||||||
|
@ -66,48 +79,28 @@ export const MenuItem: ParentComponent<{ label: string }> = (props) => {
|
||||||
}) as unknown as JSX.Element;
|
}) as unknown as JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Menu: ParentComponent<{}> = (props) => {
|
const Root: ParentComponent<{}> = (props) => {
|
||||||
const menu = useMenu();
|
const menu = useMenu();
|
||||||
const items: { label: string, children?: { label: string }[] }[] = (isServer
|
const items: { label: string, children?: { label: string }[] }[] = (isServer
|
||||||
? props.children
|
? props.children
|
||||||
: props.children?.map(c => c())) ?? [];
|
: props.children?.map(c => c())) ?? [];
|
||||||
|
|
||||||
createRenderEffect(() => {
|
return <Portal mount={menu.ref()}>
|
||||||
const indices = items.map(({ label, children }) =>
|
<For each={items}>
|
||||||
menu.add({
|
{(item) => <>
|
||||||
id: createUniqueId(),
|
<button {...(item.children ? { popovertarget: item.label } : {})}>{item.label}</button>
|
||||||
label,
|
|
||||||
children: children?.map(({ label }) => ({ id: createUniqueId(), label }))
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
onCleanup(() => {
|
<Show when={item.children}>
|
||||||
for(const index of indices){
|
<div id={item.label} popover>
|
||||||
menu.remove(index);
|
<For each={item.children}>
|
||||||
|
{(child) => <span>{child.label}</span>}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
});
|
</For>
|
||||||
});
|
</Portal>
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MenuRoot: Component = () => {
|
export const Menu = { Root, Item } as const;
|
||||||
const menu = useMenu();
|
|
||||||
|
|
||||||
return <div data-app-menu="root"></div>
|
|
||||||
|
|
||||||
// return <For each={menu?.items()}>
|
|
||||||
// {(item) => <>
|
|
||||||
// <button {...(item.children ? { popovertarget: item.label } : {})}>{item.label}</button>
|
|
||||||
|
|
||||||
// <Show when={item.children}>
|
|
||||||
// <div id={item.label} popover>
|
|
||||||
// <For each={item.children}>
|
|
||||||
// {(child) => <span>{child.label}</span>}
|
|
||||||
// </For>
|
|
||||||
// </div>
|
|
||||||
// </Show>
|
|
||||||
// </>
|
|
||||||
// }
|
|
||||||
// </For>;
|
|
||||||
};
|
|
|
@ -1,17 +1,20 @@
|
||||||
import { Title } from "@solidjs/meta";
|
import { Title } from "@solidjs/meta";
|
||||||
|
import { JSX, createSignal } from "solid-js";
|
||||||
import { FilesProvider } from "~/features/file";
|
import { FilesProvider } from "~/features/file";
|
||||||
import { MenuRoot, MenuProvider } from "~/features/menu";
|
import { MenuProvider, Menu } from "~/features/menu";
|
||||||
|
|
||||||
|
|
||||||
export default function Editor(props) {
|
export default function Editor(props) {
|
||||||
return <MenuProvider>
|
const [ref, setRef] = createSignal<JSX.Element>();
|
||||||
<nav>
|
|
||||||
<Title>Translation-Tool</Title>
|
return <MenuProvider root={ref()}>
|
||||||
|
<Title>Translation-Tool</Title>
|
||||||
|
|
||||||
|
<nav ref={setRef}>
|
||||||
<a href="/">Index</a>
|
<a href="/">Index</a>
|
||||||
<a href="/about">About</a>
|
<a href="/about">About</a>
|
||||||
<MenuRoot />
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<FilesProvider>
|
<FilesProvider>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { Menu, MenuItem } from "~/features/menu";
|
import { Menu } from "~/features/menu";
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Menu>
|
<Menu.Root>
|
||||||
<MenuItem label="file">
|
<Menu.Item label="file">
|
||||||
<MenuItem label="open" />
|
<Menu.Item label="open" />
|
||||||
|
|
||||||
<MenuItem label="save" />
|
<Menu.Item label="save" />
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
|
|
||||||
<MenuItem label="edit" />
|
<Menu.Item label="edit" />
|
||||||
|
|
||||||
<MenuItem label="selection" />
|
<Menu.Item label="selection" />
|
||||||
|
|
||||||
<MenuItem label="view" />
|
<Menu.Item label="view" />
|
||||||
</Menu>
|
</Menu.Root>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue