@k2b/ui 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/actions/ContextMenu.js +5 -0
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/DragAndDrop.js +89 -0
- package/dist/browser/actions/DragAndDrop.js.map +1 -0
- package/dist/browser/actions/GestureMenu.js +26 -3
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/drag-and-drop-messages.js +75 -0
- package/dist/browser/actions/drag-and-drop-messages.js.map +1 -0
- package/dist/browser/actions/drag-and-drop.js +692 -0
- package/dist/browser/actions/drag-and-drop.js.map +1 -0
- package/dist/browser/actions/index.js +1 -0
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +385 -265
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/ChatDecision.js +778 -0
- package/dist/browser/chat/ChatDecision.js.map +1 -0
- package/dist/browser/chat/ChatPrimitives.js +34 -28
- package/dist/browser/chat/ChatPrimitives.js.map +1 -1
- package/dist/browser/chat/ChatTimeline.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +6 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +10 -3
- package/dist/browser/chat/command-search.js.map +1 -1
- package/dist/browser/chat/index.js +6 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/types.js.map +1 -1
- package/dist/browser/content/Calendar.js +3 -3
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/Chart.js +54 -71
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/FileBrowser.js +2 -2
- package/dist/browser/content/FileBrowser.js.map +1 -1
- package/dist/browser/content/FileTree.js +42 -36
- package/dist/browser/content/FileTree.js.map +1 -1
- package/dist/browser/content/FileTypeIcon.js +72 -0
- package/dist/browser/content/FileTypeIcon.js.map +1 -0
- package/dist/browser/content/FileView.js +2 -2
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/ReferenceChip.js +162 -0
- package/dist/browser/content/ReferenceChip.js.map +1 -0
- package/dist/browser/content/calendar-pointer.js +9 -0
- package/dist/browser/content/calendar-pointer.js.map +1 -1
- package/dist/browser/content/calendar-time-view.js +6 -3
- package/dist/browser/content/calendar-time-view.js.map +1 -1
- package/dist/browser/content/index.js +2 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/layout/AppOverview.js +1 -1
- package/dist/browser/layout/AppOverview.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +644 -445
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/PanelDialog.js +88 -86
- package/dist/browser/layout/PanelDialog.js.map +1 -1
- package/dist/browser/layout/ResizeSeparator.js +81 -0
- package/dist/browser/layout/ResizeSeparator.js.map +1 -0
- package/dist/browser/layout/SidebarSwitcher.js +9 -2
- package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
- package/dist/browser/layout/TabBar.js +15 -12
- package/dist/browser/layout/TabBar.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +130 -17
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/index.js +3 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/resize-separator.js +90 -0
- package/dist/browser/layout/resize-separator.js.map +1 -0
- package/dist/browser/layout/workspace-messages.js +12 -2
- package/dist/browser/layout/workspace-messages.js.map +1 -1
- package/dist/browser/surfaces/LinkCard.js +1 -1
- package/dist/browser/surfaces/LinkCard.js.map +1 -1
- package/dist/browser/surfaces/Placeholder.js +14 -3
- package/dist/browser/surfaces/Placeholder.js.map +1 -1
- package/dist/browser/surfaces/StatCell.js +23 -0
- package/dist/browser/surfaces/StatCell.js.map +1 -1
- package/dist/browser/widgets/Widget.js +1 -1
- package/dist/browser/widgets/Widget.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +5 -0
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/DragAndDrop.js +63 -0
- package/dist/ssr/actions/DragAndDrop.js.map +1 -0
- package/dist/ssr/actions/GestureMenu.js +26 -3
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/drag-and-drop-messages.js +75 -0
- package/dist/ssr/actions/drag-and-drop-messages.js.map +1 -0
- package/dist/ssr/actions/drag-and-drop.js +692 -0
- package/dist/ssr/actions/drag-and-drop.js.map +1 -0
- package/dist/ssr/actions/index.js +1 -0
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +131 -14
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/ChatDecision.js +465 -0
- package/dist/ssr/chat/ChatDecision.js.map +1 -0
- package/dist/ssr/chat/ChatPrimitives.js +2 -2
- package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
- package/dist/ssr/chat/ChatTimeline.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +6 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +10 -3
- package/dist/ssr/chat/command-search.js.map +1 -1
- package/dist/ssr/chat/index.js +6 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/types.js.map +1 -1
- package/dist/ssr/content/Calendar.js +3 -3
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/Chart.js +19 -23
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/FileBrowser.js +2 -2
- package/dist/ssr/content/FileBrowser.js.map +1 -1
- package/dist/ssr/content/FileTree.js +21 -14
- package/dist/ssr/content/FileTree.js.map +1 -1
- package/dist/ssr/content/FileTypeIcon.js +50 -0
- package/dist/ssr/content/FileTypeIcon.js.map +1 -0
- package/dist/ssr/content/FileView.js +2 -2
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/ReferenceChip.js +121 -0
- package/dist/ssr/content/ReferenceChip.js.map +1 -0
- package/dist/ssr/content/calendar-pointer.js +9 -0
- package/dist/ssr/content/calendar-pointer.js.map +1 -1
- package/dist/ssr/content/calendar-time-view.js +6 -3
- package/dist/ssr/content/calendar-time-view.js.map +1 -1
- package/dist/ssr/content/index.js +2 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/layout/AppOverview.js +1 -1
- package/dist/ssr/layout/AppOverview.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +272 -95
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/PanelDialog.js +7 -6
- package/dist/ssr/layout/PanelDialog.js.map +1 -1
- package/dist/ssr/layout/ResizeSeparator.js +45 -0
- package/dist/ssr/layout/ResizeSeparator.js.map +1 -0
- package/dist/ssr/layout/SidebarSwitcher.js +9 -2
- package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
- package/dist/ssr/layout/TabBar.js +1 -1
- package/dist/ssr/layout/TabBar.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +130 -17
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/index.js +3 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/resize-separator.js +90 -0
- package/dist/ssr/layout/resize-separator.js.map +1 -0
- package/dist/ssr/layout/workspace-messages.js +12 -2
- package/dist/ssr/layout/workspace-messages.js.map +1 -1
- package/dist/ssr/surfaces/LinkCard.js +1 -1
- package/dist/ssr/surfaces/LinkCard.js.map +1 -1
- package/dist/ssr/surfaces/Placeholder.js +4 -2
- package/dist/ssr/surfaces/Placeholder.js.map +1 -1
- package/dist/ssr/surfaces/StatCell.js +23 -0
- package/dist/ssr/surfaces/StatCell.js.map +1 -1
- package/dist/ssr/widgets/Widget.js +1 -1
- package/dist/ssr/widgets/Widget.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +1 -0
- package/dist/types/actions/DragAndDrop.d.ts +29 -0
- package/dist/types/actions/drag-and-drop-messages.d.ts +35 -0
- package/dist/types/actions/drag-and-drop.d.ts +36 -0
- package/dist/types/actions/index.d.ts +2 -0
- package/dist/types/chat/ChatComposer.d.ts +19 -1
- package/dist/types/chat/ChatDecision.d.ts +133 -0
- package/dist/types/chat/ChatPrimitives.d.ts +4 -1
- package/dist/types/chat/ChatTimeline.d.ts +2 -1
- package/dist/types/chat/chat-messages.d.ts +3 -0
- package/dist/types/chat/command-search.d.ts +3 -0
- package/dist/types/chat/index.d.ts +23 -1
- package/dist/types/chat/types.d.ts +54 -1
- package/dist/types/content/Chart.d.ts +9 -3
- package/dist/types/content/FileTypeIcon.d.ts +27 -0
- package/dist/types/content/ReferenceChip.d.ts +49 -0
- package/dist/types/content/calendar-pointer.d.ts +6 -0
- package/dist/types/content/index.d.ts +3 -0
- package/dist/types/layout/AppWorkspace.d.ts +5 -3
- package/dist/types/layout/ResizeSeparator.d.ts +9 -0
- package/dist/types/layout/TabBar.d.ts +7 -0
- package/dist/types/layout/app-workspace-controller.d.ts +2 -0
- package/dist/types/layout/index.d.ts +3 -1
- package/dist/types/layout/resize-separator.d.ts +18 -0
- package/dist/types/layout/workspace-messages.d.ts +5 -0
- package/dist/types/surfaces/StatCell.d.ts +6 -0
- package/package.json +2 -2
|
@@ -166,6 +166,11 @@ export function ContextMenuBase(props) {
|
|
|
166
166
|
}
|
|
167
167
|
};
|
|
168
168
|
props.openAt?.(open);
|
|
169
|
+
// A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.
|
|
170
|
+
props.closeWith?.(() => {
|
|
171
|
+
if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);
|
|
172
|
+
close();
|
|
173
|
+
});
|
|
169
174
|
onMount(() => {
|
|
170
175
|
onCleanup(() => {
|
|
171
176
|
detachOpenListeners();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n};\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & { openAt?: (open: (x: number, y: number) => void) => void; title?: string },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n};\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { template as _$template } from "solid-js/web";
|
|
2
|
+
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
3
|
+
import { className as _$className } from "solid-js/web";
|
|
4
|
+
import { effect as _$effect } from "solid-js/web";
|
|
5
|
+
import { getNextElement as _$getNextElement } from "solid-js/web";
|
|
6
|
+
import { insert as _$insert } from "solid-js/web";
|
|
7
|
+
import { use as _$use } from "solid-js/web";
|
|
8
|
+
var _tmpl$ = /*#__PURE__*/_$template(`<div>`);
|
|
9
|
+
import { createEffect, onCleanup, onMount } from "solid-js";
|
|
10
|
+
import { bindDragSource, registerDropTarget, startKeyboardDrag } from "./drag-and-drop";
|
|
11
|
+
import { useDragAndDropMessages } from "./drag-and-drop-messages";
|
|
12
|
+
export { activeDrag } from "./drag-and-drop";
|
|
13
|
+
export function DragSource(props) {
|
|
14
|
+
const messages = useDragAndDropMessages();
|
|
15
|
+
let source;
|
|
16
|
+
onMount(() => onCleanup(bindDragSource(source, () => ({
|
|
17
|
+
payload: props.payload,
|
|
18
|
+
disabled: props.disabled,
|
|
19
|
+
messages: messages()
|
|
20
|
+
}))));
|
|
21
|
+
return (() => {
|
|
22
|
+
var _el$ = _$getNextElement(_tmpl$);
|
|
23
|
+
var _ref$ = source;
|
|
24
|
+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : source = _el$;
|
|
25
|
+
_$insert(_el$, () => props.children);
|
|
26
|
+
_$effect(_p$ => {
|
|
27
|
+
var _v$ = `k2b-drag-source${props.class ? ` ${props.class}` : ""}`,
|
|
28
|
+
_v$2 = props.disabled ? "" : undefined;
|
|
29
|
+
_v$ !== _p$.e && _$className(_el$, _p$.e = _v$);
|
|
30
|
+
_v$2 !== _p$.t && _$setAttribute(_el$, "data-drag-disabled", _p$.t = _v$2);
|
|
31
|
+
return _p$;
|
|
32
|
+
}, {
|
|
33
|
+
e: undefined,
|
|
34
|
+
t: undefined
|
|
35
|
+
});
|
|
36
|
+
return _el$;
|
|
37
|
+
})();
|
|
38
|
+
}
|
|
39
|
+
export function DropTarget(props) {
|
|
40
|
+
// Resolve the inherited locale in the component's owner, as DragSource and the keyboard hook do.
|
|
41
|
+
const messages = useDragAndDropMessages();
|
|
42
|
+
let element;
|
|
43
|
+
onMount(() => {
|
|
44
|
+
const read = () => {
|
|
45
|
+
const accept = props.accept;
|
|
46
|
+
const onDrop = props.onDrop;
|
|
47
|
+
return {
|
|
48
|
+
accept,
|
|
49
|
+
label: props.label,
|
|
50
|
+
messages: messages(),
|
|
51
|
+
disabled: props.disabled,
|
|
52
|
+
drop: payload => {
|
|
53
|
+
// Only this membership guard narrows the opaque payload type at the registry boundary.
|
|
54
|
+
const type = accept.find(type => type === payload.type);
|
|
55
|
+
if (type !== undefined) onDrop({
|
|
56
|
+
...payload,
|
|
57
|
+
type
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const target = registerDropTarget(element, read());
|
|
63
|
+
createEffect(() => target.update(read()));
|
|
64
|
+
onCleanup(() => target.dispose());
|
|
65
|
+
});
|
|
66
|
+
return (() => {
|
|
67
|
+
var _el$2 = _$getNextElement(_tmpl$);
|
|
68
|
+
var _ref$2 = element;
|
|
69
|
+
typeof _ref$2 === "function" ? _$use(_ref$2, _el$2) : element = _el$2;
|
|
70
|
+
_$insert(_el$2, () => props.children);
|
|
71
|
+
_$effect(() => _$className(_el$2, `k2b-drop-target${props.class ? ` ${props.class}` : ""}`));
|
|
72
|
+
return _el$2;
|
|
73
|
+
})();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Starts the optional keyboard pick-up sequence from a menu entry. Focus returns to `origin` afterwards, or to its
|
|
78
|
+
* nearest focusable ancestor, such as the group of a `GestureMenu`.
|
|
79
|
+
*/
|
|
80
|
+
export function useKeyboardDrag() {
|
|
81
|
+
const messages = useDragAndDropMessages();
|
|
82
|
+
let cancel;
|
|
83
|
+
onCleanup(() => cancel?.());
|
|
84
|
+
return (payload, origin) => {
|
|
85
|
+
cancel?.();
|
|
86
|
+
cancel = startKeyboardDrag(payload, origin, messages());
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=DragAndDrop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/DragAndDrop.tsx"],"sourcesContent":["import { createEffect, type JSX, onCleanup, onMount } from \"solid-js\";\nimport { bindDragSource, type DragPayload, registerDropTarget, startKeyboardDrag } from \"./drag-and-drop\";\nimport { useDragAndDropMessages } from \"./drag-and-drop-messages\";\n\nexport type { DragPayload } from \"./drag-and-drop\";\nexport { activeDrag } from \"./drag-and-drop\";\n\nexport type DragSourceProps<Type extends string = string> = {\n /** Read when the drag starts, so a selection can decide what is dragged. */\n payload: DragPayload<Type>;\n disabled?: boolean;\n class?: string;\n children: JSX.Element;\n};\nexport type DropTargetProps<Type extends string = string> = {\n /** The payload types this target takes. */\n accept: readonly Type[];\n /** Names the target in announcements and in the keyboard path, such as \"Archive\". */\n label: string;\n onDrop: (payload: DragPayload<Type>) => void;\n /** The target takes nothing now, for example without access; it refuses every drop. */\n disabled?: boolean;\n class?: string;\n children: JSX.Element;\n};\n\nexport function DragSource<Type extends string = string>(props: DragSourceProps<Type>): JSX.Element {\n const messages = useDragAndDropMessages();\n let source!: HTMLDivElement;\n onMount(() => onCleanup(bindDragSource(source, () => ({ payload: props.payload, disabled: props.disabled, messages: messages() }))));\n return (\n <div ref={source} class={`k2b-drag-source${props.class ? ` ${props.class}` : \"\"}`} data-drag-disabled={props.disabled ? \"\" : undefined}>\n {props.children}\n </div>\n );\n}\n\nexport function DropTarget<Type extends string = string>(props: DropTargetProps<Type>): JSX.Element {\n // Resolve the inherited locale in the component's owner, as DragSource and the keyboard hook do.\n const messages = useDragAndDropMessages();\n let element!: HTMLDivElement;\n onMount(() => {\n const read = () => {\n const accept = props.accept;\n const onDrop = props.onDrop;\n return {\n accept,\n label: props.label,\n messages: messages(),\n disabled: props.disabled,\n drop: (payload: DragPayload) => {\n // Only this membership guard narrows the opaque payload type at the registry boundary.\n const type = accept.find((type) => type === payload.type);\n if (type !== undefined) onDrop({ ...payload, type });\n },\n };\n };\n const target = registerDropTarget(element, read());\n createEffect(() => target.update(read()));\n onCleanup(() => target.dispose());\n });\n return (\n <div ref={element} class={`k2b-drop-target${props.class ? ` ${props.class}` : \"\"}`}>\n {props.children}\n </div>\n );\n}\n\n/**\n * Starts the optional keyboard pick-up sequence from a menu entry. Focus returns to `origin` afterwards, or to its\n * nearest focusable ancestor, such as the group of a `GestureMenu`.\n */\nexport function useKeyboardDrag(): (payload: DragPayload, origin: HTMLElement) => void {\n const messages = useDragAndDropMessages();\n let cancel: (() => void) | undefined;\n onCleanup(() => cancel?.());\n return (payload, origin) => {\n cancel?.();\n cancel = startKeyboardDrag(payload, origin, messages());\n };\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,YAAY,EAAY,SAAS,EAAE,OAAO,QAAQ,UAAU;AACrE,SAAS,cAAc,EAAoB,kBAAkB,EAAE,iBAAiB,QAAQ,iBAAiB;AACzG,SAAS,sBAAsB,QAAQ,0BAA0B;AAGjE,SAAS,UAAU,QAAQ,iBAAiB;AAqB5C,OAAO,SAAS,UAAU,CAA+B,KAA4B,EAAe;EAClG,MAAM,QAAQ,GAAG,sBAAsB,CAAC,CAAC;EACzC,IAAI,MAAuB;EAC3B,OAAO,CAAC,MAAM,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO;IAAE,OAAO,EAAE,KAAK,CAAC,OAAO;IAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ;IAAE,QAAQ,EAAE,QAAQ,CAAC;EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;EACpI;IAAA;IAAA,YACY,MAAM;IAAA,mDAAN,MAAM;IAAA,qBACb,KAAK,CAAC,QAAQ;IAAA;MAAA,UADQ,kBAAkB,KAAK,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAAA,OAAsB,KAAK,CAAC,QAAQ,GAAG,EAAE,GAAG,SAAS;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;IAAA;IAAA;EAAA;AAI1I;AAEA,OAAO,SAAS,UAAU,CAA+B,KAA4B,EAAe;EAClG;EACA,MAAM,QAAQ,GAAG,sBAAsB,CAAC,CAAC;EACzC,IAAI,OAAwB;EAC5B,OAAO,CAAC,MAAM;IACZ,MAAM,IAAI,GAAG,MAAM;MACjB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;MAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;MAC3B,OAAO;QACL,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAG,OAAoB,IAAK;UAC9B;UACA,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAE,IAAI,IAAK,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;UACzD,IAAI,IAAI,KAAK,SAAS,EAAE,MAAM,CAAC;YAAE,GAAG,OAAO;YAAE;UAAK,CAAC,CAAC;QACtD;MACF,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAClD,YAAY,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,SAAS,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;EACnC,CAAC,CAAC;EACF;IAAA;IAAA,aACY,OAAO;IAAA,sDAAP,OAAO;IAAA,sBACd,KAAK,CAAC,QAAQ;IAAA,kCADS,kBAAkB,KAAK,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAAA;EAAA;AAItF;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAAS,eAAe,GAAwD;EACrF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,CAAC;EACzC,IAAI,MAAgC;EACpC,SAAS,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC;EAC3B,OAAO,CAAC,OAAO,EAAE,MAAM,KAAK;IAC1B,MAAM,GAAG,CAAC;IACV,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;EACzD,CAAC;AACH","ignoreList":[]}
|
|
@@ -15,6 +15,7 @@ import { useLocale } from "../intl/locale";
|
|
|
15
15
|
import { prefersReducedMotion } from "../motion";
|
|
16
16
|
import { ContextMenuBase } from "./ContextMenu";
|
|
17
17
|
import { DropdownItems } from "./Dropdown";
|
|
18
|
+
import { onPointerDragStart } from "./drag-and-drop";
|
|
18
19
|
import { openMenuSheet } from "./menu-sheet";
|
|
19
20
|
|
|
20
21
|
/** A finger held this long without moving opens the menu, as the platforms' own long press does. */
|
|
@@ -62,6 +63,8 @@ export function GestureMenu(props) {
|
|
|
62
63
|
const [swipe, setSwipe] = createSignal();
|
|
63
64
|
let surface;
|
|
64
65
|
let openMenuAt;
|
|
66
|
+
let closeMenu;
|
|
67
|
+
let sheetController;
|
|
65
68
|
let press;
|
|
66
69
|
let lastTap;
|
|
67
70
|
let lastPointer = "mouse";
|
|
@@ -101,6 +104,12 @@ export function GestureMenu(props) {
|
|
|
101
104
|
const openSheet = () => {
|
|
102
105
|
if (sheetOpen || !active()) return;
|
|
103
106
|
sheetOpen = true;
|
|
107
|
+
const controller = new AbortController();
|
|
108
|
+
sheetController = controller;
|
|
109
|
+
const abortSheet = () => controller.abort();
|
|
110
|
+
disposed.signal.addEventListener("abort", abortSheet, {
|
|
111
|
+
once: true
|
|
112
|
+
});
|
|
104
113
|
props.onOpen?.();
|
|
105
114
|
void openMenuSheet({
|
|
106
115
|
Items: DropdownItems,
|
|
@@ -108,9 +117,13 @@ export function GestureMenu(props) {
|
|
|
108
117
|
label: props.label,
|
|
109
118
|
locale: locale(),
|
|
110
119
|
top: props.sheetTop,
|
|
111
|
-
signal:
|
|
120
|
+
signal: controller.signal
|
|
112
121
|
}).finally(() => {
|
|
113
|
-
|
|
122
|
+
disposed.signal.removeEventListener("abort", abortSheet);
|
|
123
|
+
if (sheetController === controller) {
|
|
124
|
+
sheetController = undefined;
|
|
125
|
+
sheetOpen = false;
|
|
126
|
+
}
|
|
114
127
|
});
|
|
115
128
|
};
|
|
116
129
|
|
|
@@ -191,7 +204,7 @@ export function GestureMenu(props) {
|
|
|
191
204
|
const onPointerMove = event => {
|
|
192
205
|
const current = press;
|
|
193
206
|
if (!current || event.pointerId !== current.id) return;
|
|
194
|
-
//
|
|
207
|
+
// Hold-then-drag hands this press to DragSource through onPointerDragStart.
|
|
195
208
|
if (current.long) return;
|
|
196
209
|
const dx = event.clientX - current.x;
|
|
197
210
|
const dy = event.clientY - current.y;
|
|
@@ -299,6 +312,14 @@ export function GestureMenu(props) {
|
|
|
299
312
|
doubleTap.action();
|
|
300
313
|
};
|
|
301
314
|
onMount(() => {
|
|
315
|
+
const unsubscribeDrag = onPointerDragStart(pointerId => {
|
|
316
|
+
if (press?.id !== pointerId) return;
|
|
317
|
+
consumed = true;
|
|
318
|
+
lastTap = undefined;
|
|
319
|
+
closeMenu?.();
|
|
320
|
+
sheetController?.abort();
|
|
321
|
+
endPress();
|
|
322
|
+
});
|
|
302
323
|
surface.addEventListener("pointerdown", onPointerDown);
|
|
303
324
|
surface.addEventListener("pointermove", onPointerMove);
|
|
304
325
|
surface.addEventListener("pointerup", onPointerUp);
|
|
@@ -314,6 +335,7 @@ export function GestureMenu(props) {
|
|
|
314
335
|
surface.addEventListener("mousedown", onMouseDown);
|
|
315
336
|
surface.addEventListener("dblclick", onDoubleClick);
|
|
316
337
|
onCleanup(() => {
|
|
338
|
+
unsubscribeDrag();
|
|
317
339
|
disposed.abort();
|
|
318
340
|
endPress();
|
|
319
341
|
clearTimeout(settleTimer);
|
|
@@ -331,6 +353,7 @@ export function GestureMenu(props) {
|
|
|
331
353
|
});
|
|
332
354
|
return _$createComponent(ContextMenuBase, {
|
|
333
355
|
openAt: open => openMenuAt = open,
|
|
356
|
+
closeWith: close => closeMenu = close,
|
|
334
357
|
get title() {
|
|
335
358
|
return props.label;
|
|
336
359
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/GestureMenu.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { useLocale } from \"../intl/locale\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { ContextMenuBase } from \"./ContextMenu\";\nimport { type DropdownAction, type DropdownActionBase, type DropdownChoice, DropdownItems, type DropdownSection } from \"./Dropdown\";\nimport { openMenuSheet } from \"./menu-sheet\";\n\n/** A finger held this long without moving opens the menu, as the platforms' own long press does. */\nconst LONG_PRESS_MS = 500;\n/** A second tap that starts this soon after the first ended makes a double tap. */\nconst DOUBLE_TAP_MS = 300;\n/** The second tap lands at most this far from the first. */\nconst DOUBLE_TAP_DISTANCE = 32;\n/** Movement up to this is still a tap or a long press. */\nconst SLOP = 10;\n/** A swipe must be this many times wider than tall; anything steeper belongs to the page's scrolling. */\nconst SWIPE_RATIO = 1.5;\n/** Travel at which a released swipe runs its action. */\nconst SWIPE_THRESHOLD = 64;\n/** The content follows the finger up to the threshold, then at a quarter of its travel, up to this. */\nconst SWIPE_MAX = 96;\nconst SWIPE_RESISTANCE = 0.25;\n/** Swipes do not start this close to the screen's side edges, where the system's back and forward gestures are. */\nconst EDGE = 20;\n/** Duration of the snap back in `.k2b-gesture-menu[data-settling]`. */\nconst SETTLE_MS = 160;\n\n/**\n * Gestures never start on these elements: links, controls, fields, code blocks, and anything marked\n * `data-gesture-ignore` keep their own touch and mouse behavior.\n */\nconst IGNORE = [\n \"a[href]\",\n \"button\",\n \"input\",\n \"textarea\",\n \"select\",\n \"summary\",\n \"label\",\n \"audio\",\n \"video\",\n \"pre\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[role='button']\",\n \"[role='link']\",\n \"[role='checkbox']\",\n \"[role='switch']\",\n \"[role='slider']\",\n \"[role='tab']\",\n \"[role^='menuitem']\",\n \"[data-gesture-ignore]\",\n].join(\", \");\n\nexport type GestureKind = \"swipe-right\" | \"swipe-left\" | \"double-tap\";\n\n/** A menu action that a gesture runs as well. */\nexport type GestureMenuAction = DropdownActionBase & {\n action: () => void;\n /** The gesture that runs this action. Give each gesture to at most one item; a disabled item disables its gesture. */\n gesture?: GestureKind;\n};\n\nexport type GestureMenuSection = Omit<DropdownSection, \"items\"> & {\n items: readonly (GestureMenuAction | DropdownAction | DropdownChoice)[];\n};\n\nexport type GestureMenuItem = GestureMenuAction | DropdownAction | DropdownChoice | GestureMenuSection;\n\nexport type GestureMenuProps = {\n /**\n * The menu. A long press opens a BottomSheet below 48rem and the same menu at the finger from 48rem.\n * Right-click opens it at the pointer; the Context Menu key and Shift+F10 open it beside the focused element.\n * An item with `gesture` is also run by that gesture, so every gesture has its entry here.\n */\n items: readonly GestureMenuItem[];\n /** Names the element and its menu, for example \"Message from Nora, 10:42\". */\n label: string;\n children: JSX.Element;\n /** Shown only above the menu in the phone sheet, for example a row of quick reactions. `close` closes the sheet. */\n sheetTop?: (close: () => void) => JSX.Element;\n /** Tab order of the element. A list that moves focus between its rows itself passes -1. */\n tabIndex?: number;\n /** Runs before the menu or the sheet shows its items, for example to select what was pressed. */\n onOpen?: () => void;\n class?: string;\n};\n\ntype SwipeDirection = \"right\" | \"left\";\n\ntype Swipe = {\n direction: SwipeDirection;\n icon?: string;\n /** How far the content is moved, in pixels; always 0 with reduced motion. */\n offset: number;\n /** Travel relative to the threshold, from 0 to 1. */\n progress: number;\n armed: boolean;\n settling: boolean;\n};\n\ntype Press = {\n id: number;\n x: number;\n y: number;\n timer?: ReturnType<typeof setTimeout>;\n /** The finger left the slop: no tap or long press any more. */\n moved: boolean;\n /** The long press opened the menu or the sheet. */\n long: boolean;\n /** The press started soon after a tap nearby. */\n second: boolean;\n /** The press started at a side edge of the screen. */\n edge: boolean;\n direction?: SwipeDirection;\n};\n\nconst gestureAction = (items: readonly GestureMenuItem[], kind: GestureKind): GestureMenuAction | undefined => {\n for (const item of items)\n for (const entry of \"items\" in item ? item.items : [item])\n if (\"gesture\" in entry && entry.gesture === kind) return entry.disabled ? undefined : entry;\n return undefined;\n};\n\nconst swipeKind = (direction: SwipeDirection): GestureKind => (direction === \"right\" ? \"swipe-right\" : \"swipe-left\");\n\n/**\n * Touch gestures for an element, each the shortcut of an entry in its menu: a horizontal swipe, a double tap, and a\n * long press that opens a `BottomSheet` below 48rem and the same menu at the finger from 48rem. A mouse double-click\n * runs the double-tap action; right-click opens the menu at the pointer, the keyboard beside the focused element.\n * Vertical scrolling never turns into a swipe.\n */\nexport function GestureMenu(props: GestureMenuProps): JSX.Element {\n const locale = useLocale();\n const [swipe, setSwipe] = createSignal<Swipe>();\n let surface!: HTMLDivElement;\n let openMenuAt: ((x: number, y: number) => void) | undefined;\n let press: Press | undefined;\n let lastTap: { x: number; y: number; at: number } | undefined;\n let lastPointer = \"mouse\";\n /**\n * The touch or pen press that just ended did something: its `touchend` is cancelled, so no click or mouse events\n * follow, and a pen's click, which comes without touch events, is cancelled itself.\n */\n let consumed = false;\n let sheetOpen = false;\n /** Closes an open sheet when the element goes, for example when its message is deleted. */\n const disposed = new AbortController();\n let reduced = false;\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n const active = () => props.items.length > 0;\n const wide = () => window.matchMedia?.(\"(min-width: 48rem)\").matches ?? false;\n /**\n * A modal dialog makes everything outside it inert, also ContextMenu's menu on the body, so inside one the hold\n * keeps the sheet, which opens on the same dialog stack. An engine without `:modal` gets the sheet too.\n */\n const inModal = () => {\n const dialog = surface.closest(\"dialog[open]\");\n if (!dialog) return false;\n try {\n return dialog.matches(\":modal\");\n } catch {\n return true;\n }\n };\n const action = (kind: GestureKind) => gestureAction(props.items, kind);\n const touchAction = () => (action(\"swipe-right\") || action(\"swipe-left\") ? \"swipe\" : action(\"double-tap\") ? \"tap\" : undefined);\n\n /** Whether the event started on something with a meaning of its own, inside this element. */\n const ignored = (target: EventTarget | null) => {\n const found = target instanceof Element ? target.closest(IGNORE) : null;\n return found !== null && found !== surface && surface.contains(found);\n };\n\n const openSheet = () => {\n if (sheetOpen || !active()) return;\n sheetOpen = true;\n props.onOpen?.();\n void openMenuSheet({\n Items: DropdownItems,\n items: props.items,\n label: props.label,\n locale: locale(),\n top: props.sheetTop,\n signal: disposed.signal,\n }).finally(() => {\n sheetOpen = false;\n });\n };\n\n /** Another pointer that goes down anywhere while a finger presses, as in a pinch, ends the gesture. */\n const onOtherPointer = (event: PointerEvent) => {\n if (!press || event.pointerId === press.id) return;\n if (press.direction) settle();\n endPress();\n };\n\n const endPress = () => {\n clearTimeout(press?.timer);\n press = undefined;\n document.removeEventListener(\"pointerdown\", onOtherPointer, true);\n delete surface.dataset.pressing;\n };\n\n const settle = () => {\n const current = swipe();\n if (!current) return;\n clearTimeout(settleTimer);\n if (reduced || current.offset === 0) {\n setSwipe(undefined);\n return;\n }\n setSwipe({ ...current, offset: 0, progress: 0, armed: false, settling: true });\n settleTimer = setTimeout(() => setSwipe(undefined), SETTLE_MS);\n };\n\n const moveSwipe = (current: Press, direction: SwipeDirection, dx: number) => {\n const travel = Math.max(0, direction === \"right\" ? dx : -dx);\n const moved = travel <= SWIPE_THRESHOLD ? travel : SWIPE_THRESHOLD + (travel - SWIPE_THRESHOLD) * SWIPE_RESISTANCE;\n const offset = reduced ? 0 : Math.min(SWIPE_MAX, moved) * (direction === \"right\" ? 1 : -1);\n current.direction = direction;\n setSwipe({\n direction,\n icon: action(swipeKind(direction))?.icon,\n offset,\n progress: Math.min(1, travel / SWIPE_THRESHOLD),\n armed: travel >= SWIPE_THRESHOLD,\n settling: false,\n });\n };\n\n const longPress = () => {\n if (!press) return;\n press.long = true;\n lastTap = undefined;\n if (wide() && !inModal()) openMenuAt?.(press.x, press.y);\n else openSheet();\n };\n\n const onPointerDown = (event: PointerEvent) => {\n lastPointer = event.pointerType;\n consumed = false;\n // Any press in between, on a link, with a mouse, or with another finger, ends a pending double tap.\n const previous = lastTap;\n lastTap = undefined;\n // Another finger ends the gesture through `onOtherPointer` and starts none.\n if (event.pointerType === \"mouse\" || !event.isPrimary) return;\n endPress();\n if (!active() || ignored(event.target)) return;\n const second =\n previous !== undefined &&\n performance.now() - previous.at <= DOUBLE_TAP_MS &&\n Math.hypot(event.clientX - previous.x, event.clientY - previous.y) <= DOUBLE_TAP_DISTANCE;\n press = {\n id: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n moved: false,\n long: false,\n second,\n edge: event.clientX < EDGE || event.clientX > window.innerWidth - EDGE,\n timer: setTimeout(longPress, LONG_PRESS_MS),\n };\n document.addEventListener(\"pointerdown\", onOtherPointer, true);\n // Hybrid devices keep text selection for the mouse; a finger on the element selects nothing.\n surface.dataset.pressing = \"\";\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n // A later \"hold, then drag\" gesture takes over the pointer here.\n if (current.long) return;\n const dx = event.clientX - current.x;\n const dy = event.clientY - current.y;\n if (current.direction) {\n moveSwipe(current, current.direction, dx);\n return;\n }\n if (current.moved || Math.hypot(dx, dy) < SLOP) return;\n current.moved = true;\n clearTimeout(current.timer);\n if (current.edge || Math.abs(dx) < Math.abs(dy) * SWIPE_RATIO) return;\n const direction: SwipeDirection = dx > 0 ? \"right\" : \"left\";\n if (!action(swipeKind(direction))) return;\n clearTimeout(settleTimer);\n reduced = prefersReducedMotion();\n moveSwipe(current, direction, dx);\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n endPress();\n if (current.long) {\n consumed = true;\n return;\n }\n if (current.direction) {\n // Where the finger lifts decides, and the item as it is now.\n moveSwipe(current, current.direction, event.clientX - current.x);\n const swipeAction = swipe()?.armed ? action(swipeKind(current.direction)) : undefined;\n settle();\n if (swipeAction) {\n consumed = true;\n swipeAction.action();\n }\n return;\n }\n if (current.moved) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n if (current.second) {\n consumed = true;\n doubleTap.action();\n return;\n }\n lastTap = { x: event.clientX, y: event.clientY, at: performance.now() };\n };\n\n // The browser took the touch, for example to scroll the page.\n const onPointerCancel = (event: PointerEvent) => {\n if (!press || event.pointerId !== press.id) return;\n if (press.direction) settle();\n endPress();\n lastTap = undefined;\n };\n\n // Once the hold opens the menu or sheet, further movement must not scroll the page underneath it.\n const onTouchMove = (event: TouchEvent) => {\n if (press?.long && event.cancelable) event.preventDefault();\n };\n\n const onTouchEnd = (event: TouchEvent) => {\n if (!consumed) return;\n consumed = false;\n if (event.cancelable) event.preventDefault();\n };\n\n // A pen sends no touch events; the click after its gesture is cancelled here. A keyboard's click has no detail.\n const onClick = (event: MouseEvent) => {\n if (!consumed || event.detail === 0) return;\n consumed = false;\n event.preventDefault();\n event.stopPropagation();\n };\n\n const onContextMenu = (event: MouseEvent) => {\n // Without items the element has no menu, and the browser keeps its own.\n if (!active()) return;\n // Links, fields, and code keep the browser's own menu.\n if (ignored(event.target)) {\n event.stopPropagation();\n return;\n }\n // A mouse or the keyboard opens the menu beside the element through ContextMenu.\n if (!press && !(\"pointerType\" in event && (event.pointerType === \"touch\" || event.pointerType === \"pen\"))) return;\n // Android and touch screens report a long press as a context-menu event, sometimes before the timer.\n event.preventDefault();\n event.stopPropagation();\n if (press && !press.long && !press.moved) {\n clearTimeout(press.timer);\n longPress();\n }\n };\n\n // The second press of a mouse double-click would select a word; in this element it runs the double-tap action.\n const onMouseDown = (event: MouseEvent) => {\n if (event.button === 0 && event.detail >= 2 && lastPointer === \"mouse\" && action(\"double-tap\") && !ignored(event.target))\n event.preventDefault();\n };\n\n const onDoubleClick = (event: MouseEvent) => {\n if (lastPointer !== \"mouse\" || ignored(event.target)) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n event.preventDefault();\n doubleTap.action();\n };\n\n onMount(() => {\n surface.addEventListener(\"pointerdown\", onPointerDown);\n surface.addEventListener(\"pointermove\", onPointerMove);\n surface.addEventListener(\"pointerup\", onPointerUp);\n surface.addEventListener(\"pointercancel\", onPointerCancel);\n surface.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n surface.addEventListener(\"touchend\", onTouchEnd, { passive: false });\n surface.addEventListener(\"click\", onClick, true);\n surface.addEventListener(\"contextmenu\", onContextMenu);\n surface.addEventListener(\"mousedown\", onMouseDown);\n surface.addEventListener(\"dblclick\", onDoubleClick);\n onCleanup(() => {\n disposed.abort();\n endPress();\n clearTimeout(settleTimer);\n surface.removeEventListener(\"pointerdown\", onPointerDown);\n surface.removeEventListener(\"pointermove\", onPointerMove);\n surface.removeEventListener(\"pointerup\", onPointerUp);\n surface.removeEventListener(\"pointercancel\", onPointerCancel);\n surface.removeEventListener(\"touchmove\", onTouchMove);\n surface.removeEventListener(\"touchend\", onTouchEnd);\n surface.removeEventListener(\"click\", onClick, true);\n surface.removeEventListener(\"contextmenu\", onContextMenu);\n surface.removeEventListener(\"mousedown\", onMouseDown);\n surface.removeEventListener(\"dblclick\", onDoubleClick);\n });\n });\n\n return (\n <ContextMenuBase\n openAt={(open) => (openMenuAt = open)}\n title={props.label}\n items={props.items}\n label={props.label}\n tabIndex={props.tabIndex}\n disabled={!active()}\n onOpen={props.onOpen}\n class={props.class}\n >\n <div\n ref={surface}\n class=\"k2b-gesture-menu\"\n data-active={active() ? \"\" : undefined}\n data-touch={touchAction()}\n data-swipe={swipe()?.direction}\n data-armed={swipe()?.armed ? \"\" : undefined}\n data-settling={swipe()?.settling ? \"\" : undefined}\n style={{\n \"--k2b-gesture-menu-offset\": `${swipe()?.offset ?? 0}px`,\n \"--k2b-gesture-menu-progress\": String(swipe()?.progress ?? 0),\n }}\n >\n <Show when={swipe()}>\n {(current) => (\n <span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\">\n <i class={current().icon ?? (current().direction === \"right\" ? \"ti ti-arrow-right\" : \"ti ti-arrow-left\")} />\n </span>\n )}\n </Show>\n <div class=\"k2b-gesture-menu__content\">{props.children}</div>\n </div>\n </ContextMenuBase>\n );\n}\n\nexport default GestureMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/GestureMenu.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { useLocale } from \"../intl/locale\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { ContextMenuBase } from \"./ContextMenu\";\nimport { type DropdownAction, type DropdownActionBase, type DropdownChoice, DropdownItems, type DropdownSection } from \"./Dropdown\";\nimport { onPointerDragStart } from \"./drag-and-drop\";\nimport { openMenuSheet } from \"./menu-sheet\";\n\n/** A finger held this long without moving opens the menu, as the platforms' own long press does. */\nconst LONG_PRESS_MS = 500;\n/** A second tap that starts this soon after the first ended makes a double tap. */\nconst DOUBLE_TAP_MS = 300;\n/** The second tap lands at most this far from the first. */\nconst DOUBLE_TAP_DISTANCE = 32;\n/** Movement up to this is still a tap or a long press. */\nconst SLOP = 10;\n/** A swipe must be this many times wider than tall; anything steeper belongs to the page's scrolling. */\nconst SWIPE_RATIO = 1.5;\n/** Travel at which a released swipe runs its action. */\nconst SWIPE_THRESHOLD = 64;\n/** The content follows the finger up to the threshold, then at a quarter of its travel, up to this. */\nconst SWIPE_MAX = 96;\nconst SWIPE_RESISTANCE = 0.25;\n/** Swipes do not start this close to the screen's side edges, where the system's back and forward gestures are. */\nconst EDGE = 20;\n/** Duration of the snap back in `.k2b-gesture-menu[data-settling]`. */\nconst SETTLE_MS = 160;\n\n/**\n * Gestures never start on these elements: links, controls, fields, code blocks, and anything marked\n * `data-gesture-ignore` keep their own touch and mouse behavior.\n */\nconst IGNORE = [\n \"a[href]\",\n \"button\",\n \"input\",\n \"textarea\",\n \"select\",\n \"summary\",\n \"label\",\n \"audio\",\n \"video\",\n \"pre\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[role='button']\",\n \"[role='link']\",\n \"[role='checkbox']\",\n \"[role='switch']\",\n \"[role='slider']\",\n \"[role='tab']\",\n \"[role^='menuitem']\",\n \"[data-gesture-ignore]\",\n].join(\", \");\n\nexport type GestureKind = \"swipe-right\" | \"swipe-left\" | \"double-tap\";\n\n/** A menu action that a gesture runs as well. */\nexport type GestureMenuAction = DropdownActionBase & {\n action: () => void;\n /** The gesture that runs this action. Give each gesture to at most one item; a disabled item disables its gesture. */\n gesture?: GestureKind;\n};\n\nexport type GestureMenuSection = Omit<DropdownSection, \"items\"> & {\n items: readonly (GestureMenuAction | DropdownAction | DropdownChoice)[];\n};\n\nexport type GestureMenuItem = GestureMenuAction | DropdownAction | DropdownChoice | GestureMenuSection;\n\nexport type GestureMenuProps = {\n /**\n * The menu. A long press opens a BottomSheet below 48rem and the same menu at the finger from 48rem.\n * Right-click opens it at the pointer; the Context Menu key and Shift+F10 open it beside the focused element.\n * An item with `gesture` is also run by that gesture, so every gesture has its entry here.\n */\n items: readonly GestureMenuItem[];\n /** Names the element and its menu, for example \"Message from Nora, 10:42\". */\n label: string;\n children: JSX.Element;\n /** Shown only above the menu in the phone sheet, for example a row of quick reactions. `close` closes the sheet. */\n sheetTop?: (close: () => void) => JSX.Element;\n /** Tab order of the element. A list that moves focus between its rows itself passes -1. */\n tabIndex?: number;\n /** Runs before the menu or the sheet shows its items, for example to select what was pressed. */\n onOpen?: () => void;\n class?: string;\n};\n\ntype SwipeDirection = \"right\" | \"left\";\n\ntype Swipe = {\n direction: SwipeDirection;\n icon?: string;\n /** How far the content is moved, in pixels; always 0 with reduced motion. */\n offset: number;\n /** Travel relative to the threshold, from 0 to 1. */\n progress: number;\n armed: boolean;\n settling: boolean;\n};\n\ntype Press = {\n id: number;\n x: number;\n y: number;\n timer?: ReturnType<typeof setTimeout>;\n /** The finger left the slop: no tap or long press any more. */\n moved: boolean;\n /** The long press opened the menu or the sheet. */\n long: boolean;\n /** The press started soon after a tap nearby. */\n second: boolean;\n /** The press started at a side edge of the screen. */\n edge: boolean;\n direction?: SwipeDirection;\n};\n\nconst gestureAction = (items: readonly GestureMenuItem[], kind: GestureKind): GestureMenuAction | undefined => {\n for (const item of items)\n for (const entry of \"items\" in item ? item.items : [item])\n if (\"gesture\" in entry && entry.gesture === kind) return entry.disabled ? undefined : entry;\n return undefined;\n};\n\nconst swipeKind = (direction: SwipeDirection): GestureKind => (direction === \"right\" ? \"swipe-right\" : \"swipe-left\");\n\n/**\n * Touch gestures for an element, each the shortcut of an entry in its menu: a horizontal swipe, a double tap, and a\n * long press that opens a `BottomSheet` below 48rem and the same menu at the finger from 48rem. A mouse double-click\n * runs the double-tap action; right-click opens the menu at the pointer, the keyboard beside the focused element.\n * Vertical scrolling never turns into a swipe.\n */\nexport function GestureMenu(props: GestureMenuProps): JSX.Element {\n const locale = useLocale();\n const [swipe, setSwipe] = createSignal<Swipe>();\n let surface!: HTMLDivElement;\n let openMenuAt: ((x: number, y: number) => void) | undefined;\n let closeMenu: (() => void) | undefined;\n let sheetController: AbortController | undefined;\n let press: Press | undefined;\n let lastTap: { x: number; y: number; at: number } | undefined;\n let lastPointer = \"mouse\";\n /**\n * The touch or pen press that just ended did something: its `touchend` is cancelled, so no click or mouse events\n * follow, and a pen's click, which comes without touch events, is cancelled itself.\n */\n let consumed = false;\n let sheetOpen = false;\n /** Closes an open sheet when the element goes, for example when its message is deleted. */\n const disposed = new AbortController();\n let reduced = false;\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n const active = () => props.items.length > 0;\n const wide = () => window.matchMedia?.(\"(min-width: 48rem)\").matches ?? false;\n /**\n * A modal dialog makes everything outside it inert, also ContextMenu's menu on the body, so inside one the hold\n * keeps the sheet, which opens on the same dialog stack. An engine without `:modal` gets the sheet too.\n */\n const inModal = () => {\n const dialog = surface.closest(\"dialog[open]\");\n if (!dialog) return false;\n try {\n return dialog.matches(\":modal\");\n } catch {\n return true;\n }\n };\n const action = (kind: GestureKind) => gestureAction(props.items, kind);\n const touchAction = () => (action(\"swipe-right\") || action(\"swipe-left\") ? \"swipe\" : action(\"double-tap\") ? \"tap\" : undefined);\n\n /** Whether the event started on something with a meaning of its own, inside this element. */\n const ignored = (target: EventTarget | null) => {\n const found = target instanceof Element ? target.closest(IGNORE) : null;\n return found !== null && found !== surface && surface.contains(found);\n };\n\n const openSheet = () => {\n if (sheetOpen || !active()) return;\n sheetOpen = true;\n const controller = new AbortController();\n sheetController = controller;\n const abortSheet = () => controller.abort();\n disposed.signal.addEventListener(\"abort\", abortSheet, { once: true });\n props.onOpen?.();\n void openMenuSheet({\n Items: DropdownItems,\n items: props.items,\n label: props.label,\n locale: locale(),\n top: props.sheetTop,\n signal: controller.signal,\n }).finally(() => {\n disposed.signal.removeEventListener(\"abort\", abortSheet);\n if (sheetController === controller) {\n sheetController = undefined;\n sheetOpen = false;\n }\n });\n };\n\n /** Another pointer that goes down anywhere while a finger presses, as in a pinch, ends the gesture. */\n const onOtherPointer = (event: PointerEvent) => {\n if (!press || event.pointerId === press.id) return;\n if (press.direction) settle();\n endPress();\n };\n\n const endPress = () => {\n clearTimeout(press?.timer);\n press = undefined;\n document.removeEventListener(\"pointerdown\", onOtherPointer, true);\n delete surface.dataset.pressing;\n };\n\n const settle = () => {\n const current = swipe();\n if (!current) return;\n clearTimeout(settleTimer);\n if (reduced || current.offset === 0) {\n setSwipe(undefined);\n return;\n }\n setSwipe({ ...current, offset: 0, progress: 0, armed: false, settling: true });\n settleTimer = setTimeout(() => setSwipe(undefined), SETTLE_MS);\n };\n\n const moveSwipe = (current: Press, direction: SwipeDirection, dx: number) => {\n const travel = Math.max(0, direction === \"right\" ? dx : -dx);\n const moved = travel <= SWIPE_THRESHOLD ? travel : SWIPE_THRESHOLD + (travel - SWIPE_THRESHOLD) * SWIPE_RESISTANCE;\n const offset = reduced ? 0 : Math.min(SWIPE_MAX, moved) * (direction === \"right\" ? 1 : -1);\n current.direction = direction;\n setSwipe({\n direction,\n icon: action(swipeKind(direction))?.icon,\n offset,\n progress: Math.min(1, travel / SWIPE_THRESHOLD),\n armed: travel >= SWIPE_THRESHOLD,\n settling: false,\n });\n };\n\n const longPress = () => {\n if (!press) return;\n press.long = true;\n lastTap = undefined;\n if (wide() && !inModal()) openMenuAt?.(press.x, press.y);\n else openSheet();\n };\n\n const onPointerDown = (event: PointerEvent) => {\n lastPointer = event.pointerType;\n consumed = false;\n // Any press in between, on a link, with a mouse, or with another finger, ends a pending double tap.\n const previous = lastTap;\n lastTap = undefined;\n // Another finger ends the gesture through `onOtherPointer` and starts none.\n if (event.pointerType === \"mouse\" || !event.isPrimary) return;\n endPress();\n if (!active() || ignored(event.target)) return;\n const second =\n previous !== undefined &&\n performance.now() - previous.at <= DOUBLE_TAP_MS &&\n Math.hypot(event.clientX - previous.x, event.clientY - previous.y) <= DOUBLE_TAP_DISTANCE;\n press = {\n id: event.pointerId,\n x: event.clientX,\n y: event.clientY,\n moved: false,\n long: false,\n second,\n edge: event.clientX < EDGE || event.clientX > window.innerWidth - EDGE,\n timer: setTimeout(longPress, LONG_PRESS_MS),\n };\n document.addEventListener(\"pointerdown\", onOtherPointer, true);\n // Hybrid devices keep text selection for the mouse; a finger on the element selects nothing.\n surface.dataset.pressing = \"\";\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n // Hold-then-drag hands this press to DragSource through onPointerDragStart.\n if (current.long) return;\n const dx = event.clientX - current.x;\n const dy = event.clientY - current.y;\n if (current.direction) {\n moveSwipe(current, current.direction, dx);\n return;\n }\n if (current.moved || Math.hypot(dx, dy) < SLOP) return;\n current.moved = true;\n clearTimeout(current.timer);\n if (current.edge || Math.abs(dx) < Math.abs(dy) * SWIPE_RATIO) return;\n const direction: SwipeDirection = dx > 0 ? \"right\" : \"left\";\n if (!action(swipeKind(direction))) return;\n clearTimeout(settleTimer);\n reduced = prefersReducedMotion();\n moveSwipe(current, direction, dx);\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const current = press;\n if (!current || event.pointerId !== current.id) return;\n endPress();\n if (current.long) {\n consumed = true;\n return;\n }\n if (current.direction) {\n // Where the finger lifts decides, and the item as it is now.\n moveSwipe(current, current.direction, event.clientX - current.x);\n const swipeAction = swipe()?.armed ? action(swipeKind(current.direction)) : undefined;\n settle();\n if (swipeAction) {\n consumed = true;\n swipeAction.action();\n }\n return;\n }\n if (current.moved) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n if (current.second) {\n consumed = true;\n doubleTap.action();\n return;\n }\n lastTap = { x: event.clientX, y: event.clientY, at: performance.now() };\n };\n\n // The browser took the touch, for example to scroll the page.\n const onPointerCancel = (event: PointerEvent) => {\n if (!press || event.pointerId !== press.id) return;\n if (press.direction) settle();\n endPress();\n lastTap = undefined;\n };\n\n // Once the hold opens the menu or sheet, further movement must not scroll the page underneath it.\n const onTouchMove = (event: TouchEvent) => {\n if (press?.long && event.cancelable) event.preventDefault();\n };\n\n const onTouchEnd = (event: TouchEvent) => {\n if (!consumed) return;\n consumed = false;\n if (event.cancelable) event.preventDefault();\n };\n\n // A pen sends no touch events; the click after its gesture is cancelled here. A keyboard's click has no detail.\n const onClick = (event: MouseEvent) => {\n if (!consumed || event.detail === 0) return;\n consumed = false;\n event.preventDefault();\n event.stopPropagation();\n };\n\n const onContextMenu = (event: MouseEvent) => {\n // Without items the element has no menu, and the browser keeps its own.\n if (!active()) return;\n // Links, fields, and code keep the browser's own menu.\n if (ignored(event.target)) {\n event.stopPropagation();\n return;\n }\n // A mouse or the keyboard opens the menu beside the element through ContextMenu.\n if (!press && !(\"pointerType\" in event && (event.pointerType === \"touch\" || event.pointerType === \"pen\"))) return;\n // Android and touch screens report a long press as a context-menu event, sometimes before the timer.\n event.preventDefault();\n event.stopPropagation();\n if (press && !press.long && !press.moved) {\n clearTimeout(press.timer);\n longPress();\n }\n };\n\n // The second press of a mouse double-click would select a word; in this element it runs the double-tap action.\n const onMouseDown = (event: MouseEvent) => {\n if (event.button === 0 && event.detail >= 2 && lastPointer === \"mouse\" && action(\"double-tap\") && !ignored(event.target))\n event.preventDefault();\n };\n\n const onDoubleClick = (event: MouseEvent) => {\n if (lastPointer !== \"mouse\" || ignored(event.target)) return;\n const doubleTap = action(\"double-tap\");\n if (!doubleTap) return;\n event.preventDefault();\n doubleTap.action();\n };\n\n onMount(() => {\n const unsubscribeDrag = onPointerDragStart((pointerId) => {\n if (press?.id !== pointerId) return;\n consumed = true;\n lastTap = undefined;\n closeMenu?.();\n sheetController?.abort();\n endPress();\n });\n surface.addEventListener(\"pointerdown\", onPointerDown);\n surface.addEventListener(\"pointermove\", onPointerMove);\n surface.addEventListener(\"pointerup\", onPointerUp);\n surface.addEventListener(\"pointercancel\", onPointerCancel);\n surface.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n surface.addEventListener(\"touchend\", onTouchEnd, { passive: false });\n surface.addEventListener(\"click\", onClick, true);\n surface.addEventListener(\"contextmenu\", onContextMenu);\n surface.addEventListener(\"mousedown\", onMouseDown);\n surface.addEventListener(\"dblclick\", onDoubleClick);\n onCleanup(() => {\n unsubscribeDrag();\n disposed.abort();\n endPress();\n clearTimeout(settleTimer);\n surface.removeEventListener(\"pointerdown\", onPointerDown);\n surface.removeEventListener(\"pointermove\", onPointerMove);\n surface.removeEventListener(\"pointerup\", onPointerUp);\n surface.removeEventListener(\"pointercancel\", onPointerCancel);\n surface.removeEventListener(\"touchmove\", onTouchMove);\n surface.removeEventListener(\"touchend\", onTouchEnd);\n surface.removeEventListener(\"click\", onClick, true);\n surface.removeEventListener(\"contextmenu\", onContextMenu);\n surface.removeEventListener(\"mousedown\", onMouseDown);\n surface.removeEventListener(\"dblclick\", onDoubleClick);\n });\n });\n\n return (\n <ContextMenuBase\n openAt={(open) => (openMenuAt = open)}\n closeWith={(close) => (closeMenu = close)}\n title={props.label}\n items={props.items}\n label={props.label}\n tabIndex={props.tabIndex}\n disabled={!active()}\n onOpen={props.onOpen}\n class={props.class}\n >\n <div\n ref={surface}\n class=\"k2b-gesture-menu\"\n data-active={active() ? \"\" : undefined}\n data-touch={touchAction()}\n data-swipe={swipe()?.direction}\n data-armed={swipe()?.armed ? \"\" : undefined}\n data-settling={swipe()?.settling ? \"\" : undefined}\n style={{\n \"--k2b-gesture-menu-offset\": `${swipe()?.offset ?? 0}px`,\n \"--k2b-gesture-menu-progress\": String(swipe()?.progress ?? 0),\n }}\n >\n <Show when={swipe()}>\n {(current) => (\n <span class=\"k2b-gesture-menu__swipe\" aria-hidden=\"true\">\n <i class={current().icon ?? (current().direction === \"right\" ? \"ti ti-arrow-right\" : \"ti ti-arrow-left\")} />\n </span>\n )}\n </Show>\n <div class=\"k2b-gesture-menu__content\">{props.children}</div>\n </div>\n </ContextMenuBase>\n );\n}\n\nexport default GestureMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
import { useLocale } from "../intl/locale";
|
|
3
|
+
const dragAndDropMessages = i18n.define({
|
|
4
|
+
baseLocale: "en",
|
|
5
|
+
messages: {
|
|
6
|
+
en: {
|
|
7
|
+
pickedUp: ({
|
|
8
|
+
label
|
|
9
|
+
}) => `${label} picked up. Drag it to a place and let go, or press Escape to cancel.`,
|
|
10
|
+
pickedUpKeyboard: ({
|
|
11
|
+
label,
|
|
12
|
+
count
|
|
13
|
+
}) => `${label} picked up. ${count === 1 ? "1 place takes it" : `${count} places take it`}. Arrow keys choose a place, Enter drops, Escape cancels.`,
|
|
14
|
+
choice: ({
|
|
15
|
+
target,
|
|
16
|
+
index,
|
|
17
|
+
count
|
|
18
|
+
}) => `${target}, ${index} of ${count}.`,
|
|
19
|
+
over: ({
|
|
20
|
+
target
|
|
21
|
+
}) => `Over ${target}.`,
|
|
22
|
+
refused: ({
|
|
23
|
+
target,
|
|
24
|
+
label
|
|
25
|
+
}) => `${target} does not take ${label}.`,
|
|
26
|
+
dropped: ({
|
|
27
|
+
label,
|
|
28
|
+
target
|
|
29
|
+
}) => `${label} dropped on ${target}.`,
|
|
30
|
+
cancelled: ({
|
|
31
|
+
label
|
|
32
|
+
}) => `${label} not moved.`,
|
|
33
|
+
noTarget: ({
|
|
34
|
+
label
|
|
35
|
+
}) => `No place here takes ${label}.`
|
|
36
|
+
},
|
|
37
|
+
de: {
|
|
38
|
+
pickedUp: ({
|
|
39
|
+
label
|
|
40
|
+
}) => `${label} angehoben. Zieh es an einen Ort und lass los, oder drück Escape zum Abbrechen.`,
|
|
41
|
+
pickedUpKeyboard: ({
|
|
42
|
+
label,
|
|
43
|
+
count
|
|
44
|
+
}) => `${label} angehoben. ${count === 1 ? "1 Ort nimmt es an" : `${count} Orte nehmen es an`}. Pfeiltasten wählen einen Ort, Eingabe legt ab, Escape bricht ab.`,
|
|
45
|
+
choice: ({
|
|
46
|
+
target,
|
|
47
|
+
index,
|
|
48
|
+
count
|
|
49
|
+
}) => `${target}, ${index} von ${count}.`,
|
|
50
|
+
over: ({
|
|
51
|
+
target
|
|
52
|
+
}) => `Über ${target}.`,
|
|
53
|
+
refused: ({
|
|
54
|
+
target,
|
|
55
|
+
label
|
|
56
|
+
}) => `${target} nimmt ${label} nicht an.`,
|
|
57
|
+
dropped: ({
|
|
58
|
+
label,
|
|
59
|
+
target
|
|
60
|
+
}) => `${label} auf ${target} abgelegt.`,
|
|
61
|
+
cancelled: ({
|
|
62
|
+
label
|
|
63
|
+
}) => `${label} nicht verschoben.`,
|
|
64
|
+
noTarget: ({
|
|
65
|
+
label
|
|
66
|
+
}) => `Hier nimmt kein Ort ${label} an.`
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
export const useDragAndDropMessages = () => {
|
|
71
|
+
const locale = useLocale();
|
|
72
|
+
return () => dragAndDropMessages.resolve([locale()]).t;
|
|
73
|
+
};
|
|
74
|
+
export const checkDragAndDropMessages = () => dragAndDropMessages.check();
|
|
75
|
+
//# sourceMappingURL=drag-and-drop-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/drag-and-drop-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst dragAndDropMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n pickedUp: ({ label }: { label: string }) => `${label} picked up. Drag it to a place and let go, or press Escape to cancel.`,\n pickedUpKeyboard: ({ label, count }: { label: string; count: number }) =>\n `${label} picked up. ${count === 1 ? \"1 place takes it\" : `${count} places take it`}. Arrow keys choose a place, Enter drops, Escape cancels.`,\n choice: ({ target, index, count }: { target: string; index: number; count: number }) => `${target}, ${index} of ${count}.`,\n over: ({ target }: { target: string }) => `Over ${target}.`,\n refused: ({ target, label }: { target: string; label: string }) => `${target} does not take ${label}.`,\n dropped: ({ label, target }: { label: string; target: string }) => `${label} dropped on ${target}.`,\n cancelled: ({ label }: { label: string }) => `${label} not moved.`,\n noTarget: ({ label }: { label: string }) => `No place here takes ${label}.`,\n },\n de: {\n pickedUp: ({ label }: { label: string }) => `${label} angehoben. Zieh es an einen Ort und lass los, oder drück Escape zum Abbrechen.`,\n pickedUpKeyboard: ({ label, count }: { label: string; count: number }) =>\n `${label} angehoben. ${count === 1 ? \"1 Ort nimmt es an\" : `${count} Orte nehmen es an`}. Pfeiltasten wählen einen Ort, Eingabe legt ab, Escape bricht ab.`,\n choice: ({ target, index, count }: { target: string; index: number; count: number }) => `${target}, ${index} von ${count}.`,\n over: ({ target }: { target: string }) => `Über ${target}.`,\n refused: ({ target, label }: { target: string; label: string }) => `${target} nimmt ${label} nicht an.`,\n dropped: ({ label, target }: { label: string; target: string }) => `${label} auf ${target} abgelegt.`,\n cancelled: ({ label }: { label: string }) => `${label} nicht verschoben.`,\n noTarget: ({ label }: { label: string }) => `Hier nimmt kein Ort ${label} an.`,\n },\n },\n});\n\nexport type DragAndDropMessages = ReturnType<(typeof dragAndDropMessages)[\"resolve\"]>[\"t\"];\nexport const useDragAndDropMessages = (): (() => DragAndDropMessages) => {\n const locale = useLocale();\n return () => dragAndDropMessages.resolve([locale()]).t;\n};\nexport const checkDragAndDropMessages = () => dragAndDropMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC;EACtC,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,QAAQ,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,GAAG,KAAK,uEAAuE;MAC3H,gBAAgB,EAAE,CAAC;QAAE,KAAK;QAAE;MAAwC,CAAC,KACnE,GAAG,KAAK,eAAe,KAAK,KAAK,CAAC,GAAG,kBAAkB,GAAG,GAAG,KAAK,iBAAiB,2DAA2D;MAChJ,MAAM,EAAE,CAAC;QAAE,MAAM;QAAE,KAAK;QAAE;MAAwD,CAAC,KAAK,GAAG,MAAM,KAAK,KAAK,OAAO,KAAK,GAAG;MAC1H,IAAI,EAAE,CAAC;QAAE;MAA2B,CAAC,KAAK,QAAQ,MAAM,GAAG;MAC3D,OAAO,EAAE,CAAC;QAAE,MAAM;QAAE;MAAyC,CAAC,KAAK,GAAG,MAAM,kBAAkB,KAAK,GAAG;MACtG,OAAO,EAAE,CAAC;QAAE,KAAK;QAAE;MAA0C,CAAC,KAAK,GAAG,KAAK,eAAe,MAAM,GAAG;MACnG,SAAS,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,GAAG,KAAK,aAAa;MAClE,QAAQ,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,uBAAuB,KAAK;IAC1E,CAAC;IACD,EAAE,EAAE;MACF,QAAQ,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,GAAG,KAAK,iFAAiF;MACrI,gBAAgB,EAAE,CAAC;QAAE,KAAK;QAAE;MAAwC,CAAC,KACnE,GAAG,KAAK,eAAe,KAAK,KAAK,CAAC,GAAG,mBAAmB,GAAG,GAAG,KAAK,oBAAoB,oEAAoE;MAC7J,MAAM,EAAE,CAAC;QAAE,MAAM;QAAE,KAAK;QAAE;MAAwD,CAAC,KAAK,GAAG,MAAM,KAAK,KAAK,QAAQ,KAAK,GAAG;MAC3H,IAAI,EAAE,CAAC;QAAE;MAA2B,CAAC,KAAK,QAAQ,MAAM,GAAG;MAC3D,OAAO,EAAE,CAAC;QAAE,MAAM;QAAE;MAAyC,CAAC,KAAK,GAAG,MAAM,UAAU,KAAK,YAAY;MACvG,OAAO,EAAE,CAAC;QAAE,KAAK;QAAE;MAA0C,CAAC,KAAK,GAAG,KAAK,QAAQ,MAAM,YAAY;MACrG,SAAS,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,GAAG,KAAK,oBAAoB;MACzE,QAAQ,EAAE,CAAC;QAAE;MAAyB,CAAC,KAAK,uBAAuB,KAAK;IAC1E;EACF;AACF,CAAC,CAAC;AAGF,OAAO,MAAM,sBAAsB,GAAG,MAAmC;EACvE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AACD,OAAO,MAAM,wBAAwB,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
|