From dda579c8ad30f81ade458769971d85ff7afee64c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sun, 14 Dec 2025 20:32:14 -0600 Subject: wip(desktop): progress --- packages/ui/src/components/dialog.css | 2 + packages/ui/src/components/dialog.tsx | 123 ++++++++++------------------------ packages/ui/src/context/dialog.tsx | 79 ++++++++++++++++++++++ packages/ui/src/context/index.ts | 1 + 4 files changed, 118 insertions(+), 87 deletions(-) create mode 100644 packages/ui/src/context/dialog.tsx (limited to 'packages/ui/src') diff --git a/packages/ui/src/components/dialog.css b/packages/ui/src/components/dialog.css index fa5e1171e..6fa71c64c 100644 --- a/packages/ui/src/components/dialog.css +++ b/packages/ui/src/components/dialog.css @@ -60,6 +60,7 @@ [data-slot="dialog-header"] { display: flex; padding: 16px; + padding-left: 20px; justify-content: space-between; align-items: center; flex-shrink: 0; @@ -82,6 +83,7 @@ [data-slot="dialog-description"] { display: flex; padding: 16px; + padding-left: 20px; padding-top: 0; margin-top: -8px; justify-content: space-between; diff --git a/packages/ui/src/components/dialog.tsx b/packages/ui/src/components/dialog.tsx index aebb77885..47d6af42e 100644 --- a/packages/ui/src/components/dialog.tsx +++ b/packages/ui/src/components/dialog.tsx @@ -1,96 +1,45 @@ -import { - Dialog as Kobalte, - DialogRootProps, - DialogTitleProps, - DialogCloseButtonProps, - DialogDescriptionProps, -} from "@kobalte/core/dialog" -import { ComponentProps, type JSX, onCleanup, onMount, Show, splitProps } from "solid-js" +import { Dialog as Kobalte } from "@kobalte/core/dialog" +import { ComponentProps, JSXElement, Match, ParentProps, Show, Switch } from "solid-js" import { IconButton } from "./icon-button" -export interface DialogProps extends DialogRootProps { - trigger?: JSX.Element +export interface DialogProps extends ParentProps { + title?: JSXElement + description?: JSXElement + action?: JSXElement class?: ComponentProps<"div">["class"] classList?: ComponentProps<"div">["classList"] } -function DialogRoot(props: DialogProps) { - let trigger!: HTMLElement - const [local, others] = splitProps(props, ["trigger", "class", "classList", "children"]) - - const resetTabIndex = () => { - trigger.tabIndex = 0 - } - - const handleTriggerFocus = (e: FocusEvent & { currentTarget: HTMLElement | null }) => { - const firstChild = e.currentTarget?.firstElementChild as HTMLElement - if (!firstChild) return - - firstChild.focus() - trigger.tabIndex = -1 - - firstChild.addEventListener("focusout", resetTabIndex) - onCleanup(() => { - firstChild.removeEventListener("focusout", resetTabIndex) - }) - } - - onMount(() => { - // @ts-ignore - document?.activeElement?.blur?.() - }) - +export function Dialog(props: DialogProps) { return ( - - - - {props.trigger} - - - - -
-
- - {local.children} - -
-
-
-
+
+
+ + +
+ + {props.title} + + + {props.action} + + + + +
+
+ + {props.description} + +
{props.children}
+
+
+
) } - -function DialogHeader(props: ComponentProps<"div">) { - return
-} - -function DialogBody(props: ComponentProps<"div">) { - return
-} - -function DialogTitle(props: DialogTitleProps & ComponentProps<"h2">) { - return -} - -function DialogDescription(props: DialogDescriptionProps & ComponentProps<"p">) { - return -} - -function DialogCloseButton(props: DialogCloseButtonProps & ComponentProps<"button">) { - return -} - -export const Dialog = Object.assign(DialogRoot, { - Header: DialogHeader, - Title: DialogTitle, - Description: DialogDescription, - CloseButton: DialogCloseButton, - Body: DialogBody, -}) diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx new file mode 100644 index 000000000..af5da06f9 --- /dev/null +++ b/packages/ui/src/context/dialog.tsx @@ -0,0 +1,79 @@ +import { For, Show, type JSX } from "solid-js" +import { createStore } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" + +type DialogElement = JSX.Element | (() => JSX.Element) + +export const { use: useDialog, provider: DialogProvider } = createSimpleContext({ + name: "Dialog", + init: () => { + const [store, setStore] = createStore({ + stack: [] as { + element: DialogElement + onClose?: () => void + }[], + }) + + return { + get stack() { + return store.stack + }, + push(element: DialogElement, onClose?: () => void) { + setStore("stack", (s) => [...s, { element, onClose }]) + }, + pop() { + const current = store.stack.at(-1) + current?.onClose?.() + setStore("stack", store.stack.slice(0, -1)) + }, + replace(element: DialogElement, onClose?: () => void) { + for (const item of store.stack) { + item.onClose?.() + } + setStore("stack", [{ element, onClose }]) + }, + clear() { + for (const item of store.stack) { + item.onClose?.() + } + setStore("stack", []) + }, + } + }, +}) + +import { Dialog as Kobalte } from "@kobalte/core/dialog" + +export function DialogRoot(props: { children?: JSX.Element }) { + const dialog = useDialog() + return ( + <> + {props.children} + 0}> +
+ + {(item, index) => ( + + { + if (!open) { + item.onClose?.() + dialog.pop() + } + }} + > + + + {typeof item.element === "function" ? item.element() : item.element} + + + + )} + +
+
+ + ) +} diff --git a/packages/ui/src/context/index.ts b/packages/ui/src/context/index.ts index 3e0f5de74..499cb74d4 100644 --- a/packages/ui/src/context/index.ts +++ b/packages/ui/src/context/index.ts @@ -1,3 +1,4 @@ export * from "./helper" export * from "./data" export * from "./diff" +export * from "./dialog" -- cgit v1.2.3