@k2b/ui 0.28.0 → 0.30.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/README.md +1 -1
- package/dist/base.css +2 -2
- 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/Dropdown.js +6 -3
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +137 -7
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +26 -3
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/SegmentedControl.js +5 -9
- package/dist/browser/actions/SegmentedControl.js.map +1 -1
- package/dist/browser/actions/SpotlightSearch.js +6 -3
- package/dist/browser/actions/SpotlightSearch.js.map +1 -1
- package/dist/browser/actions/Tabs.js +5 -2
- package/dist/browser/actions/Tabs.js.map +1 -1
- package/dist/browser/actions/ViewTabs.js +294 -0
- package/dist/browser/actions/ViewTabs.js.map +1 -0
- 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/filter-messages.js +6 -2
- package/dist/browser/actions/filter-messages.js.map +1 -1
- package/dist/browser/actions/index.js +3 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +1229 -605
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/ChatDecision.js +814 -0
- package/dist/browser/chat/ChatDecision.js.map +1 -0
- package/dist/browser/chat/ChatPrimitives.js +292 -153
- 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 +14 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +35 -17
- package/dist/browser/chat/command-search.js.map +1 -1
- package/dist/browser/chat/index.js +10 -3
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/types.js.map +1 -1
- package/dist/browser/content/Calendar.js +146 -119
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +291 -266
- package/dist/browser/content/CalendarWeekView.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/DataTable.js +224 -155
- package/dist/browser/content/DataTable.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/data-table-messages.js +4 -2
- package/dist/browser/content/data-table-messages.js.map +1 -1
- package/dist/browser/content/index.js +2 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/MovedHint.js +197 -0
- package/dist/browser/feedback/MovedHint.js.map +1 -0
- package/dist/browser/feedback/dialog-core.js +66 -9
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/feedback/index.js +1 -0
- package/dist/browser/feedback/index.js.map +1 -1
- package/dist/browser/feedback/prompts.js +6 -1
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +337 -212
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/date-picker.js +59 -5
- package/dist/browser/inputs/date-picker.js.map +1 -1
- package/dist/browser/intl/messages.js +12 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/intl/weekend.js +39 -0
- package/dist/browser/intl/weekend.js.map +1 -0
- package/dist/browser/layout/AppOverview.js +1 -2
- package/dist/browser/layout/AppOverview.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +947 -531
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +3 -2
- package/dist/browser/layout/PageTitle.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/SettingsModal.js +2 -2
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/layout/SidebarSwitcher.js +19 -11
- package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
- package/dist/browser/layout/TabBar.js +16 -13
- package/dist/browser/layout/TabBar.js.map +1 -1
- package/dist/browser/layout/app-host-width.js +44 -0
- package/dist/browser/layout/app-host-width.js.map +1 -0
- package/dist/browser/layout/app-workspace-controller.js +337 -44
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/index.js +4 -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 +45 -11
- 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/Dropdown.js +5 -2
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +59 -7
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +26 -3
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/SegmentedControl.js +1 -2
- package/dist/ssr/actions/SegmentedControl.js.map +1 -1
- package/dist/ssr/actions/SpotlightSearch.js +2 -2
- package/dist/ssr/actions/SpotlightSearch.js.map +1 -1
- package/dist/ssr/actions/Tabs.js +2 -2
- package/dist/ssr/actions/Tabs.js.map +1 -1
- package/dist/ssr/actions/ViewTabs.js +211 -0
- package/dist/ssr/actions/ViewTabs.js.map +1 -0
- 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/filter-messages.js +6 -2
- package/dist/ssr/actions/filter-messages.js.map +1 -1
- package/dist/ssr/actions/index.js +3 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +668 -136
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/ChatDecision.js +479 -0
- package/dist/ssr/chat/ChatDecision.js.map +1 -0
- package/dist/ssr/chat/ChatPrimitives.js +95 -24
- 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 +14 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +35 -17
- package/dist/ssr/chat/command-search.js.map +1 -1
- package/dist/ssr/chat/index.js +10 -3
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/types.js.map +1 -1
- package/dist/ssr/content/Calendar.js +112 -103
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +42 -28
- package/dist/ssr/content/CalendarWeekView.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/DataTable.js +78 -31
- package/dist/ssr/content/DataTable.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/data-table-messages.js +4 -2
- package/dist/ssr/content/data-table-messages.js.map +1 -1
- package/dist/ssr/content/index.js +2 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/MovedHint.js +166 -0
- package/dist/ssr/feedback/MovedHint.js.map +1 -0
- package/dist/ssr/feedback/dialog-core.js +66 -9
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/feedback/index.js +1 -0
- package/dist/ssr/feedback/index.js.map +1 -1
- package/dist/ssr/feedback/prompts.js +6 -1
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +138 -69
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/date-picker.js +59 -5
- package/dist/ssr/inputs/date-picker.js.map +1 -1
- package/dist/ssr/intl/messages.js +12 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/intl/weekend.js +39 -0
- package/dist/ssr/intl/weekend.js.map +1 -0
- package/dist/ssr/layout/AppOverview.js +1 -2
- package/dist/ssr/layout/AppOverview.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +457 -116
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +3 -2
- package/dist/ssr/layout/PageTitle.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/SettingsModal.js +2 -2
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/layout/SidebarSwitcher.js +19 -11
- package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
- package/dist/ssr/layout/TabBar.js +2 -2
- package/dist/ssr/layout/TabBar.js.map +1 -1
- package/dist/ssr/layout/app-host-width.js +44 -0
- package/dist/ssr/layout/app-host-width.js.map +1 -0
- package/dist/ssr/layout/app-workspace-controller.js +337 -44
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/index.js +4 -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 +25 -6
- 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/Dropdown.d.ts +4 -0
- package/dist/types/actions/FilterChip.d.ts +22 -0
- package/dist/types/actions/ViewTabs.d.ts +30 -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/filter-messages.d.ts +2 -0
- package/dist/types/actions/index.d.ts +6 -2
- package/dist/types/chat/ChatComposer.d.ts +71 -1
- package/dist/types/chat/ChatDecision.d.ts +149 -0
- package/dist/types/chat/ChatPrimitives.d.ts +14 -1
- package/dist/types/chat/ChatTimeline.d.ts +2 -1
- package/dist/types/chat/chat-messages.d.ts +7 -0
- package/dist/types/chat/command-search.d.ts +5 -0
- package/dist/types/chat/index.d.ts +28 -5
- package/dist/types/chat/types.d.ts +54 -1
- package/dist/types/content/Chart.d.ts +9 -3
- package/dist/types/content/DataTable.d.ts +3 -0
- 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/data-table-messages.d.ts +1 -0
- package/dist/types/content/index.d.ts +3 -0
- package/dist/types/feedback/MovedHint.d.ts +25 -0
- package/dist/types/feedback/dialog-core.d.ts +5 -2
- package/dist/types/feedback/index.d.ts +2 -0
- package/dist/types/feedback/prompts.d.ts +2 -0
- package/dist/types/inputs/DatePicker.d.ts +7 -0
- package/dist/types/inputs/date-picker.d.ts +25 -1
- package/dist/types/intl/messages.d.ts +6 -0
- package/dist/types/intl/weekend.d.ts +12 -0
- package/dist/types/layout/AppWorkspace.d.ts +48 -10
- package/dist/types/layout/ResizeSeparator.d.ts +9 -0
- package/dist/types/layout/TabBar.d.ts +7 -0
- package/dist/types/layout/app-host-width.d.ts +6 -0
- package/dist/types/layout/app-workspace-controller.d.ts +2 -0
- package/dist/types/layout/index.d.ts +5 -2
- package/dist/types/layout/resize-separator.d.ts +18 -0
- package/dist/types/layout/workspace-messages.d.ts +5 -0
- package/dist/types/surfaces/Placeholder.d.ts +2 -1
- package/dist/types/surfaces/StatCell.d.ts +6 -0
- package/package.json +5 -5
|
@@ -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":";;;;;;;AAAA,SAAS,YAAY,EAAY,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AAC3E,SAAS,SAAS,QAAQ,gBAAgB;AAC1C,SAAS,oBAAoB,QAAQ,WAAW;AAChD,SAAS,eAAe,QAAQ,eAAe;AAC/C,SAA4E,aAAa,QAA8B,YAAY;AACnI,SAAS,aAAa,QAAQ,cAAc;;AAE5C;AACA,MAAM,aAAa,GAAG,GAAG;AACzB;AACA,MAAM,aAAa,GAAG,GAAG;AACzB;AACA,MAAM,mBAAmB,GAAG,EAAE;AAC9B;AACA,MAAM,IAAI,GAAG,EAAE;AACf;AACA,MAAM,WAAW,GAAG,GAAG;AACvB;AACA,MAAM,eAAe,GAAG,EAAE;AAC1B;AACA,MAAM,SAAS,GAAG,EAAE;AACpB,MAAM,gBAAgB,GAAG,IAAI;AAC7B;AACA,MAAM,IAAI,GAAG,EAAE;AACf;AACA,MAAM,SAAS,GAAG,GAAG;;AAErB;AACA;AACA;AACA;AACA,MAAM,MAAM,GAAG,CACb,SAAS,EACT,QAAQ,EACR,OAAO,EACP,UAAU,EACV,QAAQ,EACR,SAAS,EACT,OAAO,EACP,OAAO,EACP,OAAO,EACP,KAAK,EACL,kDAAkD,EAClD,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,CACxB,CAAC,IAAI,CAAC,IAAI,CAAC;;AAIZ;;AA6DA,MAAM,aAAa,GAAG,CAAC,KAAiC,EAAE,IAAiB,KAAoC;EAC7G,KAAK,MAAM,IAAI,IAAI,KAAK,EACtB,KAAK,MAAM,KAAK,IAAI,OAAO,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,EACvD,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,KAAK;EAC/F,OAAO,SAAS;AAClB,CAAC;AAED,MAAM,SAAS,GAAI,SAAyB,IAAmB,SAAS,KAAK,OAAO,GAAG,aAAa,GAAG,YAAa;;AAEpH;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,WAAW,CAAC,KAAuB,EAAe;EAChE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAQ,CAAC;EAC/C,IAAI,OAAwB;EAC5B,IAAI,UAAwD;EAC5D,IAAI,KAAwB;EAC5B,IAAI,OAAyD;EAC7D,IAAI,WAAW,GAAG,OAAO;EACzB;AACF;AACA;AACA;EACE,IAAI,QAAQ,GAAG,KAAK;EACpB,IAAI,SAAS,GAAG,KAAK;EACrB;EACA,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,CAAC;EACtC,IAAI,OAAO,GAAG,KAAK;EACnB,IAAI,WAAsD;EAE1D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;EAC3C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,GAAG,oBAAoB,CAAC,CAAC,OAAO,IAAI,KAAK;EAC7E;AACF;AACA;AACA;EACE,MAAM,OAAO,GAAG,MAAM;IACpB,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,OAAO,KAAK;IACzB,IAAI;MACF,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjC,CAAC,CAAC,MAAM;MACN,OAAO,IAAI;IACb;EACF,CAAC;EACD,MAAM,MAAM,GAAI,IAAiB,IAAK,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;EACtE,MAAM,WAAW,GAAG,MAAO,MAAM,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,GAAG,SAAU;;EAE9H;EACA,MAAM,OAAO,GAAI,MAA0B,IAAK;IAC9C,MAAM,KAAK,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;IACvE,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;EACvE,CAAC;EAED,MAAM,SAAS,GAAG,MAAM;IACtB,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IAC5B,SAAS,GAAG,IAAI;IAChB,KAAK,CAAC,MAAM,GAAG,CAAC;IAChB,KAAK,aAAa,CAAC;MACjB,KAAK,EAAE,aAAa;MACpB,KAAK,EAAE,KAAK,CAAC,KAAK;MAClB,KAAK,EAAE,KAAK,CAAC,KAAK;MAClB,MAAM,EAAE,MAAM,CAAC,CAAC;MAChB,GAAG,EAAE,KAAK,CAAC,QAAQ;MACnB,MAAM,EAAE,QAAQ,CAAC;IACnB,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;MACf,SAAS,GAAG,KAAK;IACnB,CAAC,CAAC;EACJ,CAAC;;EAED;EACA,MAAM,cAAc,GAAI,KAAmB,IAAK;IAC9C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,EAAE;IAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,CAAC;EACZ,CAAC;EAED,MAAM,QAAQ,GAAG,MAAM;IACrB,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;IAC1B,KAAK,GAAG,SAAS;IACjB,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;IACjE,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ;EACjC,CAAC;EAED,MAAM,MAAM,GAAG,MAAM;IACnB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE;IACd,YAAY,CAAC,WAAW,CAAC;IACzB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;MACnC,QAAQ,CAAC,SAAS,CAAC;MACnB;IACF;IACA,QAAQ,CAAC;MAAE,GAAG,OAAO;MAAE,MAAM,EAAE,CAAC;MAAE,QAAQ,EAAE,CAAC;MAAE,KAAK,EAAE,KAAK;MAAE,QAAQ,EAAE;IAAK,CAAC,CAAC;IAC9E,WAAW,GAAG,UAAU,CAAC,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;EAChE,CAAC;EAED,MAAM,SAAS,GAAG,CAAC,OAAc,EAAE,SAAyB,EAAE,EAAU,KAAK;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,KAAK,OAAO,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,IAAI,eAAe,GAAG,MAAM,GAAG,eAAe,GAAG,CAAC,MAAM,GAAG,eAAe,IAAI,gBAAgB;IAClH,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,SAAS,KAAK,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,SAAS,GAAG,SAAS;IAC7B,QAAQ,CAAC;MACP,SAAS;MACT,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI;MACxC,MAAM;MACN,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;MAC/C,KAAK,EAAE,MAAM,IAAI,eAAe;MAChC,QAAQ,EAAE;IACZ,CAAC,CAAC;EACJ,CAAC;EAED,MAAM,SAAS,GAAG,MAAM;IACtB,IAAI,CAAC,KAAK,EAAE;IACZ,KAAK,CAAC,IAAI,GAAG,IAAI;IACjB,OAAO,GAAG,SAAS;IACnB,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KACpD,SAAS,CAAC,CAAC;EAClB,CAAC;EAED,MAAM,aAAa,GAAI,KAAmB,IAAK;IAC7C,WAAW,GAAG,KAAK,CAAC,WAAW;IAC/B,QAAQ,GAAG,KAAK;IAChB;IACA,MAAM,QAAQ,GAAG,OAAO;IACxB,OAAO,GAAG,SAAS;IACnB;IACA,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;IACvD,QAAQ,CAAC,CAAC;IACV,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;IACxC,MAAM,MAAM,GACV,QAAQ,KAAK,SAAS,IACtB,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,IAAI,aAAa,IAChD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,mBAAmB;IAC3F,KAAK,GAAG;MACN,EAAE,EAAE,KAAK,CAAC,SAAS;MACnB,CAAC,EAAE,KAAK,CAAC,OAAO;MAChB,CAAC,EAAE,KAAK,CAAC,OAAO;MAChB,KAAK,EAAE,KAAK;MACZ,IAAI,EAAE,KAAK;MACX,MAAM;MACN,IAAI,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI;MACtE,KAAK,EAAE,UAAU,CAAC,SAAS,EAAE,aAAa;IAC5C,CAAC;IACD,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,cAAc,EAAE,IAAI,CAAC;IAC9D;IACA,OAAO,CAAC,OAAO,CAAC,QAAQ,GAAG,EAAE;EAC/B,CAAC;EAED,MAAM,aAAa,GAAI,KAAmB,IAAK;IAC7C,MAAM,OAAO,GAAG,KAAK;IACrB,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE;IAChD;IACA,IAAI,OAAO,CAAC,IAAI,EAAE;IAClB,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC;IACpC,IAAI,OAAO,CAAC,SAAS,EAAE;MACrB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;MACzC;IACF;IACA,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE;IAChD,OAAO,CAAC,KAAK,GAAG,IAAI;IACpB,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3B,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE;IAC/D,MAAM,SAAyB,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,GAAG,MAAM;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE;IACnC,YAAY,CAAC,WAAW,CAAC;IACzB,OAAO,GAAG,oBAAoB,CAAC,CAAC;IAChC,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC;EACnC,CAAC;EAED,MAAM,WAAW,GAAI,KAAmB,IAAK;IAC3C,MAAM,OAAO,GAAG,KAAK;IACrB,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE;IAChD,QAAQ,CAAC,CAAC;IACV,IAAI,OAAO,CAAC,IAAI,EAAE;MAChB,QAAQ,GAAG,IAAI;MACf;IACF;IACA,IAAI,OAAO,CAAC,SAAS,EAAE;MACrB;MACA,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;MAChE,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,SAAS;MACrF,MAAM,CAAC,CAAC;MACR,IAAI,WAAW,EAAE;QACf,QAAQ,GAAG,IAAI;QACf,WAAW,CAAC,MAAM,CAAC,CAAC;MACtB;MACA;IACF;IACA,IAAI,OAAO,CAAC,KAAK,EAAE;IACnB,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IACtC,IAAI,CAAC,SAAS,EAAE;IAChB,IAAI,OAAO,CAAC,MAAM,EAAE;MAClB,QAAQ,GAAG,IAAI;MACf,SAAS,CAAC,MAAM,CAAC,CAAC;MAClB;IACF;IACA,OAAO,GAAG;MAAE,CAAC,EAAE,KAAK,CAAC,OAAO;MAAE,CAAC,EAAE,KAAK,CAAC,OAAO;MAAE,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC;IAAE,CAAC;EACzE,CAAC;;EAED;EACA,MAAM,eAAe,GAAI,KAAmB,IAAK;IAC/C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,EAAE;IAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,CAAC;IACV,OAAO,GAAG,SAAS;EACrB,CAAC;;EAED;EACA,MAAM,WAAW,GAAI,KAAiB,IAAK;IACzC,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;EAC7D,CAAC;EAED,MAAM,UAAU,GAAI,KAAiB,IAAK;IACxC,IAAI,CAAC,QAAQ,EAAE;IACf,QAAQ,GAAG,KAAK;IAChB,IAAI,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;EAC9C,CAAC;;EAED;EACA,MAAM,OAAO,GAAI,KAAiB,IAAK;IACrC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;IACrC,QAAQ,GAAG,KAAK;IAChB,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,KAAK,CAAC,eAAe,CAAC,CAAC;EACzB,CAAC;EAED,MAAM,aAAa,GAAI,KAAiB,IAAK;IAC3C;IACA,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IACf;IACA,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;MACzB,KAAK,CAAC,eAAe,CAAC,CAAC;MACvB;IACF;IACA;IACA,IAAI,CAAC,KAAK,IAAI,EAAE,aAAa,IAAI,KAAK,KAAK,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,EAAE;IAC3G;IACA,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,KAAK,CAAC,eAAe,CAAC,CAAC;IACvB,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;MACxC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC;MACzB,SAAS,CAAC,CAAC;IACb;EACF,CAAC;;EAED;EACA,MAAM,WAAW,GAAI,KAAiB,IAAK;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,WAAW,KAAK,OAAO,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EACtH,KAAK,CAAC,cAAc,CAAC,CAAC;EAC1B,CAAC;EAED,MAAM,aAAa,GAAI,KAAiB,IAAK;IAC3C,IAAI,WAAW,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;IACtD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IACtC,IAAI,CAAC,SAAS,EAAE;IAChB,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,SAAS,CAAC,MAAM,CAAC,CAAC;EACpB,CAAC;EAED,OAAO,CAAC,MAAM;IACZ,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1D,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE;MAAE,OAAO,EAAE;IAAM,CAAC,CAAC;IACtE,OAAO,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE;MAAE,OAAO,EAAE;IAAM,CAAC,CAAC;IACpE,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;IAChD,OAAO,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IACtD,OAAO,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAC,UAAU,EAAE,aAAa,CAAC;IACnD,SAAS,CAAC,MAAM;MACd,QAAQ,CAAC,KAAK,CAAC,CAAC;MAChB,QAAQ,CAAC,CAAC;MACV,YAAY,CAAC,WAAW,CAAC;MACzB,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,eAAe,EAAE,eAAe,CAAC;MAC7D,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC;MACnD,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;MACnD,OAAO,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;MACzD,OAAO,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;MACrD,OAAO,CAAC,mBAAmB,CAAC,UAAU,EAAE,aAAa,CAAC;IACxD,CAAC,CAAC;EACJ,CAAC,CAAC;EAEF,yBACG,eAAe;IACd,MAAM,EAAG,IAAI,IAAM,UAAU,GAAG,IAAK;IAAA,IACrC,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,QAAQ;MAAA,OAAE,CAAC,MAAM,CAAC,CAAC;IAAA;IAAA,IACnB,MAAM;MAAA,OAAE,KAAK,CAAC,MAAM;IAAA;IAAA;MAAA,OACb,KAAK,CAAC,KAAK;IAAA;IAAA;MAAA,mDAKH,MAAM,CAAC,CAAC,GAAG,EAAE,YAAG,SAAS,wDAC1B,WAAW,CAAC,CAAC,wDACb,KAAK,CAAC,CAAC,EAAE,SAAS,+CAClB,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,YAAG,SAAS,kDAC5B,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,EAAE,YAAG,SAAS,kEAElB,YAAG,KAAK,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,WAAI,iEACzB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,CAAC,qCAG9D,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,CAAC;QAAA;QAAA,UACf,OAAO,oDAEK,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;MAE3G,cAEqC,KAAK,CAAC,QAAQ;IAAA;EAAA;AAI9D;AAEA,eAAe,WAAW","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":[]}
|
|
@@ -45,12 +45,11 @@ export function SegmentedControl(props) {
|
|
|
45
45
|
if (currentValue() === value) return 0;
|
|
46
46
|
return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;
|
|
47
47
|
};
|
|
48
|
-
const divider = (index, value) => index < props.options.length - 1 && currentValue() !== value && currentValue() !== props.options[index + 1]?.value;
|
|
49
48
|
return _$ssr(_tmpl$, `k2b-segmented-control ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-size", _$escape(props.size ?? "md", true), false), _$ssrAttribute("aria-label", _$escape(props.ariaLabel ?? props.label ?? messages().options, true), false), _$ssrAttribute("aria-disabled", props.disabled ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(For, {
|
|
50
49
|
get each() {
|
|
51
50
|
return props.options;
|
|
52
51
|
},
|
|
53
|
-
children: (option, index) => _$ssr(_tmpl$2, _$ssrAttribute("aria-checked", _$escape(currentValue(), true) === _$escape(option.value, true), false) + _$ssrAttribute("data-selected", currentValue() === option.value ? "true" : _$escape(undefined, true), false)
|
|
52
|
+
children: (option, index) => _$ssr(_tmpl$2, _$ssrAttribute("aria-checked", _$escape(currentValue(), true) === _$escape(option.value, true), false) + _$ssrAttribute("data-selected", currentValue() === option.value ? "true" : _$escape(undefined, true), false), _$ssrAttribute("disabled", props.disabled || option.disabled, true) + _$ssrAttribute("tabindex", _$escape(tabIndex(index(), option.value), true), false), option.icon && _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(option.icon, true), false)), _$escape(option.label))
|
|
54
53
|
})));
|
|
55
54
|
}
|
|
56
55
|
export default SegmentedControl;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/SegmentedControl.tsx"],"sourcesContent":["import { createMemo, For, type JSX } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type SegmentedControlProps<T extends string = string> = {\n options: readonly SegmentOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n disabled?: boolean;\n ariaLabel?: string;\n label?: string;\n size?: \"sm\" | \"md\";\n class?: string;\n};\n\n/** Controlled radio group with automatic selection during arrow-key navigation. */\nexport function SegmentedControl<T extends string = string>(props: SegmentedControlProps<T>): JSX.Element {\n const messages = useUiMessages();\n const buttons: HTMLButtonElement[] = [];\n const currentValue = createMemo<T>(() => (typeof props.value === \"function\" ? props.value() : props.value));\n const enabled = createMemo(() =>\n props.options.map((option, index) => ({ option, index })).filter(({ option }) => !props.disabled && !option.disabled),\n );\n const selectedEnabled = createMemo(() =>\n props.options.some((option) => option.value === currentValue() && !props.disabled && !option.disabled),\n );\n const emit = (value: T) => props.onValueChange(value);\n const select = (index: number) => {\n const option = props.options[index];\n if (!option || props.disabled || option.disabled) return;\n emit(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const selectRelative = (currentIndex: number, direction: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const current = available.findIndex(({ index }) => index === currentIndex);\n const next = available[(current + direction + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n const edge = (last: boolean) => {\n const available = enabled();\n const next = last ? available.at(-1) : available[0];\n if (next) select(next.index);\n };\n const tabIndex = (index: number, value: T) => {\n if (props.disabled || props.options[index]?.disabled) return -1;\n if (currentValue() === value) return 0;\n return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;\n };\n
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/SegmentedControl.tsx"],"sourcesContent":["import { createMemo, For, type JSX } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type SegmentOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n};\n\nexport type SegmentedControlProps<T extends string = string> = {\n options: readonly SegmentOption<T>[];\n value: T | (() => T);\n onValueChange: (value: T) => void;\n disabled?: boolean;\n ariaLabel?: string;\n label?: string;\n size?: \"sm\" | \"md\";\n class?: string;\n};\n\n/** Controlled radio group with automatic selection during arrow-key navigation. */\nexport function SegmentedControl<T extends string = string>(props: SegmentedControlProps<T>): JSX.Element {\n const messages = useUiMessages();\n const buttons: HTMLButtonElement[] = [];\n const currentValue = createMemo<T>(() => (typeof props.value === \"function\" ? props.value() : props.value));\n const enabled = createMemo(() =>\n props.options.map((option, index) => ({ option, index })).filter(({ option }) => !props.disabled && !option.disabled),\n );\n const selectedEnabled = createMemo(() =>\n props.options.some((option) => option.value === currentValue() && !props.disabled && !option.disabled),\n );\n const emit = (value: T) => props.onValueChange(value);\n const select = (index: number) => {\n const option = props.options[index];\n if (!option || props.disabled || option.disabled) return;\n emit(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const selectRelative = (currentIndex: number, direction: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const current = available.findIndex(({ index }) => index === currentIndex);\n const next = available[(current + direction + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n const edge = (last: boolean) => {\n const available = enabled();\n const next = last ? available.at(-1) : available[0];\n if (next) select(next.index);\n };\n const tabIndex = (index: number, value: T) => {\n if (props.disabled || props.options[index]?.disabled) return -1;\n if (currentValue() === value) return 0;\n return !selectedEnabled() && enabled()[0]?.index === index ? 0 : -1;\n };\n\n return (\n <div\n class={`k2b-segmented-control ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n role=\"radiogroup\"\n aria-label={props.ariaLabel ?? props.label ?? messages().options}\n aria-orientation=\"horizontal\"\n aria-disabled={props.disabled ? \"true\" : undefined}\n >\n <For each={props.options}>\n {(option, index) => (\n <button\n ref={(element) => {\n buttons[index()] = element;\n }}\n type=\"button\"\n role=\"radio\"\n class=\"k2b-segmented-control__option\"\n aria-checked={currentValue() === option.value}\n data-selected={currentValue() === option.value ? \"true\" : undefined}\n disabled={props.disabled || option.disabled}\n tabIndex={tabIndex(index(), option.value)}\n onClick={() => emit(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n selectRelative(index(), 1);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n selectRelative(index(), -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n edge(event.key === \"End\");\n }\n }}\n >\n {option.icon && <i class={option.icon} aria-hidden=\"true\" />}\n <span>{option.label}</span>\n </button>\n )}\n </For>\n </div>\n );\n}\n\nexport default SegmentedControl;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -2,7 +2,7 @@ import { createComponent as _$createComponent } from "solid-js/web";
|
|
|
2
2
|
import { ssr as _$ssr } from "solid-js/web";
|
|
3
3
|
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
4
4
|
import { escape as _$escape } from "solid-js/web";
|
|
5
|
-
var _tmpl$ = ["<button type=\"button\" class=\"", "\"", "", "><i", " aria-hidden=\"true\"></i><span
|
|
5
|
+
var _tmpl$ = ["<button type=\"button\" class=\"", "\"", "", "><i", " aria-hidden=\"true\"></i><span", ">", "</span>", "</button>"],
|
|
6
6
|
_tmpl$2 = ["<kbd class=\"k2b-kbd\"><kbd class=\"k2b-kbd__key\">", "</kbd></kbd>"];
|
|
7
7
|
import { Kbd } from "../content/Kbd";
|
|
8
8
|
import { prompts } from "../feedback/prompts";
|
|
@@ -32,7 +32,7 @@ export function SpotlightButton(props) {
|
|
|
32
32
|
const shortcut = () => props.shortcut ?? props.shortcutLabel;
|
|
33
33
|
const title = () => props.title ?? label();
|
|
34
34
|
const showsShortcut = () => Boolean(shortcut()) && ["chip", "sidebar"].includes(variant());
|
|
35
|
-
return _$ssr(_tmpl$, `k2b-spotlight-button ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-variant", _$escape(variant(), true), false), _$ssrAttribute("disabled", props.disabled, true) + _$ssrAttribute("aria-label", _$escape(props.ariaLabel ?? (["compact", "icon"].includes(variant()) ? label() : undefined), true), false) + _$ssrAttribute("title", _$escape(title(), true), false), _$ssrAttribute("class", _$escape(icon(), true), false), _$escape(label()), showsShortcut() && (props.shortcut !== undefined ? _$escape(_$createComponent(Kbd, {
|
|
35
|
+
return _$ssr(_tmpl$, `k2b-spotlight-button ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-variant", _$escape(variant(), true), false), _$ssrAttribute("disabled", props.disabled, true) + _$ssrAttribute("aria-label", _$escape(props.ariaLabel ?? (["compact", "icon"].includes(variant()) ? label() : undefined), true), false) + _$ssrAttribute("title", _$escape(title(), true), false), _$ssrAttribute("class", _$escape(icon(), true), false), _$ssrAttribute("class", variant() === "sidebar" ? "k2b-spotlight-button__label k2b-truncate-fade" : "k2b-spotlight-button__label", false), _$escape(label()), showsShortcut() && (props.shortcut !== undefined ? _$escape(_$createComponent(Kbd, {
|
|
36
36
|
get keys() {
|
|
37
37
|
return props.shortcut;
|
|
38
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/SpotlightSearch.tsx"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { Kbd } from \"../content/Kbd\";\nimport type { PromptSearchInput, PromptSearchItem, PromptSearchOptions } from \"../feedback/prompts\";\nimport { prompts } from \"../feedback/prompts\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\nimport { resolveSpotlightMessages } from \"./spotlight-messages\";\n\nexport type SpotlightSearchResolver<T = unknown> = (input: PromptSearchInput) => Promise<PromptSearchItem<T>[]> | PromptSearchItem<T>[];\n\nexport type SpotlightSearchOptions<T = unknown> = PromptSearchOptions & {\n resolve: SpotlightSearchResolver<T>;\n};\n\nexport type SpotlightButtonVariant = \"default\" | \"compact\" | \"chip\" | \"sidebar\" | \"sidebar-mobile\" | \"icon\";\n\nexport type SpotlightButtonProps = {\n variant?: SpotlightButtonVariant;\n label?: string;\n title?: string;\n icon?: string;\n /** Shortcut such as \"mod+k\"; takes precedence over shortcutLabel. */\n shortcut?: string;\n shortcutLabel?: string | false;\n ariaLabel?: string;\n disabled?: boolean;\n class?: string;\n onClick: () => void | Promise<void>;\n};\n\nexport const openSpotlightSearch = <T extends unknown = unknown>(\n options: SpotlightSearchOptions<T>,\n): Promise<PromptSearchItem<T> | undefined> => {\n const { resolve, ...promptOptions } = options;\n const messages = resolveUiMessages();\n const spotlightMessages = resolveSpotlightMessages();\n return prompts.search(resolve, {\n icon: \"ti ti-search\",\n placeholder: messages.search,\n minQueryLength: 0,\n noResultsText: spotlightMessages.spotlightNoResults,\n size: \"small\",\n ...promptOptions,\n });\n};\n\nexport function SpotlightButton(props: SpotlightButtonProps): JSX.Element {\n const messages = useUiMessages();\n const variant = () => props.variant ?? \"default\";\n const label = () => props.label ?? messages().searchLabel;\n const icon = () => props.icon ?? \"ti ti-search\";\n const shortcut = () => props.shortcut ?? props.shortcutLabel;\n const title = () => props.title ?? label();\n const showsShortcut = () => Boolean(shortcut()) && [\"chip\", \"sidebar\"].includes(variant());\n\n return (\n <button\n type=\"button\"\n class={`k2b-spotlight-button ${props.class ?? \"\"}`}\n data-variant={variant()}\n disabled={props.disabled}\n aria-label={props.ariaLabel ?? ([\"compact\", \"icon\"].includes(variant()) ? label() : undefined)}\n title={title()}\n onClick={() => void props.onClick()}\n >\n <i class={icon()} aria-hidden=\"true\" />\n <span class
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/SpotlightSearch.tsx"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { Kbd } from \"../content/Kbd\";\nimport type { PromptSearchInput, PromptSearchItem, PromptSearchOptions } from \"../feedback/prompts\";\nimport { prompts } from \"../feedback/prompts\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\nimport { resolveSpotlightMessages } from \"./spotlight-messages\";\n\nexport type SpotlightSearchResolver<T = unknown> = (input: PromptSearchInput) => Promise<PromptSearchItem<T>[]> | PromptSearchItem<T>[];\n\nexport type SpotlightSearchOptions<T = unknown> = PromptSearchOptions & {\n resolve: SpotlightSearchResolver<T>;\n};\n\nexport type SpotlightButtonVariant = \"default\" | \"compact\" | \"chip\" | \"sidebar\" | \"sidebar-mobile\" | \"icon\";\n\nexport type SpotlightButtonProps = {\n variant?: SpotlightButtonVariant;\n label?: string;\n title?: string;\n icon?: string;\n /** Shortcut such as \"mod+k\"; takes precedence over shortcutLabel. */\n shortcut?: string;\n shortcutLabel?: string | false;\n ariaLabel?: string;\n disabled?: boolean;\n class?: string;\n onClick: () => void | Promise<void>;\n};\n\nexport const openSpotlightSearch = <T extends unknown = unknown>(\n options: SpotlightSearchOptions<T>,\n): Promise<PromptSearchItem<T> | undefined> => {\n const { resolve, ...promptOptions } = options;\n const messages = resolveUiMessages();\n const spotlightMessages = resolveSpotlightMessages();\n return prompts.search(resolve, {\n icon: \"ti ti-search\",\n placeholder: messages.search,\n minQueryLength: 0,\n noResultsText: spotlightMessages.spotlightNoResults,\n size: \"small\",\n ...promptOptions,\n });\n};\n\nexport function SpotlightButton(props: SpotlightButtonProps): JSX.Element {\n const messages = useUiMessages();\n const variant = () => props.variant ?? \"default\";\n const label = () => props.label ?? messages().searchLabel;\n const icon = () => props.icon ?? \"ti ti-search\";\n const shortcut = () => props.shortcut ?? props.shortcutLabel;\n const title = () => props.title ?? label();\n const showsShortcut = () => Boolean(shortcut()) && [\"chip\", \"sidebar\"].includes(variant());\n\n return (\n <button\n type=\"button\"\n class={`k2b-spotlight-button ${props.class ?? \"\"}`}\n data-variant={variant()}\n disabled={props.disabled}\n aria-label={props.ariaLabel ?? ([\"compact\", \"icon\"].includes(variant()) ? label() : undefined)}\n title={title()}\n onClick={() => void props.onClick()}\n >\n <i class={icon()} aria-hidden=\"true\" />\n <span class={variant() === \"sidebar\" ? \"k2b-spotlight-button__label k2b-truncate-fade\" : \"k2b-spotlight-button__label\"}>\n {label()}\n </span>\n {showsShortcut() &&\n (props.shortcut !== undefined ? (\n <Kbd keys={props.shortcut} />\n ) : (\n <kbd class=\"k2b-kbd\">\n <kbd class=\"k2b-kbd__key\">{props.shortcutLabel}</kbd>\n </kbd>\n ))}\n </button>\n );\n}\n\nexport default SpotlightButton;\n"],"mappings":";;;;;;AACA,SAAS,GAAG,QAAQ,gBAAgB;AAEpC,SAAS,OAAO,QAAQ,qBAAqB;AAC7C,SAAS,iBAAiB,EAAE,aAAa,QAAQ,kBAAkB;AACnE,SAAS,wBAAwB,QAAQ,sBAAsB;AAwB/D,OAAO,MAAM,mBAAmB,GAC9B,OAAkC,IACW;EAC7C,MAAM;IAAE,OAAO;IAAE,GAAG;EAAc,CAAC,GAAG,OAAO;EAC7C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC;EACpC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,CAAC;EACpD,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,QAAQ,CAAC,MAAM;IAC5B,cAAc,EAAE,CAAC;IACjB,aAAa,EAAE,iBAAiB,CAAC,kBAAkB;IACnD,IAAI,EAAE,OAAO;IACb,GAAG;EACL,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,SAAS,eAAe,CAAC,KAA2B,EAAe;EACxE,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,IAAI,SAAS;EAChD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW;EACzD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,cAAc;EAC/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,aAAa;EAC5D,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC;EAC1C,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;EAE1F,qBAGW,iCAAwB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,0CACpC,OAAO,CAAC,CAAC,4CACb,KAAK,CAAC,QAAQ,gDACZ,KAAK,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,mDACvF,KAAK,CAAC,CAAC,kDAGJ,IAAI,CAAC,CAAC,yCACH,OAAO,CAAC,CAAC,KAAK,SAAS,GAAG,+CAA+C,GAAG,6BAA6B,mBACnH,KAAK,CAAC,CAAC,GAET,aAAa,CAAC,CAAC,KACb,KAAK,CAAC,QAAQ,KAAK,SAAS,8BAC1B,GAAG;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;EAAA,8BAGI,KAAK,CAAC,aAAa,EAEjD,CAAC;AAGV;AAEA,eAAe,eAAe","ignoreList":[]}
|
package/dist/ssr/actions/Tabs.js
CHANGED
|
@@ -6,7 +6,7 @@ var _tmpl$ = ["<div class=\"k2b-tabs__trailing\">", "</div>"],
|
|
|
6
6
|
_tmpl$2 = ["<div id=\"", "\" class=\"k2b-tabs__panel\" role=\"tabpanel\" aria-labelledby=\"", "\" tabindex=\"0\">", "</div>"],
|
|
7
7
|
_tmpl$3 = ["<div class=\"", "\"", "><div class=\"k2b-tabs__bar\"><div", " data-scroll-fade-axis=\"horizontal\" class=\"k2b-tabs__list\" role=\"tablist\"", ">", "</div>", "</div>", "</div>"],
|
|
8
8
|
_tmpl$4 = ["<button type=\"button\" class=\"k2b-tabs__close\"", "", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
|
|
9
|
-
_tmpl$5 = ["<div class=\"k2b-tabs__item\" role=\"presentation\"><button", " type=\"button\" role=\"tab\"", "", ">", "<span>", "</span></button>", "</div>"],
|
|
9
|
+
_tmpl$5 = ["<div class=\"k2b-tabs__item\" role=\"presentation\"><button", " type=\"button\" role=\"tab\"", "", ">", "<span", ">", "</span></button>", "</div>"],
|
|
10
10
|
_tmpl$6 = ["<i", " aria-hidden=\"true\"></i>"];
|
|
11
11
|
import { children, createEffect, createMemo, createUniqueId, For, Show } from "solid-js";
|
|
12
12
|
import { resolveMaybeAccessor } from "../inputs/field-contract";
|
|
@@ -105,7 +105,7 @@ function TabsRoot(props) {
|
|
|
105
105
|
return option.icon;
|
|
106
106
|
},
|
|
107
107
|
children: icon => _$ssr(_tmpl$6, _$ssrAttribute("class", _$escape(icon(), true), false))
|
|
108
|
-
})), _$escape(option.label), _$escape(_$createComponent(Show, {
|
|
108
|
+
})), _$ssrAttribute("class", props.variant === "pill" ? "k2b-truncate-fade" : _$escape(undefined, true), false), _$escape(option.label), _$escape(_$createComponent(Show, {
|
|
109
109
|
get when() {
|
|
110
110
|
return option.onClose;
|
|
111
111
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/Tabs.tsx"],"sourcesContent":["import { children, createEffect, createMemo, createUniqueId, For, type JSX, Show } from \"solid-js\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { resolveMaybeAccessor } from \"../inputs/field-contract\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade } from \"../layout/scroll-fade\";\n\nexport type TabOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n panel?: JSX.Element;\n onClose?: () => void;\n closeLabel?: string;\n};\n\nexport type TabsItemProps<T extends string = string> = Omit<TabOption<T>, \"panel\"> & {\n children?: JSX.Element;\n};\n\ntype TabsItemSlot<T extends string = string> = {\n readonly kind: typeof TABS_ITEM;\n readonly props: TabsItemProps<T>;\n};\n\nexport type TabsProps<T extends string = string> = {\n value: MaybeAccessor<T>;\n onValueChange: (value: T) => void;\n ariaLabel: string;\n orientation?: \"horizontal\" | \"vertical\";\n class?: string;\n variant?: \"line\" | \"pill\";\n trailing?: JSX.Element;\n /** Data-driven alternative to colocated `Tabs.Item` children. */\n options?: readonly TabOption<T>[];\n children?: JSX.Element;\n};\n\ntype TabsComponent = (<T extends string = string>(props: TabsProps<T>) => JSX.Element) & {\n Item: <T extends string = string>(props: TabsItemProps<T>) => JSX.Element;\n};\n\nconst TABS_ITEM = Symbol(\"Tabs.Item\");\n\nconst isTabsItem = <T extends string>(value: unknown): value is TabsItemSlot<T> =>\n !!value && typeof value === \"object\" && \"kind\" in value && value.kind === TABS_ITEM;\n\nconst collectTabsItems = <T extends string>(value: unknown): TabsItemSlot<T>[] => {\n if (Array.isArray(value)) return value.flatMap(collectTabsItems<T>);\n return isTabsItem<T>(value) ? [value] : [];\n};\n\nfunction TabsItem<T extends string = string>(props: TabsItemProps<T>): JSX.Element {\n return { kind: TABS_ITEM, props } satisfies TabsItemSlot<T> as unknown as JSX.Element;\n}\n\n/** Controlled, keyboard-accessible tabs with compositional or data-driven items. */\nfunction TabsRoot<T extends string = string>(props: TabsProps<T>): JSX.Element {\n const messages = useUiMessages();\n let root: HTMLDivElement | undefined;\n let list: HTMLDivElement | undefined;\n createScrollFade(\n () => list,\n () => props.orientation !== \"vertical\",\n );\n const instanceId = `k2b-tabs-${createUniqueId()}`;\n const resolvedChildren = children(() => props.children);\n const trailing = children(() => props.trailing);\n const items = createMemo<readonly TabOption<T>[]>(() => {\n if (props.options) return props.options;\n return collectTabsItems<T>(resolvedChildren.toArray()).map((item) => ({\n value: item.props.value,\n label: item.props.label,\n icon: item.props.icon,\n disabled: item.props.disabled,\n panel: item.props.children,\n onClose: item.props.onClose,\n closeLabel: item.props.closeLabel,\n }));\n });\n const buttons: HTMLButtonElement[] = [];\n let closing: T | undefined;\n const requestClose = (option: TabOption<T>) => {\n closing = option.value;\n option.onClose?.();\n };\n const current = () => resolveMaybeAccessor(props.value);\n const active = createMemo(() => items().find((option) => option.value === current()));\n const activeIndex = createMemo(() =>\n Math.max(\n 0,\n items().findIndex((option) => option.value === current()),\n ),\n );\n const enabled = () =>\n items()\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled);\n const tabStopIndex = createMemo(() => {\n const selected = items().findIndex((option) => option.value === current() && !option.disabled);\n return selected >= 0 ? selected : (enabled()[0]?.index ?? -1);\n });\n createEffect(() => {\n const index = activeIndex();\n const removed = closing !== undefined && !items().some((item) => item.value === closing);\n if (removed) closing = undefined;\n queueMicrotask(() => {\n buttons[index]?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" });\n if (removed) {\n const target = items().length ? buttons[index] : root?.querySelector<HTMLElement>(\".k2b-tabs__trailing button\");\n target?.focus();\n }\n });\n });\n const select = (index: number) => {\n const option = items()[index];\n if (!option || option.disabled) return;\n props.onValueChange(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const move = (index: number, delta: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const currentIndex = available.findIndex((item) => item.index === index);\n const next = available[(currentIndex + delta + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n\n return (\n <div\n ref={root}\n class={`k2b-tabs ${props.class ?? \"\"}`}\n data-orientation={props.orientation ?? \"horizontal\"}\n data-variant={props.variant ?? \"line\"}\n >\n <div class=\"k2b-tabs__bar\">\n <div\n ref={list}\n data-scroll-fade-mode={props.orientation !== \"vertical\" ? \"both\" : undefined}\n data-scroll-fade-axis=\"horizontal\"\n class=\"k2b-tabs__list\"\n role=\"tablist\"\n aria-label={props.ariaLabel}\n aria-orientation={props.orientation ?? \"horizontal\"}\n >\n <For each={items()}>\n {(option, index) => {\n const id = () => `${instanceId}-tab-${index()}`;\n const panelId = () => `${instanceId}-panel-${index()}`;\n return (\n <div class=\"k2b-tabs__item\" role=\"presentation\">\n <button\n ref={(element) => {\n buttons[index()] = element;\n }}\n id={id()}\n type=\"button\"\n role=\"tab\"\n aria-selected={current() === option.value}\n aria-controls={option.panel !== undefined ? panelId() : undefined}\n tabIndex={tabStopIndex() === index() ? 0 : -1}\n disabled={option.disabled}\n onClick={() => props.onValueChange(option.value)}\n onKeyDown={(event) => {\n if ((event.key === \"Delete\" || event.key === \"Backspace\") && option.onClose) {\n event.preventDefault();\n requestClose(option);\n return;\n }\n const previous = props.orientation === \"vertical\" ? \"ArrowUp\" : \"ArrowLeft\";\n const next = props.orientation === \"vertical\" ? \"ArrowDown\" : \"ArrowRight\";\n if (event.key === previous || event.key === next) {\n event.preventDefault();\n move(index(), event.key === next ? 1 : -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const available = enabled();\n const target = event.key === \"End\" ? available.at(-1) : available[0];\n if (target) select(target.index);\n }\n }}\n >\n <Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span>{option.label}</span>\n </button>\n <Show when={option.onClose}>\n <button\n type=\"button\"\n class=\"k2b-tabs__close\"\n aria-label={\n option.closeLabel ??\n messages().closeNamed({ name: typeof option.label === \"string\" ? option.label : props.ariaLabel })\n }\n disabled={option.disabled}\n onClick={() => requestClose(option)}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n );\n }}\n </For>\n </div>\n <Show when={trailing()}>\n <div class=\"k2b-tabs__trailing\">{trailing()}</div>\n </Show>\n </div>\n <Show when={active()?.panel !== undefined}>\n <div\n id={`${instanceId}-panel-${activeIndex()}`}\n class=\"k2b-tabs__panel\"\n role=\"tabpanel\"\n aria-labelledby={`${instanceId}-tab-${activeIndex()}`}\n tabIndex={0}\n >\n {active()?.panel}\n </div>\n </Show>\n </div>\n );\n}\n\nexport const Tabs = TabsRoot as TabsComponent;\nTabs.Item = TabsItem;\n\nexport default Tabs;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/Tabs.tsx"],"sourcesContent":["import { children, createEffect, createMemo, createUniqueId, For, type JSX, Show } from \"solid-js\";\nimport type { MaybeAccessor } from \"../inputs/field-contract\";\nimport { resolveMaybeAccessor } from \"../inputs/field-contract\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade } from \"../layout/scroll-fade\";\n\nexport type TabOption<T extends string = string> = {\n value: T;\n label: JSX.Element;\n icon?: string;\n disabled?: boolean;\n panel?: JSX.Element;\n onClose?: () => void;\n closeLabel?: string;\n};\n\nexport type TabsItemProps<T extends string = string> = Omit<TabOption<T>, \"panel\"> & {\n children?: JSX.Element;\n};\n\ntype TabsItemSlot<T extends string = string> = {\n readonly kind: typeof TABS_ITEM;\n readonly props: TabsItemProps<T>;\n};\n\nexport type TabsProps<T extends string = string> = {\n value: MaybeAccessor<T>;\n onValueChange: (value: T) => void;\n ariaLabel: string;\n orientation?: \"horizontal\" | \"vertical\";\n class?: string;\n variant?: \"line\" | \"pill\";\n trailing?: JSX.Element;\n /** Data-driven alternative to colocated `Tabs.Item` children. */\n options?: readonly TabOption<T>[];\n children?: JSX.Element;\n};\n\ntype TabsComponent = (<T extends string = string>(props: TabsProps<T>) => JSX.Element) & {\n Item: <T extends string = string>(props: TabsItemProps<T>) => JSX.Element;\n};\n\nconst TABS_ITEM = Symbol(\"Tabs.Item\");\n\nconst isTabsItem = <T extends string>(value: unknown): value is TabsItemSlot<T> =>\n !!value && typeof value === \"object\" && \"kind\" in value && value.kind === TABS_ITEM;\n\nconst collectTabsItems = <T extends string>(value: unknown): TabsItemSlot<T>[] => {\n if (Array.isArray(value)) return value.flatMap(collectTabsItems<T>);\n return isTabsItem<T>(value) ? [value] : [];\n};\n\nfunction TabsItem<T extends string = string>(props: TabsItemProps<T>): JSX.Element {\n return { kind: TABS_ITEM, props } satisfies TabsItemSlot<T> as unknown as JSX.Element;\n}\n\n/** Controlled, keyboard-accessible tabs with compositional or data-driven items. */\nfunction TabsRoot<T extends string = string>(props: TabsProps<T>): JSX.Element {\n const messages = useUiMessages();\n let root: HTMLDivElement | undefined;\n let list: HTMLDivElement | undefined;\n createScrollFade(\n () => list,\n () => props.orientation !== \"vertical\",\n );\n const instanceId = `k2b-tabs-${createUniqueId()}`;\n const resolvedChildren = children(() => props.children);\n const trailing = children(() => props.trailing);\n const items = createMemo<readonly TabOption<T>[]>(() => {\n if (props.options) return props.options;\n return collectTabsItems<T>(resolvedChildren.toArray()).map((item) => ({\n value: item.props.value,\n label: item.props.label,\n icon: item.props.icon,\n disabled: item.props.disabled,\n panel: item.props.children,\n onClose: item.props.onClose,\n closeLabel: item.props.closeLabel,\n }));\n });\n const buttons: HTMLButtonElement[] = [];\n let closing: T | undefined;\n const requestClose = (option: TabOption<T>) => {\n closing = option.value;\n option.onClose?.();\n };\n const current = () => resolveMaybeAccessor(props.value);\n const active = createMemo(() => items().find((option) => option.value === current()));\n const activeIndex = createMemo(() =>\n Math.max(\n 0,\n items().findIndex((option) => option.value === current()),\n ),\n );\n const enabled = () =>\n items()\n .map((option, index) => ({ option, index }))\n .filter(({ option }) => !option.disabled);\n const tabStopIndex = createMemo(() => {\n const selected = items().findIndex((option) => option.value === current() && !option.disabled);\n return selected >= 0 ? selected : (enabled()[0]?.index ?? -1);\n });\n createEffect(() => {\n const index = activeIndex();\n const removed = closing !== undefined && !items().some((item) => item.value === closing);\n if (removed) closing = undefined;\n queueMicrotask(() => {\n buttons[index]?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" });\n if (removed) {\n const target = items().length ? buttons[index] : root?.querySelector<HTMLElement>(\".k2b-tabs__trailing button\");\n target?.focus();\n }\n });\n });\n const select = (index: number) => {\n const option = items()[index];\n if (!option || option.disabled) return;\n props.onValueChange(option.value);\n queueMicrotask(() => buttons[index]?.focus());\n };\n const move = (index: number, delta: 1 | -1) => {\n const available = enabled();\n if (available.length === 0) return;\n const currentIndex = available.findIndex((item) => item.index === index);\n const next = available[(currentIndex + delta + available.length) % available.length] ?? available[0];\n if (next) select(next.index);\n };\n\n return (\n <div\n ref={root}\n class={`k2b-tabs ${props.class ?? \"\"}`}\n data-orientation={props.orientation ?? \"horizontal\"}\n data-variant={props.variant ?? \"line\"}\n >\n <div class=\"k2b-tabs__bar\">\n <div\n ref={list}\n data-scroll-fade-mode={props.orientation !== \"vertical\" ? \"both\" : undefined}\n data-scroll-fade-axis=\"horizontal\"\n class=\"k2b-tabs__list\"\n role=\"tablist\"\n aria-label={props.ariaLabel}\n aria-orientation={props.orientation ?? \"horizontal\"}\n >\n <For each={items()}>\n {(option, index) => {\n const id = () => `${instanceId}-tab-${index()}`;\n const panelId = () => `${instanceId}-panel-${index()}`;\n return (\n <div class=\"k2b-tabs__item\" role=\"presentation\">\n <button\n ref={(element) => {\n buttons[index()] = element;\n }}\n id={id()}\n type=\"button\"\n role=\"tab\"\n aria-selected={current() === option.value}\n aria-controls={option.panel !== undefined ? panelId() : undefined}\n tabIndex={tabStopIndex() === index() ? 0 : -1}\n disabled={option.disabled}\n onClick={() => props.onValueChange(option.value)}\n onKeyDown={(event) => {\n if ((event.key === \"Delete\" || event.key === \"Backspace\") && option.onClose) {\n event.preventDefault();\n requestClose(option);\n return;\n }\n const previous = props.orientation === \"vertical\" ? \"ArrowUp\" : \"ArrowLeft\";\n const next = props.orientation === \"vertical\" ? \"ArrowDown\" : \"ArrowRight\";\n if (event.key === previous || event.key === next) {\n event.preventDefault();\n move(index(), event.key === next ? 1 : -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const available = enabled();\n const target = event.key === \"End\" ? available.at(-1) : available[0];\n if (target) select(target.index);\n }\n }}\n >\n <Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class={props.variant === \"pill\" ? \"k2b-truncate-fade\" : undefined}>{option.label}</span>\n </button>\n <Show when={option.onClose}>\n <button\n type=\"button\"\n class=\"k2b-tabs__close\"\n aria-label={\n option.closeLabel ??\n messages().closeNamed({ name: typeof option.label === \"string\" ? option.label : props.ariaLabel })\n }\n disabled={option.disabled}\n onClick={() => requestClose(option)}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n );\n }}\n </For>\n </div>\n <Show when={trailing()}>\n <div class=\"k2b-tabs__trailing\">{trailing()}</div>\n </Show>\n </div>\n <Show when={active()?.panel !== undefined}>\n <div\n id={`${instanceId}-panel-${activeIndex()}`}\n class=\"k2b-tabs__panel\"\n role=\"tabpanel\"\n aria-labelledby={`${instanceId}-tab-${activeIndex()}`}\n tabIndex={0}\n >\n {active()?.panel}\n </div>\n </Show>\n </div>\n );\n}\n\nexport const Tabs = TabsRoot as TabsComponent;\nTabs.Item = TabsItem;\n\nexport default Tabs;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
2
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
|
+
import { ssr as _$ssr } from "solid-js/web";
|
|
4
|
+
import { escape as _$escape } from "solid-js/web";
|
|
5
|
+
var _tmpl$ = ["<span class=\"k2b-view-tabs__count\">", "</span>"],
|
|
6
|
+
_tmpl$2 = ["<span class=\"k2b-view-tabs__label k2b-truncate-fade\">", "</span>"],
|
|
7
|
+
_tmpl$3 = ["<i", " aria-hidden=\"true\"></i>"],
|
|
8
|
+
_tmpl$4 = ["<span class=\"k2b-view-tabs__label\">", "</span>"],
|
|
9
|
+
_tmpl$5 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">+", "</span>"],
|
|
10
|
+
_tmpl$6 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">+", "</span>"],
|
|
11
|
+
_tmpl$7 = "<i class=\"ti ti-chevron-down\" aria-hidden=\"true\"></i>",
|
|
12
|
+
_tmpl$8 = ["<li class=\"k2b-view-tabs__more\"", ">", "</li>"],
|
|
13
|
+
_tmpl$9 = ["<nav class=\"", "\"", "><ul class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">", "", "</ul><script>", "</script></nav>"],
|
|
14
|
+
_tmpl$0 = ["<li class=\"k2b-view-tabs__item\"", "><a class=\"k2b-view-tabs__tab\"", ">", "</a></li>"];
|
|
15
|
+
import { createEffect, createMemo, createSignal, For, on, onCleanup, onMount, Show } from "solid-js";
|
|
16
|
+
import { useUiMessages } from "../intl/messages";
|
|
17
|
+
import { createScrollFade, scrollFadeEdges } from "../layout/scroll-fade";
|
|
18
|
+
import Dropdown from "./Dropdown";
|
|
19
|
+
/** Two deterministic strip levels; only opening the menu reads CSS visibility. */
|
|
20
|
+
export function viewTabsLayout(items, current, max = 5) {
|
|
21
|
+
// At least one slot keeps the current view visible, including for an invalid limit.
|
|
22
|
+
const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;
|
|
23
|
+
const currentIndex = items.findIndex(item => item.id === current);
|
|
24
|
+
const visible = size => {
|
|
25
|
+
const indices = items.slice(0, size).map((_, index) => index);
|
|
26
|
+
if (currentIndex >= size) indices[indices.length - 1] = currentIndex;
|
|
27
|
+
return indices;
|
|
28
|
+
};
|
|
29
|
+
const wide = visible(limit);
|
|
30
|
+
const compact = visible(Math.min(limit, 3));
|
|
31
|
+
return {
|
|
32
|
+
wide,
|
|
33
|
+
compact,
|
|
34
|
+
wideHidden: items.length - wide.length,
|
|
35
|
+
compactHidden: items.length - compact.length
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Self-contained: the server script embeds this before hydration. */
|
|
40
|
+
function settleViewTabs(list, edges, focused) {
|
|
41
|
+
if (!(list instanceof HTMLElement)) return;
|
|
42
|
+
const current = focused ?? list.querySelector(".k2b-view-tabs__tab[aria-current=page]");
|
|
43
|
+
if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {
|
|
44
|
+
const bounds = list.getBoundingClientRect();
|
|
45
|
+
const item = current.getBoundingClientRect();
|
|
46
|
+
const fade = edges(list);
|
|
47
|
+
const style = getComputedStyle(list);
|
|
48
|
+
const left = fade === "top" || fade === "both" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;
|
|
49
|
+
const right = fade === "bottom" || fade === "both" ? parseFloat(style.scrollPaddingRight) || 0 : 0;
|
|
50
|
+
if (item.left < bounds.left + left || item.right > bounds.right - right) {
|
|
51
|
+
let offset = item.left - bounds.left - (bounds.width - item.width) / 2;
|
|
52
|
+
if (focused) {
|
|
53
|
+
// Reserve padding at the destination edge; native clamping drops it when that end is reached.
|
|
54
|
+
offset = item.left < bounds.left + left ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0) : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);
|
|
55
|
+
}
|
|
56
|
+
// Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.
|
|
57
|
+
list.scrollTo({
|
|
58
|
+
left: list.scrollLeft + offset,
|
|
59
|
+
behavior: "instant"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const fade = edges(list);
|
|
64
|
+
if (fade) list.setAttribute("data-scroll-fade", fade);else list.removeAttribute("data-scroll-fade");
|
|
65
|
+
}
|
|
66
|
+
/** Also embedded, so it must not close over module state. */
|
|
67
|
+
function watchViewTabs(list, settle, edges) {
|
|
68
|
+
if (!(list instanceof HTMLElement)) return;
|
|
69
|
+
// A DOM property survives hydration: one observer and focus listener per reused list.
|
|
70
|
+
let watch = list.__k2bViewTabsWatch;
|
|
71
|
+
if (!watch) {
|
|
72
|
+
const focus = event => {
|
|
73
|
+
// Pointer focus must not move the target under the pointer.
|
|
74
|
+
if (watch && event.target instanceof HTMLElement && event.target.matches(".k2b-view-tabs__tab:focus-visible")) {
|
|
75
|
+
watch.preferCurrent = false;
|
|
76
|
+
settle(list, edges, event.target);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
watch = {
|
|
80
|
+
resize: new ResizeObserver(() => {
|
|
81
|
+
const focused = document.activeElement;
|
|
82
|
+
if (watch?.preferCurrent === false && focused instanceof HTMLElement && list.contains(focused) && focused.matches(".k2b-view-tabs__tab:focus-visible")) settle(list, edges, focused);else settle(list, edges);
|
|
83
|
+
}),
|
|
84
|
+
focus,
|
|
85
|
+
preferCurrent: true
|
|
86
|
+
};
|
|
87
|
+
Object.defineProperty(list, "__k2bViewTabsWatch", {
|
|
88
|
+
value: watch,
|
|
89
|
+
configurable: true
|
|
90
|
+
});
|
|
91
|
+
list.addEventListener("focusin", focus);
|
|
92
|
+
}
|
|
93
|
+
watch.preferCurrent = true;
|
|
94
|
+
const {
|
|
95
|
+
resize
|
|
96
|
+
} = watch;
|
|
97
|
+
resize.disconnect();
|
|
98
|
+
// Head actions parse after the views; settle again after their layout, before paint, and on later resizes.
|
|
99
|
+
resize.observe(list);
|
|
100
|
+
for (const child of Array.from(list.children)) resize.observe(child);
|
|
101
|
+
settle(list, edges);
|
|
102
|
+
return watch;
|
|
103
|
+
}
|
|
104
|
+
const VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,
|
|
108
|
+
* and forward keep the view the URL names.
|
|
109
|
+
*/
|
|
110
|
+
export function ViewTabs(props) {
|
|
111
|
+
const messages = useUiMessages();
|
|
112
|
+
const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));
|
|
113
|
+
const stripItems = new Map();
|
|
114
|
+
let list;
|
|
115
|
+
createScrollFade(() => list, () => true);
|
|
116
|
+
onMount(() => {
|
|
117
|
+
const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);
|
|
118
|
+
onCleanup(() => {
|
|
119
|
+
watch?.resize.disconnect();
|
|
120
|
+
if (list && watch) {
|
|
121
|
+
list.removeEventListener("focusin", watch.focus);
|
|
122
|
+
Reflect.deleteProperty(list, "__k2bViewTabsWatch");
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
// User effects run after Solid's render effects, including For and aria-current, in the same task.
|
|
127
|
+
createEffect(on(() => props.current, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), {
|
|
128
|
+
defer: true
|
|
129
|
+
}));
|
|
130
|
+
const [open, setOpen] = createSignal(false);
|
|
131
|
+
const [menuItems, setMenuItems] = createSignal([]);
|
|
132
|
+
const onOpenChange = next => {
|
|
133
|
+
if (next) {
|
|
134
|
+
setMenuItems(props.items.filter((item, index) => item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0)).map(item => ({
|
|
135
|
+
href: item.href,
|
|
136
|
+
label: item.label,
|
|
137
|
+
icon: item.icon,
|
|
138
|
+
trailing: item.count !== undefined ? _$ssr(_tmpl$, _$escape(item.count)) : undefined
|
|
139
|
+
})));
|
|
140
|
+
}
|
|
141
|
+
setOpen(next);
|
|
142
|
+
};
|
|
143
|
+
const tabContent = item => [_$createComponent(Show, {
|
|
144
|
+
get when() {
|
|
145
|
+
return item.icon;
|
|
146
|
+
},
|
|
147
|
+
children: icon => _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(icon(), true), false))
|
|
148
|
+
}), _$ssr(_tmpl$2, _$escape(item.label)), _$createComponent(Show, {
|
|
149
|
+
get when() {
|
|
150
|
+
return item.count !== undefined;
|
|
151
|
+
},
|
|
152
|
+
get children() {
|
|
153
|
+
return _$ssr(_tmpl$, _$escape(item.count));
|
|
154
|
+
}
|
|
155
|
+
})];
|
|
156
|
+
return _$ssr(_tmpl$9, `k2b-view-tabs ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(_$createComponent(For, {
|
|
157
|
+
get each() {
|
|
158
|
+
return layout().wide;
|
|
159
|
+
},
|
|
160
|
+
children: index => {
|
|
161
|
+
const item = () => props.items[index];
|
|
162
|
+
onCleanup(() => stripItems.delete(index));
|
|
163
|
+
return _$ssr(_tmpl$0, _$ssrAttribute("data-view-tab", _$escape(item().id, true), false) + _$ssrAttribute("data-compact-hidden", !layout().compact.includes(index) ? "" : _$escape(undefined, true), false), _$ssrAttribute("href", _$escape(item().href, true), false) + _$ssrAttribute("aria-current", item().id === props.current ? "page" : _$escape(undefined, true), false), _$escape(tabContent(item())));
|
|
164
|
+
}
|
|
165
|
+
})), _$escape(_$createComponent(Show, {
|
|
166
|
+
get when() {
|
|
167
|
+
return layout().compactHidden + layout().wideHidden > 0;
|
|
168
|
+
},
|
|
169
|
+
get children() {
|
|
170
|
+
return _$ssr(_tmpl$8, _$ssrAttribute("data-wide", layout().wideHidden > 0 ? "" : _$escape(undefined, true), false), _$escape(_$createComponent(Dropdown.Root, {
|
|
171
|
+
get items() {
|
|
172
|
+
return menuItems();
|
|
173
|
+
},
|
|
174
|
+
get open() {
|
|
175
|
+
return open();
|
|
176
|
+
},
|
|
177
|
+
onOpenChange: onOpenChange,
|
|
178
|
+
get label() {
|
|
179
|
+
return messages().moreViews;
|
|
180
|
+
},
|
|
181
|
+
get children() {
|
|
182
|
+
return _$createComponent(Dropdown.Trigger, {
|
|
183
|
+
appearance: "plain",
|
|
184
|
+
"class": "k2b-view-tabs__tab k2b-view-tabs__more-trigger",
|
|
185
|
+
get label() {
|
|
186
|
+
return messages().moreViews;
|
|
187
|
+
},
|
|
188
|
+
get children() {
|
|
189
|
+
return [_$ssr(_tmpl$4, _$escape(messages().more)), _$createComponent(Show, {
|
|
190
|
+
get when() {
|
|
191
|
+
return layout().wideHidden > 0;
|
|
192
|
+
},
|
|
193
|
+
get children() {
|
|
194
|
+
return _$ssr(_tmpl$5, _$escape(layout().wideHidden));
|
|
195
|
+
}
|
|
196
|
+
}), _$createComponent(Show, {
|
|
197
|
+
get when() {
|
|
198
|
+
return layout().compactHidden > 0;
|
|
199
|
+
},
|
|
200
|
+
get children() {
|
|
201
|
+
return _$ssr(_tmpl$6, _$escape(layout().compactHidden));
|
|
202
|
+
}
|
|
203
|
+
}), _$ssr(_tmpl$7)];
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
})));
|
|
208
|
+
}
|
|
209
|
+
})), VIEW_TABS_SCRIPT);
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=ViewTabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/ViewTabs.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade, scrollFadeEdges } from \"../layout/scroll-fade\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\n\nexport type ViewTab = { id: string; label: string; href: string; icon?: string; count?: number | string };\nexport type ViewTabsProps = {\n /** Accessible name of the navigation landmark, e.g. \"Views\". */\n label: string;\n items: readonly ViewTab[];\n /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */\n current: string | undefined;\n /** Tabs shown before More (default 5). */\n max?: number;\n class?: string;\n};\n\n/** Two deterministic strip levels; only opening the menu reads CSS visibility. */\nexport function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max = 5) {\n // At least one slot keeps the current view visible, including for an invalid limit.\n const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;\n const currentIndex = items.findIndex((item) => item.id === current);\n const visible = (size: number) => {\n const indices = items.slice(0, size).map((_, index) => index);\n if (currentIndex >= size) indices[indices.length - 1] = currentIndex;\n return indices;\n };\n const wide = visible(limit);\n const compact = visible(Math.min(limit, 3));\n return { wide, compact, wideHidden: items.length - wide.length, compactHidden: items.length - compact.length };\n}\n\n/** Self-contained: the server script embeds this before hydration. */\nfunction settleViewTabs(list: Element | null, edges: (element: HTMLElement) => string | undefined, focused?: HTMLElement) {\n if (!(list instanceof HTMLElement)) return;\n const current = focused ?? list.querySelector(\".k2b-view-tabs__tab[aria-current=page]\");\n if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {\n const bounds = list.getBoundingClientRect();\n const item = current.getBoundingClientRect();\n const fade = edges(list);\n const style = getComputedStyle(list);\n const left = fade === \"top\" || fade === \"both\" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;\n const right = fade === \"bottom\" || fade === \"both\" ? parseFloat(style.scrollPaddingRight) || 0 : 0;\n if (item.left < bounds.left + left || item.right > bounds.right - right) {\n let offset = item.left - bounds.left - (bounds.width - item.width) / 2;\n if (focused) {\n // Reserve padding at the destination edge; native clamping drops it when that end is reached.\n offset =\n item.left < bounds.left + left\n ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0)\n : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);\n }\n // Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.\n list.scrollTo({ left: list.scrollLeft + offset, behavior: \"instant\" });\n }\n }\n const fade = edges(list);\n if (fade) list.setAttribute(\"data-scroll-fade\", fade);\n else list.removeAttribute(\"data-scroll-fade\");\n}\n\ntype WatchedViewTabs = HTMLElement & {\n __k2bViewTabsWatch?: { resize: ResizeObserver; focus: (event: FocusEvent) => void; preferCurrent: boolean };\n};\n\n/** Also embedded, so it must not close over module state. */\nfunction watchViewTabs(list: WatchedViewTabs | null, settle: typeof settleViewTabs, edges: (element: HTMLElement) => string | undefined) {\n if (!(list instanceof HTMLElement)) return;\n // A DOM property survives hydration: one observer and focus listener per reused list.\n let watch = list.__k2bViewTabsWatch;\n if (!watch) {\n const focus = (event: FocusEvent) => {\n // Pointer focus must not move the target under the pointer.\n if (watch && event.target instanceof HTMLElement && event.target.matches(\".k2b-view-tabs__tab:focus-visible\")) {\n watch.preferCurrent = false;\n settle(list, edges, event.target);\n }\n };\n watch = {\n resize: new ResizeObserver(() => {\n const focused = document.activeElement;\n if (\n watch?.preferCurrent === false &&\n focused instanceof HTMLElement &&\n list.contains(focused) &&\n focused.matches(\".k2b-view-tabs__tab:focus-visible\")\n )\n settle(list, edges, focused);\n else settle(list, edges);\n }),\n focus,\n preferCurrent: true,\n };\n Object.defineProperty(list, \"__k2bViewTabsWatch\", { value: watch, configurable: true });\n list.addEventListener(\"focusin\", focus);\n }\n watch.preferCurrent = true;\n const { resize } = watch;\n resize.disconnect();\n // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.\n resize.observe(list);\n for (const child of Array.from(list.children)) resize.observe(child);\n settle(list, edges);\n return watch;\n}\nconst VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;\n\n/**\n * URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,\n * and forward keep the view the URL names.\n */\nexport function ViewTabs(props: ViewTabsProps): JSX.Element {\n const messages = useUiMessages();\n const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));\n const stripItems = new Map<number, HTMLLIElement>();\n let list: HTMLUListElement | undefined;\n createScrollFade(\n () => list,\n () => true,\n );\n onMount(() => {\n const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);\n onCleanup(() => {\n watch?.resize.disconnect();\n if (list && watch) {\n list.removeEventListener(\"focusin\", watch.focus);\n Reflect.deleteProperty(list, \"__k2bViewTabsWatch\");\n }\n });\n });\n // User effects run after Solid's render effects, including For and aria-current, in the same task.\n createEffect(\n on(\n () => props.current,\n () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges),\n { defer: true },\n ),\n );\n const [open, setOpen] = createSignal(false);\n const [menuItems, setMenuItems] = createSignal<DropdownItem[]>([]);\n const onOpenChange = (next: boolean) => {\n if (next) {\n setMenuItems(\n props.items\n .filter(\n (item, index) =>\n item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0),\n )\n .map((item) => ({\n href: item.href,\n label: item.label,\n icon: item.icon,\n trailing: item.count !== undefined ? <span class=\"k2b-view-tabs__count\">{item.count}</span> : undefined,\n })),\n );\n }\n setOpen(next);\n };\n const tabContent = (item: ViewTab) => (\n <>\n <Show when={item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-view-tabs__label k2b-truncate-fade\">{item.label}</span>\n <Show when={item.count !== undefined}>\n <span class=\"k2b-view-tabs__count\">{item.count}</span>\n </Show>\n </>\n );\n return (\n <nav class={`k2b-view-tabs ${props.class ?? \"\"}`} aria-label={props.label}>\n <ul ref={list} class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">\n <For each={layout().wide}>\n {(index) => {\n const item = () => props.items[index]!;\n onCleanup(() => stripItems.delete(index));\n return (\n <li\n ref={(element) => stripItems.set(index, element)}\n class=\"k2b-view-tabs__item\"\n data-view-tab={item().id}\n data-compact-hidden={!layout().compact.includes(index) ? \"\" : undefined}\n >\n <a class=\"k2b-view-tabs__tab\" href={item().href} aria-current={item().id === props.current ? \"page\" : undefined}>\n {tabContent(item())}\n </a>\n </li>\n );\n }}\n </For>\n <Show when={layout().compactHidden + layout().wideHidden > 0}>\n <li class=\"k2b-view-tabs__more\" data-wide={layout().wideHidden > 0 ? \"\" : undefined}>\n <Dropdown.Root items={menuItems()} open={open()} onOpenChange={onOpenChange} label={messages().moreViews}>\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-view-tabs__tab k2b-view-tabs__more-trigger\" label={messages().moreViews}>\n <span class=\"k2b-view-tabs__label\">{messages().more}</span>\n <Show when={layout().wideHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">\n +{layout().wideHidden}\n </span>\n </Show>\n <Show when={layout().compactHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">\n +{layout().compactHidden}\n </span>\n </Show>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </li>\n </Show>\n </ul>\n <script innerHTML={VIEW_TABS_SCRIPT} />\n </nav>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|