diff --git a/apps/docs/src/components/fragments/header.tsx b/apps/docs/src/components/fragments/header.tsx index 2d5e0e93..69af8dee 100644 --- a/apps/docs/src/components/fragments/header.tsx +++ b/apps/docs/src/components/fragments/header.tsx @@ -83,6 +83,13 @@ const Header: Component = () => { text="soft" class="lg:min-w-48 justify-start m-0 group" onClick={() => { + // Force mobile keyboard to open (first focus must be in user-triggered event handler) + const ghostInput = document.createElement("input"); + + ghostInput.classList.add("absolute", "opacity-0", "pointer-events-none"); + ghostInput.id = "ghost-input"; + document.body.appendChild(ghostInput); + ghostInput.focus(); setOpened(!opened()); }} /> diff --git a/apps/docs/src/components/fragments/search-palette.tsx b/apps/docs/src/components/fragments/search-palette.tsx index f23cfe66..ffcef8c0 100644 --- a/apps/docs/src/components/fragments/search-palette.tsx +++ b/apps/docs/src/components/fragments/search-palette.tsx @@ -164,6 +164,7 @@ const SearchPalette: Component = (props) => { if (inputRef() && props.opened && mode()) { setTimeout(() => { inputRef()?.focus(); + document.getElementById("ghost-input")?.remove(); }, 300); } }); @@ -247,7 +248,7 @@ const SearchPalette: Component = (props) => { opened={props.opened} class="items-start" shadeClass="bg-opacity-50" - wrapperClass="mt-32" + wrapperClass="mt-3 md:mt-32" onOverlayClick={() => { props.setOpened(false); }} diff --git a/apps/web/src/context/command-palette/index.tsx b/apps/web/src/context/command-palette/index.tsx index bd6a5728..7729d7e3 100644 --- a/apps/web/src/context/command-palette/index.tsx +++ b/apps/web/src/context/command-palette/index.tsx @@ -292,6 +292,7 @@ const CommandPalette: Component = (props) => { if (inputRef() && props.opened && mode()) { setTimeout(() => { inputRef()?.focus(); + document.getElementById("ghost-input")?.remove(); }, 300); } }); @@ -326,7 +327,7 @@ const CommandPalette: Component = (props) => { opened={props.opened} class="items-start" shadeClass="bg-opacity-50" - wrapperClass="mt-32" + wrapperClass="mt-3 md:mt-32" onOverlayClick={() => { props.setOpened(false); }} diff --git a/apps/web/src/layout/toolbar/index.tsx b/apps/web/src/layout/toolbar/index.tsx index fd2c997c..b855319d 100644 --- a/apps/web/src/layout/toolbar/index.tsx +++ b/apps/web/src/layout/toolbar/index.tsx @@ -419,6 +419,13 @@ const toolbarViews: Record>> = { text="soft" class="@xl:min-w-48 justify-start m-0 bg-gray-200 group" onClick={() => { + // Force mobile keyboard to open (first focus must be in user-triggered event handler) + const ghostInput = document.createElement("input"); + + ghostInput.classList.add("absolute", "opacity-0", "pointer-events-none"); + ghostInput.id = "ghost-input"; + document.body.appendChild(ghostInput); + ghostInput.focus(); setOpened(true); }} /> diff --git a/apps/web/src/views/dashboard/views/kanban/content-group-column.tsx b/apps/web/src/views/dashboard/views/kanban/content-group-column.tsx index e06a74a6..0dff798b 100644 --- a/apps/web/src/views/dashboard/views/kanban/content-group-column.tsx +++ b/apps/web/src/views/dashboard/views/kanban/content-group-column.tsx @@ -28,7 +28,7 @@ import { useSharedState, useCommandPalette } from "#context"; -import { createRef } from "#lib/utils"; +import { breakpoints, createRef } from "#lib/utils"; import { useContentPieces } from "#lib/composables"; interface ContentGroupColumnProps { @@ -224,7 +224,8 @@ const ContentGroupColumn: Component = (props) => { }, delayOnTouchOnly: true, delay: 500, - disabled: !hasPermission("manageDashboard"), + fallbackOnBody: true, + disabled: !hasPermission("manageDashboard") || !breakpoints.md(), ghostClass: "!hidden", revertOnSpill: true, onAdd(evt) { @@ -406,6 +407,7 @@ const ContentGroupColumn: Component = (props) => { ghostClass: `:base: border-4 border-gray-200 opacity-50 dark:border-gray-700 children:invisible`, group: "card", disabled: !hasPermission("manageDashboard"), + fallbackOnBody: true, onStart(event) { props.onDragStart?.(); setActiveDraggablePiece( diff --git a/apps/web/src/views/dashboard/views/kanban/index.tsx b/apps/web/src/views/dashboard/views/kanban/index.tsx index d799bd18..c536d5ad 100644 --- a/apps/web/src/views/dashboard/views/kanban/index.tsx +++ b/apps/web/src/views/dashboard/views/kanban/index.tsx @@ -49,6 +49,7 @@ const DashboardKanbanView: Component = (props) => { ghostClass: `:base: border-4 border-gray-200 opacity-50 dark:border-gray-700 children:invisible !p-0 !m-2 !mt-0 !h-unset rounded-2xl`, filter: ".locked", disabled: !hasPermission("manageDashboard"), + fallbackOnBody: true, onMove(event) { return !event.related.classList.contains("locked"); }, diff --git a/apps/web/src/views/dashboard/views/list/content-group-row.tsx b/apps/web/src/views/dashboard/views/list/content-group-row.tsx index 4fc26771..61b4266c 100644 --- a/apps/web/src/views/dashboard/views/list/content-group-row.tsx +++ b/apps/web/src/views/dashboard/views/list/content-group-row.tsx @@ -22,6 +22,7 @@ import { useSharedState } from "#context"; import { MiniEditor } from "#components/fragments"; +import { breakpoints } from "#lib/utils"; interface ContentGroupRowProps { contentGroup?: App.ContentGroup | null; @@ -146,7 +147,8 @@ const ContentGroupRow: Component = (props) => { }, delayOnTouchOnly: true, delay: 500, - disabled: !hasPermission("manageDashboard"), + fallbackOnBody: true, + disabled: !hasPermission("manageDashboard") || !breakpoints.md(), ghostClass: "!hidden", revertOnSpill: true, draggable: ".draggable", diff --git a/apps/web/src/views/dashboard/views/list/content-piece-row.tsx b/apps/web/src/views/dashboard/views/list/content-piece-row.tsx index c69dd4e8..96cdceba 100644 --- a/apps/web/src/views/dashboard/views/list/content-piece-row.tsx +++ b/apps/web/src/views/dashboard/views/list/content-piece-row.tsx @@ -48,7 +48,7 @@ const ContentPieceRow: Component = (props) => { }, delayOnTouchOnly: true, delay: 500, - disabled: !hasPermission("manageDashboard"), + disabled: !hasPermission("manageDashboard") || !breakpoints.md(), ghostClass: "!hidden", revertOnSpill: true, filter: ".locked", diff --git a/packages/components/src/primitives/overlay.tsx b/packages/components/src/primitives/overlay.tsx index 6495d255..76fad440 100644 --- a/packages/components/src/primitives/overlay.tsx +++ b/packages/components/src/primitives/overlay.tsx @@ -20,7 +20,8 @@ const Overlay: Component = (props) => { "class", "shadeClass", "portal", - "onOverlayClick" + "onOverlayClick", + "wrapperClass" ]); return (