@k2b/ui 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/actions/Button.js +15 -7
- package/dist/browser/actions/Button.js.map +1 -1
- package/dist/browser/actions/ContextMenu.js +55 -15
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +39 -15
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +1 -7
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/SplitButton.js +0 -3
- package/dist/browser/actions/SplitButton.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +78 -91
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/ChatContextPopup.js +47 -21
- package/dist/browser/chat/ChatContextPopup.js.map +1 -1
- package/dist/browser/chat/ChatPrimitives.js +221 -232
- package/dist/browser/chat/ChatPrimitives.js.map +1 -1
- package/dist/browser/chat/index.js +3 -2
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/content/Chart.js +99 -106
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartExplorer.js +3 -6
- package/dist/browser/content/ChartExplorer.js.map +1 -1
- package/dist/browser/content/FileBrowser.js +1 -1
- package/dist/browser/content/FileBrowser.js.map +1 -1
- package/dist/browser/content/FileTree.js +1 -1
- package/dist/browser/content/FileTree.js.map +1 -1
- package/dist/browser/content/FileView.js +304 -287
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/Lightbox.js +18 -0
- package/dist/browser/content/Lightbox.js.map +1 -1
- package/dist/browser/content/MarkdownView.js +8 -1
- package/dist/browser/content/MarkdownView.js.map +1 -1
- package/dist/browser/content/PdfPreview.js +68 -43
- package/dist/browser/content/PdfPreview.js.map +1 -1
- package/dist/browser/content/ZoomPanViewport.js +51 -52
- package/dist/browser/content/ZoomPanViewport.js.map +1 -1
- package/dist/browser/feedback/HoverPreview.js +391 -0
- package/dist/browser/feedback/HoverPreview.js.map +1 -0
- package/dist/browser/feedback/Tooltip.js +50 -8
- package/dist/browser/feedback/Tooltip.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +21 -3
- 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/inputs/AutocompleteEditor.js +5 -4
- package/dist/browser/inputs/AutocompleteEditor.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +10 -0
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/FileInputs.js +46 -36
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SelectChip.js +2 -1
- package/dist/browser/inputs/SelectChip.js.map +1 -1
- package/dist/browser/inputs/choice.js +5 -1
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/markdown/MarkdownEditor.js +173 -173
- package/dist/browser/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/browser/inputs/markdown/Toolbar.js +31 -34
- package/dist/browser/inputs/markdown/Toolbar.js.map +1 -1
- package/dist/browser/internal/focus-return.js +61 -0
- package/dist/browser/internal/focus-return.js.map +1 -0
- package/dist/browser/layout/AppOverview.js +1 -1
- package/dist/browser/layout/AppOverview.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +16 -15
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/FloatingWindow.js +3 -1
- package/dist/browser/layout/FloatingWindow.js.map +1 -1
- package/dist/browser/layout/PanelDialog.js +10 -9
- package/dist/browser/layout/PanelDialog.js.map +1 -1
- package/dist/browser/layout/Panes.js +82 -81
- package/dist/browser/layout/Panes.js.map +1 -1
- package/dist/browser/layout/SidebarItemPreview.js +48 -136
- package/dist/browser/layout/SidebarItemPreview.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +5 -2
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/surfaces/ProgressBar.js.map +1 -1
- package/dist/browser/surfaces/ProgressRing.js +72 -0
- package/dist/browser/surfaces/ProgressRing.js.map +1 -0
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/ssr/actions/Button.js +15 -7
- package/dist/ssr/actions/Button.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +55 -15
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +31 -12
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +1 -7
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/SplitButton.js +0 -3
- package/dist/ssr/actions/SplitButton.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +61 -10
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/ChatContextPopup.js +19 -5
- package/dist/ssr/chat/ChatContextPopup.js.map +1 -1
- package/dist/ssr/chat/ChatPrimitives.js +104 -74
- package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
- package/dist/ssr/chat/index.js +3 -2
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/content/Chart.js +22 -11
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartExplorer.js +3 -6
- package/dist/ssr/content/ChartExplorer.js.map +1 -1
- package/dist/ssr/content/FileBrowser.js +1 -1
- package/dist/ssr/content/FileBrowser.js.map +1 -1
- package/dist/ssr/content/FileTree.js +1 -1
- package/dist/ssr/content/FileTree.js.map +1 -1
- package/dist/ssr/content/FileView.js +105 -33
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/Lightbox.js +17 -0
- package/dist/ssr/content/Lightbox.js.map +1 -1
- package/dist/ssr/content/MarkdownView.js +8 -1
- package/dist/ssr/content/MarkdownView.js.map +1 -1
- package/dist/ssr/content/PdfPreview.js +44 -14
- package/dist/ssr/content/PdfPreview.js.map +1 -1
- package/dist/ssr/content/ZoomPanViewport.js +11 -3
- package/dist/ssr/content/ZoomPanViewport.js.map +1 -1
- package/dist/ssr/feedback/HoverPreview.js +360 -0
- package/dist/ssr/feedback/HoverPreview.js.map +1 -0
- package/dist/ssr/feedback/Tooltip.js +50 -8
- package/dist/ssr/feedback/Tooltip.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +21 -3
- 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/inputs/AutocompleteEditor.js +5 -4
- package/dist/ssr/inputs/AutocompleteEditor.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +5 -0
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/FileInputs.js +29 -11
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SelectChip.js +2 -1
- package/dist/ssr/inputs/SelectChip.js.map +1 -1
- package/dist/ssr/inputs/choice.js +5 -1
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/markdown/MarkdownEditor.js +46 -10
- package/dist/ssr/inputs/markdown/MarkdownEditor.js.map +1 -1
- package/dist/ssr/inputs/markdown/Toolbar.js +30 -2
- package/dist/ssr/inputs/markdown/Toolbar.js.map +1 -1
- package/dist/ssr/internal/focus-return.js +61 -0
- package/dist/ssr/internal/focus-return.js.map +1 -0
- package/dist/ssr/layout/AppOverview.js +1 -1
- package/dist/ssr/layout/AppOverview.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +16 -15
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/FloatingWindow.js +3 -1
- package/dist/ssr/layout/FloatingWindow.js.map +1 -1
- package/dist/ssr/layout/PanelDialog.js +10 -9
- package/dist/ssr/layout/PanelDialog.js.map +1 -1
- package/dist/ssr/layout/Panes.js +39 -8
- package/dist/ssr/layout/Panes.js.map +1 -1
- package/dist/ssr/layout/SidebarItemPreview.js +36 -108
- package/dist/ssr/layout/SidebarItemPreview.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +5 -2
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/surfaces/ProgressBar.js.map +1 -1
- package/dist/ssr/surfaces/ProgressRing.js +31 -0
- package/dist/ssr/surfaces/ProgressRing.js.map +1 -0
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tabler-icons-15sezdfp.woff2 +0 -0
- package/dist/tabler.css +2 -2
- package/dist/types/actions/Button.d.ts +5 -0
- package/dist/types/actions/Dropdown.d.ts +5 -1
- package/dist/types/actions/SplitButton.d.ts +1 -0
- package/dist/types/chat/ChatContextPopup.d.ts +8 -0
- package/dist/types/chat/index.d.ts +3 -2
- package/dist/types/feedback/HoverPreview.d.ts +83 -0
- package/dist/types/feedback/Tooltip.d.ts +6 -0
- package/dist/types/feedback/index.d.ts +2 -0
- package/dist/types/feedback/prompts.d.ts +9 -6
- package/dist/types/inputs/SelectChip.d.ts +1 -0
- package/dist/types/inputs/completion/overlay.d.ts +3 -1
- package/dist/types/internal/focus-return.d.ts +20 -0
- package/dist/types/intl/Format.d.ts +16 -8
- package/dist/types/layout/BottomSheet.d.ts +6 -1
- package/dist/types/layout/SidebarItemPreview.d.ts +1 -1
- package/dist/types/surfaces/ProgressBar.d.ts +1 -1
- package/dist/types/surfaces/ProgressRing.d.ts +13 -0
- package/dist/types/surfaces/index.d.ts +2 -0
- package/package.json +9 -8
- package/dist/tabler-icons-q30jt7jk.woff2 +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["feedback/HoverPreview.tsx"],"sourcesContent":["import { type Accessor, createEffect, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { positionTooltipSurface } from \"./tooltip-position\";\n\n/** A resting pointer moving from one anchor to another swaps the card this fast. */\nconst SWAP_DELAY = 90;\n/** Grace period for the pointer to travel from an anchor into the card. */\nconst CLOSE_DELAY = 180;\n/** Distance to the region and to the boundary edges. */\nconst GAP = 8;\n/** Keys the wiring between a controller and its `<HoverPreview>`. */\nconst INTERNALS = Symbol(\"k2b-hover-preview\");\n\n/**\n * Where the card opens. By default it opens to the right of its anchor,\n * centered on it or aligned with its bottom edge, and flips or clamps to stay\n * in the viewport. With `beside`, it opens right of that region, such as a list\n * column, top-aligned with the anchor and clamped into `within` (default: the\n * viewport); when the card does not fit there, it does not open at all.\n */\nexport type HoverPreviewPlacement =\n | { align?: \"center\" | \"end\" }\n | { beside: () => HTMLElement | null | undefined; within?: () => HTMLElement | null | undefined };\n\nexport type HoverPreviewOptions<T> = {\n /** Milliseconds a resting mouse waits on an anchor before the card opens. Defaults to 250. */\n openDelay?: number;\n /**\n * How keyboard users open the card: `\"space\"` (default) toggles it with Space\n * on the focused anchor and leaves focus there; `\"focus\"` opens it after the\n * open delay whenever an anchor receives focus.\n */\n keyboard?: \"space\" | \"focus\";\n placement?: HoverPreviewPlacement;\n /** Anchors whose value is disabled open no card; an open card closes once its value becomes disabled. */\n disabled?: (value: T) => boolean;\n /** Runs whenever the card opens or closes, including light dismissal by the browser. */\n onOpenChange?: (open: boolean) => void;\n};\n\nexport type HoverPreviewController<T> = {\n /** Id of the card element, for `aria-controls`. */\n readonly id: string;\n /**\n * Registers an anchor element for `value`; use the result as a `ref`.\n * `trigger` is the control that toggles the card for this anchor; Escape\n * returns focus there when focus is inside the card. Defaults to the anchor.\n */\n anchor: (value: T, trigger?: () => HTMLElement | null | undefined) => (element: HTMLElement) => void;\n /** The value whose card is open, or `undefined` while closed. */\n active: Accessor<T | undefined>;\n /** Opens the card for `value` at once and moves focus into it, or closes it when it is already pinned open. */\n toggle: (value: T) => void;\n /** Closes the card; it reopens for the same anchor only after the pointer left it. */\n close: () => void;\n /** Wiring for `<HoverPreview>`; not part of the public contract. */\n readonly [INTERNALS]: Internals<T>;\n};\n\ntype Anchor<T> = { value: T; element: HTMLElement; trigger?: () => HTMLElement | null | undefined };\n\ntype Internals<T> = {\n current: Accessor<Anchor<T> | undefined>;\n bind: (surface: HTMLElement) => void;\n enterSurface: () => void;\n leave: () => void;\n focusOut: (event: FocusEvent) => void;\n toggled: (open: boolean) => void;\n};\n\n/** Elements that use Space themselves; Space on them never toggles the card. */\nconst OWNS_SPACE = [\n \"button, input, select, textarea, summary, [contenteditable]:not([contenteditable='false'])\",\n ...[\"button\", \"checkbox\", \"switch\", \"radio\", \"option\", \"menuitem\", \"menuitemcheckbox\", \"menuitemradio\", \"tab\", \"treeitem\"].map(\n (role) => `[role='${role}']`,\n ),\n].join(\", \");\n\n/** Open light-dismiss popovers, such as a menu or a date picker, close when another one opens. */\nconst AUTO_POPOVER = \":is([popover=''], [popover='auto' i]):popover-open\";\n\n/**\n * Creates the behavior of one hover preview card shared by a group of anchors,\n * such as the rows of a list. Render the card with `<HoverPreview preview={…}>`.\n */\nexport function createHoverPreview<T>(options: HoverPreviewOptions<T> = {}): HoverPreviewController<T> {\n const id = `k2b-hover-preview-${createUniqueId()}`;\n const anchors = new Set<Anchor<T>>();\n const [current, setCurrent] = createSignal<Anchor<T>>();\n const [open, setOpen] = createSignal(false);\n let surface: HTMLElement | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n /** The anchor whose open delay runs while the card is closed. */\n let pending: Anchor<T> | undefined;\n /** The anchor that Space or `toggle()` opened the card for; only it outlasts the pointer leaving. */\n let pinned: Anchor<T> | undefined;\n let dismissed: Anchor<T> | undefined;\n let ring = true;\n let observer: ResizeObserver | undefined;\n\n const placement = (): HoverPreviewPlacement => options.placement ?? {};\n const region = () => {\n const value = placement();\n return \"beside\" in value ? value : undefined;\n };\n const focusTarget = (anchor: Anchor<T>) => anchor.trigger?.() ?? anchor.element;\n const anchorOf = (node: Node) => [...anchors].find((anchor) => anchor.element.contains(node));\n const clear = () => {\n clearTimeout(timer);\n timer = undefined;\n if (pending && !open()) document.removeEventListener(\"keydown\", escape);\n pending = undefined;\n };\n /** A passive card never closes a menu or another popover someone opened on purpose. */\n const blocked = () =>\n [...document.querySelectorAll(AUTO_POPOVER)].some((popover) => popover !== surface && !(surface && popover.contains(surface)));\n\n /** The boundary rectangle, never larger than the viewport. */\n const bounds = (within: Element | null | undefined) => {\n const rect = within?.getBoundingClientRect();\n return {\n top: Math.max(0, rect?.top ?? 0),\n right: Math.min(window.innerWidth, rect?.right ?? window.innerWidth),\n bottom: Math.min(window.innerHeight, rect?.bottom ?? window.innerHeight),\n };\n };\n /** Room right of the region for the card plus a gap on both sides. Works while the card is hidden. */\n const hasRoom = () => {\n const beside = region();\n if (!beside || !surface) return true;\n const area = beside.beside()?.getBoundingClientRect();\n if (!area) return false;\n const width = surface.getBoundingClientRect().width || Number.parseFloat(getComputedStyle(surface).width) || 0;\n return bounds(beside.within?.()).right - area.right >= width + 2 * GAP;\n };\n const position = () => {\n const anchor = current();\n if (!surface || !anchor) return;\n const beside = region();\n if (beside) {\n const area = beside.beside()?.getBoundingClientRect() ?? anchor.element.getBoundingClientRect();\n const box = bounds(beside.within?.());\n const height = surface.getBoundingClientRect().height;\n const top = anchor.element.getBoundingClientRect().top;\n surface.style.left = `${Math.round(area.right + GAP)}px`;\n surface.style.top = `${Math.round(Math.max(box.top + GAP, Math.min(top, box.bottom - height - GAP)))}px`;\n return;\n }\n positionTooltipSurface(surface, anchor.element, \"right\");\n const value = placement();\n if (!(\"beside\" in value) && value.align === \"end\") {\n const height = surface.getBoundingClientRect().height;\n const bottom = anchor.element.getBoundingClientRect().bottom;\n surface.style.top = `${Math.round(Math.max(8, Math.min(bottom - height, window.innerHeight - height - 8)))}px`;\n }\n };\n\n const escape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n if (!open()) {\n // Escape during the open delay works as if the card had opened and closed.\n if (pending) dismissed = pending;\n clear();\n return;\n }\n // Focus in the card goes back to the trigger: handled here, so the browser\n // neither returns it itself nor lights the ring for this key. A card the\n // pointer opened leaves the key to other handlers, such as an open modeless dialog.\n if (surface?.contains(document.activeElement)) event.preventDefault();\n dismiss();\n };\n // A card beside a region belongs to a row of a scrolling list: once the list\n // scrolls, another row sits under the pointer, so the card closes. A card\n // beside its anchor follows it.\n const scroll = (event: Event) => {\n const target = event.target;\n if (!region()) return position();\n if (!(target instanceof Node) || surface?.contains(target)) return;\n const anchor = current();\n if (!anchor || target.contains(anchor.element)) hide();\n };\n const resize = () => {\n if (hasRoom()) position();\n else hide();\n };\n const listen = (on: boolean) => {\n if (on) {\n document.addEventListener(\"keydown\", escape);\n window.addEventListener(\"scroll\", scroll, true);\n window.addEventListener(\"resize\", resize);\n return;\n }\n document.removeEventListener(\"keydown\", escape);\n window.removeEventListener(\"scroll\", scroll, true);\n window.removeEventListener(\"resize\", resize);\n };\n\n const hide = () => {\n clear();\n pinned = undefined;\n if (!open()) return;\n setOpen(false);\n listen(false);\n try {\n surface?.hidePopover();\n } catch {\n // The card may already be disconnected during cleanup.\n }\n };\n const dismiss = () => {\n const anchor = current();\n dismissed = anchor;\n // Before hiding, so the popover does not return focus on its own.\n if (anchor && surface?.contains(document.activeElement)) returnFocus(focusTarget(anchor), ring);\n hide();\n };\n /**\n * Opens the card for `anchor` or moves it there; `pin` keeps it open after\n * the pointer leaves. Moving the card to another anchor drops an earlier pin.\n * Returns whether it is open for `anchor`.\n */\n const show = (anchor: Anchor<T>, pin: boolean): boolean => {\n clear();\n if (!surface || dismissed === anchor) return false;\n if (options.disabled?.(anchor.value) || !hasRoom()) {\n hide();\n return false;\n }\n if (!open() || current() !== anchor) {\n ring = ringOnReturn(focusTarget(anchor));\n setCurrent(anchor);\n if (!open()) {\n try {\n surface.showPopover();\n } catch {\n return false;\n }\n setOpen(true);\n listen(true);\n }\n position();\n pinned = undefined;\n }\n if (pin) pinned = anchor;\n return true;\n };\n /** Shows `anchor` after `delay`; a keyboard swap (`follow`) carries an existing pin along. */\n const schedule = (anchor: Anchor<T>, delay: number, follow = false) => {\n clear();\n if (!open()) {\n pending = anchor;\n document.addEventListener(\"keydown\", escape);\n }\n timer = setTimeout(() => {\n if (open()) show(anchor, follow && pinned !== undefined);\n else if (blocked()) clear();\n else show(anchor, false);\n }, delay);\n };\n const leave = () => {\n clear();\n dismissed = undefined;\n if (pinned && pinned === current()) return;\n timer = setTimeout(() => {\n // Focus holds the card open inside it, and on the anchor where focus opens it.\n const focused = document.activeElement;\n const held = surface?.contains(focused) || (options.keyboard === \"focus\" && current()?.element.contains(focused));\n if (!held) hide();\n }, CLOSE_DELAY);\n };\n const focusOut = (event: FocusEvent) => {\n const next = event.relatedTarget;\n if (next instanceof Node && (surface?.contains(next) || anchorOf(next))) return;\n pinned = undefined;\n leave();\n };\n\n createEffect(() => {\n const anchor = current();\n if (open() && anchor && options.disabled?.(anchor.value)) hide();\n });\n // Only an open card holds global listeners, so a server render that\n // disposes the controller touches no browser globals.\n onCleanup(() => {\n hide();\n observer?.disconnect();\n });\n\n const anchor =\n (value: T, trigger?: () => HTMLElement | null | undefined) =>\n (element: HTMLElement): void => {\n const entry: Anchor<T> = { value, element, trigger };\n anchors.add(entry);\n const pointerEnter = (event: PointerEvent) => {\n // Touch and pen have no resting hover; the card stays a mouse affordance.\n if (event.pointerType !== \"mouse\") return;\n clear();\n if ((open() && current() === entry) || dismissed === entry) return;\n schedule(entry, open() ? SWAP_DELAY : (options.openDelay ?? 250));\n };\n // The open delay counts from the moment the mouse rests. An open card\n // swaps on entering another anchor and ignores movement inside it.\n const pointerMove = (event: PointerEvent) => {\n if (event.pointerType === \"mouse\" && !open() && dismissed !== entry) schedule(entry, options.openDelay ?? 250);\n };\n // A press acts on the row, such as opening it or its menu; a card about to open stays closed.\n const pointerDown = () => clear();\n const focusIn = () => {\n if (open()) {\n if (current() === entry) clear();\n else schedule(entry, SWAP_DELAY, true);\n return;\n }\n clear();\n if (options.keyboard === \"focus\" && dismissed !== entry) schedule(entry, options.openDelay ?? 250);\n };\n const keyDown = (event: KeyboardEvent) => {\n if (options.keyboard === \"focus\" || event.key !== \" \" || event.defaultPrevented) return;\n // Shift+Space keeps scrolling up; other modifiers belong to shortcuts.\n if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) return;\n if (event.target instanceof Element && event.target.matches(OWNS_SPACE)) return;\n event.preventDefault();\n // A held key toggles once; its repeats only keep the page from scrolling.\n if (event.repeat) return;\n if (open() && current() === entry) {\n dismiss();\n return;\n }\n dismissed = undefined;\n show(entry, true);\n };\n element.addEventListener(\"pointerenter\", pointerEnter);\n element.addEventListener(\"pointermove\", pointerMove);\n element.addEventListener(\"pointerdown\", pointerDown);\n element.addEventListener(\"pointerleave\", leave);\n element.addEventListener(\"focusin\", focusIn);\n element.addEventListener(\"focusout\", focusOut);\n element.addEventListener(\"keydown\", keyDown);\n onCleanup(() => {\n anchors.delete(entry);\n if (current() === entry) hide();\n element.removeEventListener(\"pointerenter\", pointerEnter);\n element.removeEventListener(\"pointermove\", pointerMove);\n element.removeEventListener(\"pointerdown\", pointerDown);\n element.removeEventListener(\"pointerleave\", leave);\n element.removeEventListener(\"focusin\", focusIn);\n element.removeEventListener(\"focusout\", focusOut);\n element.removeEventListener(\"keydown\", keyDown);\n });\n };\n\n return {\n id,\n anchor,\n active: () => (open() ? current()?.value : undefined),\n toggle: (value) => {\n const entry = [...anchors].find((candidate) => candidate.value === value);\n if (!entry || !surface) return;\n clear();\n if (open() && pinned === entry && current() === entry) {\n dismiss();\n return;\n }\n // A hover may have opened the card before this click or key press pinned it.\n ring = ringOnReturn(focusTarget(entry));\n dismissed = undefined;\n if (show(entry, true)) surface.focus();\n },\n close: dismiss,\n [INTERNALS]: {\n current,\n bind: (element) => {\n surface = element;\n observer = new ResizeObserver(() => {\n if (open()) position();\n });\n observer.observe(element);\n },\n enterSurface: clear,\n leave,\n focusOut,\n toggled: (visible) => {\n if (!visible) {\n // Light dismissal by the browser: an outside click or another popover.\n clear();\n pinned = undefined;\n if (open()) {\n setOpen(false);\n listen(false);\n }\n }\n options.onOpenChange?.(visible);\n },\n },\n };\n}\n\nexport type HoverPreviewProps<T> = {\n preview: HoverPreviewController<T>;\n /** Accessible name of the card. */\n label: string;\n /** `\"content\"` (default) sizes the card to its content up to 32rem; `\"fixed\"` keeps one 22rem × 20rem box for every anchor. */\n size?: \"content\" | \"fixed\";\n class?: string;\n /** Plain content stays mounted while the card is closed; a function renders the open anchor's value. */\n children: JSX.Element | ((value: T) => JSX.Element);\n};\n\n/**\n * A non-modal card that opens beside the anchor a resting mouse points at.\n * Native popover owns the top layer and light dismissal.\n */\nexport function HoverPreview<T>(props: HoverPreviewProps<T>): JSX.Element {\n const state = props.preview[INTERNALS];\n let surface!: HTMLDivElement;\n onMount(() => state.bind(surface));\n const content = () => {\n const children = props.children;\n if (typeof children !== \"function\") return children;\n return (\n <Show when={state.current()} keyed>\n {(anchor) => children(anchor.value)}\n </Show>\n );\n };\n return (\n <div\n ref={surface}\n id={props.preview.id}\n popover=\"auto\"\n role=\"dialog\"\n aria-label={props.label}\n tabIndex={-1}\n class={props.class ? `k2b-hover-preview ${props.class}` : \"k2b-hover-preview\"}\n data-size={props.size ?? \"content\"}\n onPointerEnter={() => state.enterSurface()}\n onPointerLeave={() => state.leave()}\n on:focusout={(event) => state.focusOut(event)}\n onToggle={(event) => state.toggled(event.newState === \"open\")}\n >\n {content()}\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -5,8 +5,25 @@ import { ssr as _$ssr } from "solid-js/web";
|
|
|
5
5
|
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
6
6
|
import { escape as _$escape } from "solid-js/web";
|
|
7
7
|
var _tmpl$ = ["<span", " role=\"tooltip\" popover=\"manual\" class=\"k2b-tooltip\"", ">", "</span>"];
|
|
8
|
-
import { createEffect, createUniqueId, onCleanup, onMount, splitProps } from "solid-js";
|
|
8
|
+
import { createContext, createEffect, createUniqueId, onCleanup, onMount, splitProps, useContext } from "solid-js";
|
|
9
9
|
import { positionTooltipSurface } from "./tooltip-position";
|
|
10
|
+
/** True below a Tooltip.Anchor, whose hint already covers the controls inside it. */
|
|
11
|
+
const AnchorContext = createContext(false);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The hint an icon-only control shows by default: its label, unless the caller
|
|
15
|
+
* passes its own `tooltip` (or `false`) or an enclosing Tooltip.Anchor already
|
|
16
|
+
* owns the hint.
|
|
17
|
+
*/
|
|
18
|
+
export const useLabelTooltip = (tooltip, label) => {
|
|
19
|
+
const anchored = useContext(AnchorContext);
|
|
20
|
+
return () => {
|
|
21
|
+
const explicit = tooltip();
|
|
22
|
+
if (explicit !== undefined) return explicit;
|
|
23
|
+
return anchored ? false : label();
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
10
27
|
/**
|
|
11
28
|
* Low-level tooltip surface for components that already own their target DOM
|
|
12
29
|
* element. Most callers should use Button.tooltip, IconButton.tooltip, or
|
|
@@ -65,10 +82,29 @@ function TooltipSurface(props) {
|
|
|
65
82
|
onMount(() => {
|
|
66
83
|
target = props.target();
|
|
67
84
|
if (!target) return;
|
|
85
|
+
|
|
86
|
+
// Server HTML may carry a native title as the no-JavaScript hint; once
|
|
87
|
+
// hydrated, this surface replaces it so the hint does not appear twice.
|
|
88
|
+
const originalTitle = target.getAttribute("title");
|
|
89
|
+
target.removeAttribute("title");
|
|
90
|
+
// A hint that only repeats the control's accessible name adds nothing for
|
|
91
|
+
// assistive technology, so it does not become a description.
|
|
92
|
+
const repeatsName = surface?.textContent?.trim() === target.getAttribute("aria-label")?.trim();
|
|
68
93
|
const originalDescription = target.getAttribute("aria-describedby");
|
|
69
94
|
const descriptions = new Set(originalDescription?.split(/\s+/).filter(Boolean) ?? []);
|
|
70
|
-
descriptions.add(tooltipId);
|
|
71
|
-
target.setAttribute("aria-describedby", [...descriptions].join(" "));
|
|
95
|
+
if (!repeatsName) descriptions.add(tooltipId);
|
|
96
|
+
if (descriptions.size > 0) target.setAttribute("aria-describedby", [...descriptions].join(" "));
|
|
97
|
+
|
|
98
|
+
// Touch has no hover, so a tap never opens the hint; the label stays the
|
|
99
|
+
// accessible name.
|
|
100
|
+
const enter = event => {
|
|
101
|
+
if (event.pointerType !== "touch") open();
|
|
102
|
+
};
|
|
103
|
+
// Only visible focus, as from the keyboard, opens the hint. Focus that a
|
|
104
|
+
// click or tap gives, or that a closing overlay returns silently, does not.
|
|
105
|
+
const focusIn = event => {
|
|
106
|
+
if (event.target?.matches?.(":focus-visible")) open();
|
|
107
|
+
};
|
|
72
108
|
const leave = () => {
|
|
73
109
|
dismissedUntilLeave = false;
|
|
74
110
|
close();
|
|
@@ -80,18 +116,19 @@ function TooltipSurface(props) {
|
|
|
80
116
|
dismissedUntilLeave = true;
|
|
81
117
|
close();
|
|
82
118
|
};
|
|
83
|
-
target.addEventListener("pointerenter",
|
|
119
|
+
target.addEventListener("pointerenter", enter);
|
|
84
120
|
target.addEventListener("pointerleave", leave);
|
|
85
121
|
target.addEventListener("pointerdown", pointerDown);
|
|
86
|
-
target.addEventListener("focusin",
|
|
122
|
+
target.addEventListener("focusin", focusIn);
|
|
87
123
|
target.addEventListener("focusout", focusOut);
|
|
88
124
|
onCleanup(() => {
|
|
89
125
|
close();
|
|
126
|
+
if (originalTitle !== null) target?.setAttribute("title", originalTitle);
|
|
90
127
|
if (originalDescription) target?.setAttribute("aria-describedby", originalDescription);else target?.removeAttribute("aria-describedby");
|
|
91
|
-
target?.removeEventListener("pointerenter",
|
|
128
|
+
target?.removeEventListener("pointerenter", enter);
|
|
92
129
|
target?.removeEventListener("pointerleave", leave);
|
|
93
130
|
target?.removeEventListener("pointerdown", pointerDown);
|
|
94
|
-
target?.removeEventListener("focusin",
|
|
131
|
+
target?.removeEventListener("focusin", focusIn);
|
|
95
132
|
target?.removeEventListener("focusout", focusOut);
|
|
96
133
|
});
|
|
97
134
|
});
|
|
@@ -106,7 +143,12 @@ function TooltipAnchor(props) {
|
|
|
106
143
|
get ["class"]() {
|
|
107
144
|
return `k2b-tooltip-wrapper ${local.class ?? ""}`;
|
|
108
145
|
}
|
|
109
|
-
}), [_$escape(
|
|
146
|
+
}), [_$escape(_$createComponent(AnchorContext.Provider, {
|
|
147
|
+
value: true,
|
|
148
|
+
get children() {
|
|
149
|
+
return local.children;
|
|
150
|
+
}
|
|
151
|
+
})), _$escape(_$createComponent(TooltipSurface, {
|
|
110
152
|
get content() {
|
|
111
153
|
return local.content;
|
|
112
154
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["feedback/Tooltip.tsx"],"sourcesContent":["import { createEffect, createUniqueId, type JSX, onCleanup, onMount, splitProps } from \"solid-js\";\nimport { positionTooltipSurface, type TooltipPlacement } from \"./tooltip-position\";\n\nexport type TooltipProps = {\n content: JSX.Element;\n target: () => HTMLElement | undefined;\n placement?: TooltipPlacement;\n delay?: number;\n disabled?: boolean;\n};\n\nexport type TooltipAnchorProps = Omit<JSX.HTMLAttributes<HTMLSpanElement>, \"content\"> & Omit<TooltipProps, \"target\">;\n\nexport type TooltipTriggerProps = Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, \"content\"> & Omit<TooltipProps, \"target\">;\n\n/**\n * Low-level tooltip surface for components that already own their target DOM\n * element. Most callers should use Button.tooltip, IconButton.tooltip, or\n * Tooltip.Anchor instead.\n */\nfunction TooltipSurface(props: TooltipProps): JSX.Element {\n const tooltipId = `k2b-tooltip-${createUniqueId()}`;\n let surface: HTMLSpanElement | undefined;\n let target: HTMLElement | undefined;\n let openTimer: ReturnType<typeof setTimeout> | undefined;\n let dismissedUntilLeave = false;\n\n const clearTimer = () => {\n if (openTimer) clearTimeout(openTimer);\n openTimer = undefined;\n };\n\n function dismissOnEscape(event: KeyboardEvent) {\n if (event.key !== \"Escape\" || !surface?.matches(\":popover-open\")) return;\n dismissedUntilLeave = true;\n close();\n }\n\n function close() {\n clearTimer();\n if (surface?.matches(\":popover-open\")) {\n try {\n surface.hidePopover();\n } catch {\n // The surface may disconnect during cleanup.\n }\n }\n document.removeEventListener(\"keydown\", dismissOnEscape);\n window.removeEventListener(\"scroll\", close, true);\n window.removeEventListener(\"resize\", close);\n }\n\n const open = () => {\n clearTimer();\n if (props.disabled || dismissedUntilLeave || !surface || !target || surface.matches(\":popover-open\")) return;\n const show = () => {\n openTimer = undefined;\n if (props.disabled || !surface?.isConnected || !target) return;\n try {\n surface.showPopover();\n } catch {\n return;\n }\n positionTooltipSurface(surface, target, props.placement);\n document.addEventListener(\"keydown\", dismissOnEscape);\n window.addEventListener(\"scroll\", close, true);\n window.addEventListener(\"resize\", close);\n };\n const delay = props.delay ?? 250;\n if (delay <= 0) show();\n else openTimer = setTimeout(show, delay);\n };\n\n createEffect(() => {\n if (props.disabled) close();\n });\n\n onMount(() => {\n target = props.target();\n if (!target) return;\n\n const originalDescription = target.getAttribute(\"aria-describedby\");\n const descriptions = new Set(originalDescription?.split(/\\s+/).filter(Boolean) ?? []);\n descriptions.add(tooltipId);\n target.setAttribute(\"aria-describedby\", [...descriptions].join(\" \"));\n\n const leave = () => {\n dismissedUntilLeave = false;\n close();\n };\n const focusOut = (event: FocusEvent) => {\n if (!target?.contains(event.relatedTarget as Node | null)) leave();\n };\n const pointerDown = () => {\n dismissedUntilLeave = true;\n close();\n };\n\n target.addEventListener(\"pointerenter\", open);\n target.addEventListener(\"pointerleave\", leave);\n target.addEventListener(\"pointerdown\", pointerDown);\n target.addEventListener(\"focusin\", open);\n target.addEventListener(\"focusout\", focusOut);\n\n onCleanup(() => {\n close();\n if (originalDescription) target?.setAttribute(\"aria-describedby\", originalDescription);\n else target?.removeAttribute(\"aria-describedby\");\n target?.removeEventListener(\"pointerenter\", open);\n target?.removeEventListener(\"pointerleave\", leave);\n target?.removeEventListener(\"pointerdown\", pointerDown);\n target?.removeEventListener(\"focusin\", open);\n target?.removeEventListener(\"focusout\", focusOut);\n });\n });\n\n return (\n <span\n ref={surface}\n id={tooltipId}\n role=\"tooltip\"\n popover=\"manual\"\n class=\"k2b-tooltip\"\n data-instant={props.delay !== undefined && props.delay <= 0 ? \"true\" : undefined}\n >\n {props.content}\n </span>\n );\n}\n\n/** Explicit tooltip target for non-button content. */\nfunction TooltipAnchor(props: TooltipAnchorProps): JSX.Element {\n const [local, rest] = splitProps(props, [\"children\", \"class\", \"content\", \"delay\", \"disabled\", \"placement\"]);\n let target: HTMLSpanElement | undefined;\n\n return (\n <span {...rest} ref={target} class={`k2b-tooltip-wrapper ${local.class ?? \"\"}`}>\n {local.children}\n <TooltipSurface\n content={local.content}\n target={() => target}\n delay={local.delay}\n disabled={local.disabled}\n placement={local.placement}\n />\n </span>\n );\n}\n\n/** Native button target for specialized controls that do not use Button. */\nfunction TooltipTrigger(props: TooltipTriggerProps): JSX.Element {\n const [local, rest] = splitProps(props, [\"children\", \"content\", \"delay\", \"disabled\", \"placement\", \"ref\"]);\n let target: HTMLButtonElement | undefined;\n const register = (element: HTMLButtonElement) => {\n target = element;\n if (typeof local.ref === \"function\") local.ref(element);\n };\n\n return (\n <>\n <button {...rest} ref={register} disabled={local.disabled}>\n {local.children}\n </button>\n <TooltipSurface\n content={local.content}\n target={() => target}\n delay={local.delay}\n disabled={local.disabled}\n placement={local.placement}\n />\n </>\n );\n}\n\ntype TooltipComponent = ((props: TooltipProps) => JSX.Element) & {\n Anchor: (props: TooltipAnchorProps) => JSX.Element;\n Trigger: (props: TooltipTriggerProps) => JSX.Element;\n};\n\nexport const Tooltip = TooltipSurface as TooltipComponent;\nTooltip.Anchor = TooltipAnchor;\nTooltip.Trigger = TooltipTrigger;\n\nexport type { TooltipPlacement } from \"./tooltip-position\";\n\nexport default Tooltip;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["feedback/Tooltip.tsx"],"sourcesContent":["import { createContext, createEffect, createUniqueId, type JSX, onCleanup, onMount, splitProps, useContext } from \"solid-js\";\nimport { positionTooltipSurface, type TooltipPlacement } from \"./tooltip-position\";\n\nexport type TooltipProps = {\n content: JSX.Element;\n target: () => HTMLElement | undefined;\n placement?: TooltipPlacement;\n delay?: number;\n disabled?: boolean;\n};\n\nexport type TooltipAnchorProps = Omit<JSX.HTMLAttributes<HTMLSpanElement>, \"content\"> & Omit<TooltipProps, \"target\">;\n\nexport type TooltipTriggerProps = Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, \"content\"> & Omit<TooltipProps, \"target\">;\n\n/** True below a Tooltip.Anchor, whose hint already covers the controls inside it. */\nconst AnchorContext = createContext(false);\n\n/**\n * The hint an icon-only control shows by default: its label, unless the caller\n * passes its own `tooltip` (or `false`) or an enclosing Tooltip.Anchor already\n * owns the hint.\n */\nexport const useLabelTooltip = (tooltip: () => JSX.Element | false | undefined, label: () => string | undefined) => {\n const anchored = useContext(AnchorContext);\n return (): JSX.Element | false | undefined => {\n const explicit = tooltip();\n if (explicit !== undefined) return explicit;\n return anchored ? false : label();\n };\n};\n\n/**\n * Low-level tooltip surface for components that already own their target DOM\n * element. Most callers should use Button.tooltip, IconButton.tooltip, or\n * Tooltip.Anchor instead.\n */\nfunction TooltipSurface(props: TooltipProps): JSX.Element {\n const tooltipId = `k2b-tooltip-${createUniqueId()}`;\n let surface: HTMLSpanElement | undefined;\n let target: HTMLElement | undefined;\n let openTimer: ReturnType<typeof setTimeout> | undefined;\n let dismissedUntilLeave = false;\n\n const clearTimer = () => {\n if (openTimer) clearTimeout(openTimer);\n openTimer = undefined;\n };\n\n function dismissOnEscape(event: KeyboardEvent) {\n if (event.key !== \"Escape\" || !surface?.matches(\":popover-open\")) return;\n dismissedUntilLeave = true;\n close();\n }\n\n function close() {\n clearTimer();\n if (surface?.matches(\":popover-open\")) {\n try {\n surface.hidePopover();\n } catch {\n // The surface may disconnect during cleanup.\n }\n }\n document.removeEventListener(\"keydown\", dismissOnEscape);\n window.removeEventListener(\"scroll\", close, true);\n window.removeEventListener(\"resize\", close);\n }\n\n const open = () => {\n clearTimer();\n if (props.disabled || dismissedUntilLeave || !surface || !target || surface.matches(\":popover-open\")) return;\n const show = () => {\n openTimer = undefined;\n if (props.disabled || !surface?.isConnected || !target) return;\n try {\n surface.showPopover();\n } catch {\n return;\n }\n positionTooltipSurface(surface, target, props.placement);\n document.addEventListener(\"keydown\", dismissOnEscape);\n window.addEventListener(\"scroll\", close, true);\n window.addEventListener(\"resize\", close);\n };\n const delay = props.delay ?? 250;\n if (delay <= 0) show();\n else openTimer = setTimeout(show, delay);\n };\n\n createEffect(() => {\n if (props.disabled) close();\n });\n\n onMount(() => {\n target = props.target();\n if (!target) return;\n\n // Server HTML may carry a native title as the no-JavaScript hint; once\n // hydrated, this surface replaces it so the hint does not appear twice.\n const originalTitle = target.getAttribute(\"title\");\n target.removeAttribute(\"title\");\n // A hint that only repeats the control's accessible name adds nothing for\n // assistive technology, so it does not become a description.\n const repeatsName = surface?.textContent?.trim() === target.getAttribute(\"aria-label\")?.trim();\n const originalDescription = target.getAttribute(\"aria-describedby\");\n const descriptions = new Set(originalDescription?.split(/\\s+/).filter(Boolean) ?? []);\n if (!repeatsName) descriptions.add(tooltipId);\n if (descriptions.size > 0) target.setAttribute(\"aria-describedby\", [...descriptions].join(\" \"));\n\n // Touch has no hover, so a tap never opens the hint; the label stays the\n // accessible name.\n const enter = (event: PointerEvent) => {\n if (event.pointerType !== \"touch\") open();\n };\n // Only visible focus, as from the keyboard, opens the hint. Focus that a\n // click or tap gives, or that a closing overlay returns silently, does not.\n const focusIn = (event: FocusEvent) => {\n if ((event.target as Element | null)?.matches?.(\":focus-visible\")) open();\n };\n const leave = () => {\n dismissedUntilLeave = false;\n close();\n };\n const focusOut = (event: FocusEvent) => {\n if (!target?.contains(event.relatedTarget as Node | null)) leave();\n };\n const pointerDown = () => {\n dismissedUntilLeave = true;\n close();\n };\n\n target.addEventListener(\"pointerenter\", enter);\n target.addEventListener(\"pointerleave\", leave);\n target.addEventListener(\"pointerdown\", pointerDown);\n target.addEventListener(\"focusin\", focusIn);\n target.addEventListener(\"focusout\", focusOut);\n\n onCleanup(() => {\n close();\n if (originalTitle !== null) target?.setAttribute(\"title\", originalTitle);\n if (originalDescription) target?.setAttribute(\"aria-describedby\", originalDescription);\n else target?.removeAttribute(\"aria-describedby\");\n target?.removeEventListener(\"pointerenter\", enter);\n target?.removeEventListener(\"pointerleave\", leave);\n target?.removeEventListener(\"pointerdown\", pointerDown);\n target?.removeEventListener(\"focusin\", focusIn);\n target?.removeEventListener(\"focusout\", focusOut);\n });\n });\n\n return (\n <span\n ref={surface}\n id={tooltipId}\n role=\"tooltip\"\n popover=\"manual\"\n class=\"k2b-tooltip\"\n data-instant={props.delay !== undefined && props.delay <= 0 ? \"true\" : undefined}\n >\n {props.content}\n </span>\n );\n}\n\n/** Explicit tooltip target for non-button content. */\nfunction TooltipAnchor(props: TooltipAnchorProps): JSX.Element {\n const [local, rest] = splitProps(props, [\"children\", \"class\", \"content\", \"delay\", \"disabled\", \"placement\"]);\n let target: HTMLSpanElement | undefined;\n\n return (\n <span {...rest} ref={target} class={`k2b-tooltip-wrapper ${local.class ?? \"\"}`}>\n <AnchorContext.Provider value={true}>{local.children}</AnchorContext.Provider>\n <TooltipSurface\n content={local.content}\n target={() => target}\n delay={local.delay}\n disabled={local.disabled}\n placement={local.placement}\n />\n </span>\n );\n}\n\n/** Native button target for specialized controls that do not use Button. */\nfunction TooltipTrigger(props: TooltipTriggerProps): JSX.Element {\n const [local, rest] = splitProps(props, [\"children\", \"content\", \"delay\", \"disabled\", \"placement\", \"ref\"]);\n let target: HTMLButtonElement | undefined;\n const register = (element: HTMLButtonElement) => {\n target = element;\n if (typeof local.ref === \"function\") local.ref(element);\n };\n\n return (\n <>\n <button {...rest} ref={register} disabled={local.disabled}>\n {local.children}\n </button>\n <TooltipSurface\n content={local.content}\n target={() => target}\n delay={local.delay}\n disabled={local.disabled}\n placement={local.placement}\n />\n </>\n );\n}\n\ntype TooltipComponent = ((props: TooltipProps) => JSX.Element) & {\n Anchor: (props: TooltipAnchorProps) => JSX.Element;\n Trigger: (props: TooltipTriggerProps) => JSX.Element;\n};\n\nexport const Tooltip = TooltipSurface as TooltipComponent;\nTooltip.Anchor = TooltipAnchor;\nTooltip.Trigger = TooltipTrigger;\n\nexport type { TooltipPlacement } from \"./tooltip-position\";\n\nexport default Tooltip;\n"],"mappings":";;;;;;;AAAA,SAAS,aAAa,EAAE,YAAY,EAAE,cAAc,EAAY,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,QAAQ,UAAU;AAC5H,SAAS,sBAAsB,QAA+B,oBAAoB;AAclF;AACA,MAAM,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC;;AAE1C;AACA;AACA;AACA;AACA;AACA,OAAO,MAAM,eAAe,GAAG,CAAC,OAA8C,EAAE,KAA+B,KAAK;EAClH,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC;EAC1C,OAAO,MAAuC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC;IAC1B,IAAI,QAAQ,KAAK,SAAS,EAAE,OAAO,QAAQ;IAC3C,OAAO,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;EACnC,CAAC;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,SAAS,cAAc,CAAC,KAAmB,EAAe;EACxD,MAAM,SAAS,GAAG,eAAe,cAAc,CAAC,CAAC,EAAE;EACnD,IAAI,OAAoC;EACxC,IAAI,MAA+B;EACnC,IAAI,SAAoD;EACxD,IAAI,mBAAmB,GAAG,KAAK;EAE/B,MAAM,UAAU,GAAG,MAAM;IACvB,IAAI,SAAS,EAAE,YAAY,CAAC,SAAS,CAAC;IACtC,SAAS,GAAG,SAAS;EACvB,CAAC;EAED,SAAS,eAAe,CAAC,KAAoB,EAAE;IAC7C,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EAAE;IAClE,mBAAmB,GAAG,IAAI;IAC1B,KAAK,CAAC,CAAC;EACT;EAEA,SAAS,KAAK,GAAG;IACf,UAAU,CAAC,CAAC;IACZ,IAAI,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EAAE;MACrC,IAAI;QACF,OAAO,CAAC,WAAW,CAAC,CAAC;MACvB,CAAC,CAAC,MAAM;QACN;MAAA;IAEJ;IACA,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC;IACxD,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC;IACjD,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC;EAC7C;EAEA,MAAM,IAAI,GAAG,MAAM;IACjB,UAAU,CAAC,CAAC;IACZ,IAAI,KAAK,CAAC,QAAQ,IAAI,mBAAmB,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE;IACtG,MAAM,IAAI,GAAG,MAAM;MACjB,SAAS,GAAG,SAAS;MACrB,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,WAAW,IAAI,CAAC,MAAM,EAAE;MACxD,IAAI;QACF,OAAO,CAAC,WAAW,CAAC,CAAC;MACvB,CAAC,CAAC,MAAM;QACN;MACF;MACA,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;MACxD,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,eAAe,CAAC;MACrD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC;MAC9C,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAC1C,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG;IAChC,IAAI,KAAK,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,KAClB,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC;EAC1C,CAAC;EAED,YAAY,CAAC,MAAM;IACjB,IAAI,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;EAC7B,CAAC,CAAC;EAEF,OAAO,CAAC,MAAM;IACZ,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,IAAI,CAAC,MAAM,EAAE;;IAEb;IACA;IACA,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC;IAClD,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC;IAC/B;IACA;IACA,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9F,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC;IACnE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACrF,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;IAC7C,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;IAE/F;IACA;IACA,MAAM,KAAK,GAAI,KAAmB,IAAK;MACrC,IAAI,KAAK,CAAC,WAAW,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD;IACA;IACA,MAAM,OAAO,GAAI,KAAiB,IAAK;MACrC,IAAK,KAAK,CAAC,MAAM,EAAqB,OAAO,GAAG,gBAAgB,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,KAAK,GAAG,MAAM;MAClB,mBAAmB,GAAG,KAAK;MAC3B,KAAK,CAAC,CAAC;IACT,CAAC;IACD,MAAM,QAAQ,GAAI,KAAiB,IAAK;MACtC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAA4B,CAAC,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,WAAW,GAAG,MAAM;MACxB,mBAAmB,GAAG,IAAI;MAC1B,KAAK,CAAC,CAAC;IACT,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,CAAC;IAC9C,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,KAAK,CAAC;IAC9C,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,WAAW,CAAC;IACnD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;IAC3C,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,QAAQ,CAAC;IAE7C,SAAS,CAAC,MAAM;MACd,KAAK,CAAC,CAAC;MACP,IAAI,aAAa,KAAK,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC;MACxE,IAAI,mBAAmB,EAAE,MAAM,EAAE,YAAY,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC,KAClF,MAAM,EAAE,eAAe,CAAC,kBAAkB,CAAC;MAChD,MAAM,EAAE,mBAAmB,CAAC,cAAc,EAAE,KAAK,CAAC;MAClD,MAAM,EAAE,mBAAmB,CAAC,cAAc,EAAE,KAAK,CAAC;MAClD,MAAM,EAAE,mBAAmB,CAAC,aAAa,EAAE,WAAW,CAAC;MACvD,MAAM,EAAE,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC;MAC/C,MAAM,EAAE,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC;IACnD,CAAC,CAAC;EACJ,CAAC,CAAC;EAEF,mDAGQ,SAAS,gDAIC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,MAAM,YAAG,SAAS,0BAE/E,KAAK,CAAC,OAAO;AAGpB;;AAEA;AACA,SAAS,aAAa,CAAC,KAAyB,EAAe;EAC7D,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;EAC3G,IAAI,MAAmC;EAEvC,yCACY,IAAI;IAAA;MAAA,OAAsB,uBAAuB,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE;IAAA;EAAA,gCAC3E,aAAa,CAAC,QAAQ;IAAC,KAAK,EAAE,IAAI;IAAA;MAAA,OAAG,KAAK,CAAC,QAAQ;IAAA;EAAA,gCACnD,cAAc;IAAA,IACb,OAAO;MAAA,OAAE,KAAK,CAAC,OAAO;IAAA;IACtB,MAAM,EAAE,MAAM,MAAM;IAAA,IACpB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,SAAS;MAAA,OAAE,KAAK,CAAC,SAAS;IAAA;EAAA;AAIlC;;AAEA;AACA,SAAS,cAAc,CAAC,KAA0B,EAAe;EAC/D,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;EACzG,IAAI,MAAqC;EACzC,MAAM,QAAQ,GAAI,OAA0B,IAAK;IAC/C,MAAM,GAAG,OAAO;IAChB,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;EACzD,CAAC;EAED,4CAEgB,IAAI;IAAA,IAAiB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;EAAA,aACtD,KAAK,CAAC,QAAQ,6BAEhB,cAAc;IAAA,IACb,OAAO;MAAA,OAAE,KAAK,CAAC,OAAO;IAAA;IACtB,MAAM,EAAE,MAAM,MAAM;IAAA,IACpB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,SAAS;MAAA,OAAE,KAAK,CAAC,SAAS;IAAA;EAAA;AAIlC;AAOA,OAAO,MAAM,OAAO,GAAG,cAAkC;AACzD,OAAO,CAAC,MAAM,GAAG,aAAa;AAC9B,OAAO,CAAC,OAAO,GAAG,cAAc;AAIhC,eAAe,OAAO","ignoreList":[]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { render } from "solid-js/web";
|
|
2
|
+
import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
2
3
|
import { getK2bPortalRoot } from "../internal/portal";
|
|
3
4
|
import { resolveUiMessages } from "../intl/messages";
|
|
4
5
|
import { isPointInsideToast } from "./toast";
|
|
@@ -32,6 +33,16 @@ const applyAccessibleName = (dialog, entry) => {
|
|
|
32
33
|
const schedule = callback => {
|
|
33
34
|
if (typeof requestAnimationFrame === "function") requestAnimationFrame(callback);else queueMicrotask(callback);
|
|
34
35
|
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether focus is still where closing a level left it, on the page or the
|
|
39
|
+
* dialog: nothing took it before the next frame, neither a close handler nor a
|
|
40
|
+
* Tab pressed right after Escape.
|
|
41
|
+
*/
|
|
42
|
+
const focusUnclaimed = dialog => {
|
|
43
|
+
const active = document.activeElement;
|
|
44
|
+
return !active || active === document.body || active === dialog;
|
|
45
|
+
};
|
|
35
46
|
export const createDialogCore = () => {
|
|
36
47
|
const state = {
|
|
37
48
|
stack: []
|
|
@@ -159,8 +170,8 @@ export const createDialogCore = () => {
|
|
|
159
170
|
applyAccessibleName(dialog, previous);
|
|
160
171
|
applyCancelBehavior(dialog, () => void requestDismiss(previous), previous.cancelBehavior);
|
|
161
172
|
schedule(() => {
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
if (!focusUnclaimed(dialog)) return;
|
|
174
|
+
if (top.opener?.isConnected) returnFocus(top.opener, top.openerRing);else resolveInitialFocusTarget(previous, dialog)?.focus();
|
|
164
175
|
});
|
|
165
176
|
} else if (dialog) {
|
|
166
177
|
dialog.oncancel = null;
|
|
@@ -173,8 +184,10 @@ export const createDialogCore = () => {
|
|
|
173
184
|
state.element = undefined;
|
|
174
185
|
stopConnectionObserver();
|
|
175
186
|
unlockPageScroll();
|
|
187
|
+
// After the Escape that closed it: WebKit lights the ring of whatever
|
|
188
|
+
// that key press leaves focused.
|
|
176
189
|
schedule(() => {
|
|
177
|
-
if (top.opener?.isConnected) top.opener.
|
|
190
|
+
if (top.opener?.isConnected && focusUnclaimed(dialog)) returnFocus(top.opener, top.openerRing);
|
|
178
191
|
});
|
|
179
192
|
}
|
|
180
193
|
top.resolve?.(result);
|
|
@@ -221,6 +234,7 @@ export const createDialogCore = () => {
|
|
|
221
234
|
cancelBehavior,
|
|
222
235
|
initialFocus,
|
|
223
236
|
opener: activeElement instanceof HTMLElement ? activeElement : undefined,
|
|
237
|
+
openerRing: ringOnReturn(activeElement),
|
|
224
238
|
ariaLabel: options.ariaLabel,
|
|
225
239
|
modal: true
|
|
226
240
|
};
|
|
@@ -265,6 +279,10 @@ export const createDialogCore = () => {
|
|
|
265
279
|
applyAccessibleName(dialog, entry);
|
|
266
280
|
applyCancelBehavior(dialog, () => void requestDismiss(entry), cancelBehavior);
|
|
267
281
|
if (state.stack.length === 1) {
|
|
282
|
+
// The native dialog returns focus to the element focused when it
|
|
283
|
+
// opened, with a ring of the browser's choosing. Opening from a
|
|
284
|
+
// blurred document leaves the return to popTop and its opener ring.
|
|
285
|
+
if (activeElement instanceof HTMLElement) activeElement.blur();
|
|
268
286
|
if (typeof dialog.showModal === "function") {
|
|
269
287
|
if (entry.modal) dialog.showModal();else dialog.show();
|
|
270
288
|
} else dialog.setAttribute("open", "");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["feedback/dialog-core.ts"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { getK2bPortalRoot } from \"../internal/portal\";\nimport { resolveUiMessages } from \"../intl/messages\";\nimport { isPointInsideToast } from \"./toast\";\n\nexport type DialogClose<T> = (result?: T) => void;\n\nexport type OpenDialogOptions = {\n /** Close only this dialog when its owning operation is cancelled. */\n signal?: AbortSignal;\n panelClassName?: string;\n contentClassName?: string;\n initialFocus?: \"first-input\" | \"none\" | ((dialog: HTMLDialogElement) => HTMLElement | null);\n cancelBehavior?: \"resolve-undefined\" | \"ignore\";\n ariaLabel?: string;\n};\n\nexport type DialogRender<T> = (\n close: DialogClose<T>,\n context: {\n dialog: HTMLDialogElement;\n /** Switch this entry between a modal and a modeless window without remounting. */\n setModal: (modal: boolean) => void;\n /** Set viewport coordinates, or restore the panel stylesheet position with null. */\n setPosition: (position: { x: number; y: number } | null) => void;\n /** Route Escape/backdrop through the same guarded handler as Cancel and X. */\n setDismissHandler: (handler: () => void | Promise<void>) => void;\n /** Request dismissal through this entry's cancellation policy and guard. */\n requestDismiss: () => Promise<void>;\n },\n) => JSX.Element;\n\nexport type DialogCore = {\n open: <T>(view: DialogRender<T>, options?: OpenDialogOptions) => Promise<T | undefined>;\n close: (result?: unknown) => void;\n isOpen: () => boolean;\n};\n\ntype DialogStackEntry = {\n container: HTMLDivElement;\n dispose?: () => void;\n resolve?: (value: unknown) => void;\n panelClassName: string;\n cancelBehavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>;\n initialFocus: NonNullable<OpenDialogOptions[\"initialFocus\"]>;\n opener?: HTMLElement;\n ariaLabel?: string;\n dismissHandler?: () => void | Promise<void>;\n dismissPending?: boolean;\n modal: boolean;\n position?: { x: number; y: number } | null;\n};\n\ntype DialogState = {\n element?: HTMLDialogElement;\n modal?: boolean;\n stack: DialogStackEntry[];\n scrollLocked?: boolean;\n previousBodyOverflow?: string;\n previousHtmlOverflow?: string;\n mouseDownOnDialog?: boolean;\n connectionObserver?: MutationObserver;\n};\n\nconst DEFAULT_PANEL_CLASS = \"k2b-dialog\";\nconst DEFAULT_CONTENT_CLASS = \"k2b-dialog__viewport\";\nlet nextDialogTitleId = 0;\n\nconst resolveInitialFocusTarget = (entry: DialogStackEntry, dialog: HTMLDialogElement): HTMLElement | null => {\n const { initialFocus } = entry;\n if (initialFocus === \"none\") return null;\n if (typeof initialFocus === \"function\") return initialFocus(dialog);\n const input = entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n return (\n input ??\n entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), a[href], [tabindex]:not([tabindex='-1'])\",\n )\n );\n};\n\nconst applyAccessibleName = (dialog: HTMLDialogElement, entry: DialogStackEntry): void => {\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (entry.ariaLabel) {\n dialog.setAttribute(\"aria-label\", entry.ariaLabel);\n return;\n }\n const heading = entry.container.querySelector<HTMLElement>(\"h1, h2, h3\");\n if (!heading) {\n dialog.setAttribute(\"aria-label\", resolveUiMessages().dialog);\n return;\n }\n heading.id ||= `k2b-dialog-title-${++nextDialogTitleId}`;\n dialog.setAttribute(\"aria-labelledby\", heading.id);\n};\n\nconst schedule = (callback: () => void): void => {\n if (typeof requestAnimationFrame === \"function\") requestAnimationFrame(callback);\n else queueMicrotask(callback);\n};\n\nexport const createDialogCore = (): DialogCore => {\n const state: DialogState = { stack: [] };\n\n const ensureDialogElement = () => {\n if (typeof document === \"undefined\") throw new Error(\"@k2b/ui dialogs can only be opened in the browser\");\n // Reuse the shared element whenever it is still in the document. Resolving\n // the portal root first would create a second <dialog> when focus has moved\n // into another `.k2b-ui` scope, orphaning the levels already on the stack.\n if (state.element?.isConnected) return state.element;\n\n const element = document.createElement(\"dialog\");\n element.onclose = () => {\n // Repeated Escape can force a non-cancelable native close. A retained\n // entry (ignore, an async guard, or a parent) still owns the modal.\n const top = state.stack[state.stack.length - 1];\n if (state.element !== element || element.open || !top) return;\n if (top.modal) element.showModal();\n else element.show();\n resolveInitialFocusTarget(top, element)?.focus();\n };\n getK2bPortalRoot().appendChild(element);\n state.element = element;\n return element;\n };\n\n const lockPageScroll = () => {\n if (typeof document === \"undefined\" || state.scrollLocked) return;\n state.previousBodyOverflow = document.body.style.overflow;\n state.previousHtmlOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = \"hidden\";\n document.documentElement.style.overflow = \"hidden\";\n state.scrollLocked = true;\n };\n\n const unlockPageScroll = () => {\n if (typeof document === \"undefined\" || !state.scrollLocked) return;\n document.body.style.overflow = state.previousBodyOverflow ?? \"\";\n document.documentElement.style.overflow = state.previousHtmlOverflow ?? \"\";\n state.scrollLocked = false;\n state.previousBodyOverflow = undefined;\n state.previousHtmlOverflow = undefined;\n };\n\n const applyPresentation = (entry: DialogStackEntry) => {\n const dialog = state.element;\n if (!dialog || state.stack[state.stack.length - 1] !== entry) return;\n const position = entry.position;\n dialog.style.position = position ? \"fixed\" : \"\";\n dialog.style.inset = position ? `${position.y}px auto auto ${position.x}px` : \"\";\n dialog.style.margin = position ? \"0\" : \"\";\n dialog.style.transform = position ? \"none\" : \"\";\n dialog.dataset.modeless = String(!entry.modal);\n dialog.setAttribute(\"aria-modal\", String(entry.modal));\n if (dialog.open && state.modal !== entry.modal) {\n const active = document.activeElement;\n dialog.close();\n if (entry.modal) dialog.showModal();\n else dialog.show();\n if (active instanceof HTMLElement && active.isConnected && (!entry.modal || dialog.contains(active))) {\n active.focus({ preventScroll: true });\n } else resolveInitialFocusTarget(entry, dialog)?.focus({ preventScroll: true });\n }\n state.modal = entry.modal;\n if (entry.modal) lockPageScroll();\n else unlockPageScroll();\n };\n\n const modelessEscape = (event: KeyboardEvent) => {\n const top = state.stack[state.stack.length - 1];\n if (!top || top.modal || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n event.preventDefault();\n void requestDismiss(top);\n };\n\n const stopConnectionObserver = () => {\n document.removeEventListener(\"keydown\", modelessEscape);\n state.connectionObserver?.disconnect();\n state.connectionObserver = undefined;\n };\n\n const applyCancelBehavior = (\n dialog: HTMLDialogElement,\n close: () => void,\n behavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>,\n ) => {\n dialog.oncancel = (event) => {\n if (behavior === \"ignore\") {\n event.preventDefault();\n return;\n }\n event.preventDefault();\n close();\n };\n dialog.onmousedown = (event) => {\n state.mouseDownOnDialog = event.target === dialog;\n };\n dialog.onclick = (event) => {\n const realBackdropClick = state.mouseDownOnDialog === true;\n state.mouseDownOnDialog = false;\n if (event.target !== dialog || !state.modal) return;\n if (!realBackdropClick) return;\n if (behavior === \"ignore\") return;\n if (isPointInsideToast(event.clientX, event.clientY)) return;\n close();\n };\n };\n\n const requestDismiss = async (entry: DialogStackEntry) => {\n if (state.stack[state.stack.length - 1] !== entry || entry.dismissPending || entry.cancelBehavior === \"ignore\") return;\n if (!entry.dismissHandler) {\n popTop(undefined);\n return;\n }\n entry.dismissPending = true;\n try {\n await entry.dismissHandler();\n } catch (error) {\n // A failed guard must never discard the dialog's state.\n console.error(\"Dialog dismissal failed\", error);\n } finally {\n entry.dismissPending = false;\n }\n };\n\n const popTop = (result?: unknown) => {\n const top = state.stack.pop();\n if (!top) return;\n top.dispose?.();\n top.container.remove();\n\n const dialog = state.element;\n const previous = state.stack[state.stack.length - 1];\n if (previous && dialog) {\n previous.container.style.display = \"\";\n dialog.className = previous.panelClassName;\n applyPresentation(previous);\n applyAccessibleName(dialog, previous);\n applyCancelBehavior(dialog, () => void requestDismiss(previous), previous.cancelBehavior);\n schedule(() => {\n const target = top.opener?.isConnected ? top.opener : resolveInitialFocusTarget(previous, dialog);\n target?.focus();\n });\n } else if (dialog) {\n dialog.oncancel = null;\n dialog.onmousedown = null;\n dialog.onclick = null;\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (dialog.open && typeof dialog.close === \"function\") dialog.close();\n else dialog.removeAttribute(\"open\");\n dialog.remove();\n state.element = undefined;\n stopConnectionObserver();\n unlockPageScroll();\n schedule(() => {\n if (top.opener?.isConnected) top.opener.focus();\n });\n }\n\n top.resolve?.(result);\n };\n\n const resetDisconnectedDialog = () => {\n if (state.stack.length === 0 || state.element?.isConnected) return;\n const entries = state.stack.splice(0);\n const dialog = state.element;\n state.element = undefined;\n stopConnectionObserver();\n dialog?.remove();\n unlockPageScroll();\n for (const entry of entries.reverse()) {\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n\n const observeConnection = () => {\n if (state.connectionObserver || typeof MutationObserver === \"undefined\") return;\n document.addEventListener(\"keydown\", modelessEscape);\n state.connectionObserver = new MutationObserver(resetDisconnectedDialog);\n state.connectionObserver.observe(document.documentElement, { childList: true, subtree: true });\n };\n\n const open = <T>(view: DialogRender<T>, options: OpenDialogOptions = {}): Promise<T | undefined> => {\n if (options.signal?.aborted) return Promise.resolve(undefined);\n const dialog = ensureDialogElement();\n const previousTop = state.stack[state.stack.length - 1];\n if (previousTop) previousTop.container.style.display = \"none\";\n const activeElement = document.activeElement;\n\n const panelClassName = options.panelClassName ?? DEFAULT_PANEL_CLASS;\n const cancelBehavior = options.cancelBehavior ?? \"resolve-undefined\";\n const initialFocus = options.initialFocus ?? \"first-input\";\n dialog.className = panelClassName;\n\n const container = document.createElement(\"div\");\n container.className = options.contentClassName ?? DEFAULT_CONTENT_CLASS;\n dialog.appendChild(container);\n\n const entry: DialogStackEntry = {\n container,\n panelClassName,\n cancelBehavior,\n initialFocus,\n opener: activeElement instanceof HTMLElement ? activeElement : undefined,\n ariaLabel: options.ariaLabel,\n modal: true,\n };\n\n return new Promise((resolve, reject) => {\n const abort = () => {\n const index = state.stack.indexOf(entry);\n if (index < 0) return;\n if (index === state.stack.length - 1) popTop(undefined);\n else {\n state.stack.splice(index, 1);\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n entry.resolve = (value) => {\n options.signal?.removeEventListener(\"abort\", abort);\n resolve(value as T | undefined);\n };\n const closeTyped: DialogClose<T> = (result) => {\n if (state.stack[state.stack.length - 1] !== entry) return;\n popTop(result);\n };\n\n state.stack.push(entry);\n try {\n entry.dispose = render(\n () =>\n view(closeTyped, {\n dialog,\n setModal: (modal) => {\n entry.modal = modal;\n applyPresentation(entry);\n },\n setPosition: (position) => {\n if (position && (!Number.isFinite(position.x) || !Number.isFinite(position.y))) return;\n entry.position = position;\n applyPresentation(entry);\n },\n requestDismiss: () => requestDismiss(entry),\n setDismissHandler: (handler) => {\n entry.dismissHandler = handler;\n },\n }),\n container,\n );\n applyPresentation(entry);\n applyAccessibleName(dialog, entry);\n applyCancelBehavior(dialog, () => void requestDismiss(entry), cancelBehavior);\n\n if (state.stack.length === 1) {\n if (typeof dialog.showModal === \"function\") {\n if (entry.modal) dialog.showModal();\n else dialog.show();\n } else dialog.setAttribute(\"open\", \"\");\n observeConnection();\n }\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n if (options.signal?.aborted) abort();\n schedule(() => {\n if (state.stack[state.stack.length - 1] === entry) resolveInitialFocusTarget(entry, dialog)?.focus();\n });\n } catch (error) {\n entry.resolve = undefined;\n if (state.stack[state.stack.length - 1] === entry) popTop(undefined);\n reject(error);\n }\n });\n };\n\n const close: DialogCore[\"close\"] = (result) => {\n let first = true;\n while (state.stack.length > 0) {\n popTop(first ? result : undefined);\n first = false;\n }\n };\n\n return {\n open,\n close,\n isOpen: () => state.stack.length > 0,\n };\n};\n\nexport const dialogCore = createDialogCore();\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["feedback/dialog-core.ts"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { getK2bPortalRoot } from \"../internal/portal\";\nimport { resolveUiMessages } from \"../intl/messages\";\nimport { isPointInsideToast } from \"./toast\";\n\nexport type DialogClose<T> = (result?: T) => void;\n\nexport type OpenDialogOptions = {\n /** Close only this dialog when its owning operation is cancelled. */\n signal?: AbortSignal;\n panelClassName?: string;\n contentClassName?: string;\n initialFocus?: \"first-input\" | \"none\" | ((dialog: HTMLDialogElement) => HTMLElement | null);\n cancelBehavior?: \"resolve-undefined\" | \"ignore\";\n ariaLabel?: string;\n};\n\nexport type DialogRender<T> = (\n close: DialogClose<T>,\n context: {\n dialog: HTMLDialogElement;\n /** Switch this entry between a modal and a modeless window without remounting. */\n setModal: (modal: boolean) => void;\n /** Set viewport coordinates, or restore the panel stylesheet position with null. */\n setPosition: (position: { x: number; y: number } | null) => void;\n /** Route Escape/backdrop through the same guarded handler as Cancel and X. */\n setDismissHandler: (handler: () => void | Promise<void>) => void;\n /** Request dismissal through this entry's cancellation policy and guard. */\n requestDismiss: () => Promise<void>;\n },\n) => JSX.Element;\n\nexport type DialogCore = {\n open: <T>(view: DialogRender<T>, options?: OpenDialogOptions) => Promise<T | undefined>;\n close: (result?: unknown) => void;\n isOpen: () => boolean;\n};\n\ntype DialogStackEntry = {\n container: HTMLDivElement;\n dispose?: () => void;\n resolve?: (value: unknown) => void;\n panelClassName: string;\n cancelBehavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>;\n initialFocus: NonNullable<OpenDialogOptions[\"initialFocus\"]>;\n opener?: HTMLElement;\n openerRing: boolean;\n ariaLabel?: string;\n dismissHandler?: () => void | Promise<void>;\n dismissPending?: boolean;\n modal: boolean;\n position?: { x: number; y: number } | null;\n};\n\ntype DialogState = {\n element?: HTMLDialogElement;\n modal?: boolean;\n stack: DialogStackEntry[];\n scrollLocked?: boolean;\n previousBodyOverflow?: string;\n previousHtmlOverflow?: string;\n mouseDownOnDialog?: boolean;\n connectionObserver?: MutationObserver;\n};\n\nconst DEFAULT_PANEL_CLASS = \"k2b-dialog\";\nconst DEFAULT_CONTENT_CLASS = \"k2b-dialog__viewport\";\nlet nextDialogTitleId = 0;\n\nconst resolveInitialFocusTarget = (entry: DialogStackEntry, dialog: HTMLDialogElement): HTMLElement | null => {\n const { initialFocus } = entry;\n if (initialFocus === \"none\") return null;\n if (typeof initialFocus === \"function\") return initialFocus(dialog);\n const input = entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n return (\n input ??\n entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), a[href], [tabindex]:not([tabindex='-1'])\",\n )\n );\n};\n\nconst applyAccessibleName = (dialog: HTMLDialogElement, entry: DialogStackEntry): void => {\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (entry.ariaLabel) {\n dialog.setAttribute(\"aria-label\", entry.ariaLabel);\n return;\n }\n const heading = entry.container.querySelector<HTMLElement>(\"h1, h2, h3\");\n if (!heading) {\n dialog.setAttribute(\"aria-label\", resolveUiMessages().dialog);\n return;\n }\n heading.id ||= `k2b-dialog-title-${++nextDialogTitleId}`;\n dialog.setAttribute(\"aria-labelledby\", heading.id);\n};\n\nconst schedule = (callback: () => void): void => {\n if (typeof requestAnimationFrame === \"function\") requestAnimationFrame(callback);\n else queueMicrotask(callback);\n};\n\n/**\n * Whether focus is still where closing a level left it, on the page or the\n * dialog: nothing took it before the next frame, neither a close handler nor a\n * Tab pressed right after Escape.\n */\nconst focusUnclaimed = (dialog: HTMLDialogElement): boolean => {\n const active = document.activeElement;\n return !active || active === document.body || active === dialog;\n};\n\nexport const createDialogCore = (): DialogCore => {\n const state: DialogState = { stack: [] };\n\n const ensureDialogElement = () => {\n if (typeof document === \"undefined\") throw new Error(\"@k2b/ui dialogs can only be opened in the browser\");\n // Reuse the shared element whenever it is still in the document. Resolving\n // the portal root first would create a second <dialog> when focus has moved\n // into another `.k2b-ui` scope, orphaning the levels already on the stack.\n if (state.element?.isConnected) return state.element;\n\n const element = document.createElement(\"dialog\");\n element.onclose = () => {\n // Repeated Escape can force a non-cancelable native close. A retained\n // entry (ignore, an async guard, or a parent) still owns the modal.\n const top = state.stack[state.stack.length - 1];\n if (state.element !== element || element.open || !top) return;\n if (top.modal) element.showModal();\n else element.show();\n resolveInitialFocusTarget(top, element)?.focus();\n };\n getK2bPortalRoot().appendChild(element);\n state.element = element;\n return element;\n };\n\n const lockPageScroll = () => {\n if (typeof document === \"undefined\" || state.scrollLocked) return;\n state.previousBodyOverflow = document.body.style.overflow;\n state.previousHtmlOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = \"hidden\";\n document.documentElement.style.overflow = \"hidden\";\n state.scrollLocked = true;\n };\n\n const unlockPageScroll = () => {\n if (typeof document === \"undefined\" || !state.scrollLocked) return;\n document.body.style.overflow = state.previousBodyOverflow ?? \"\";\n document.documentElement.style.overflow = state.previousHtmlOverflow ?? \"\";\n state.scrollLocked = false;\n state.previousBodyOverflow = undefined;\n state.previousHtmlOverflow = undefined;\n };\n\n const applyPresentation = (entry: DialogStackEntry) => {\n const dialog = state.element;\n if (!dialog || state.stack[state.stack.length - 1] !== entry) return;\n const position = entry.position;\n dialog.style.position = position ? \"fixed\" : \"\";\n dialog.style.inset = position ? `${position.y}px auto auto ${position.x}px` : \"\";\n dialog.style.margin = position ? \"0\" : \"\";\n dialog.style.transform = position ? \"none\" : \"\";\n dialog.dataset.modeless = String(!entry.modal);\n dialog.setAttribute(\"aria-modal\", String(entry.modal));\n if (dialog.open && state.modal !== entry.modal) {\n const active = document.activeElement;\n dialog.close();\n if (entry.modal) dialog.showModal();\n else dialog.show();\n if (active instanceof HTMLElement && active.isConnected && (!entry.modal || dialog.contains(active))) {\n active.focus({ preventScroll: true });\n } else resolveInitialFocusTarget(entry, dialog)?.focus({ preventScroll: true });\n }\n state.modal = entry.modal;\n if (entry.modal) lockPageScroll();\n else unlockPageScroll();\n };\n\n const modelessEscape = (event: KeyboardEvent) => {\n const top = state.stack[state.stack.length - 1];\n if (!top || top.modal || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n event.preventDefault();\n void requestDismiss(top);\n };\n\n const stopConnectionObserver = () => {\n document.removeEventListener(\"keydown\", modelessEscape);\n state.connectionObserver?.disconnect();\n state.connectionObserver = undefined;\n };\n\n const applyCancelBehavior = (\n dialog: HTMLDialogElement,\n close: () => void,\n behavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>,\n ) => {\n dialog.oncancel = (event) => {\n if (behavior === \"ignore\") {\n event.preventDefault();\n return;\n }\n event.preventDefault();\n close();\n };\n dialog.onmousedown = (event) => {\n state.mouseDownOnDialog = event.target === dialog;\n };\n dialog.onclick = (event) => {\n const realBackdropClick = state.mouseDownOnDialog === true;\n state.mouseDownOnDialog = false;\n if (event.target !== dialog || !state.modal) return;\n if (!realBackdropClick) return;\n if (behavior === \"ignore\") return;\n if (isPointInsideToast(event.clientX, event.clientY)) return;\n close();\n };\n };\n\n const requestDismiss = async (entry: DialogStackEntry) => {\n if (state.stack[state.stack.length - 1] !== entry || entry.dismissPending || entry.cancelBehavior === \"ignore\") return;\n if (!entry.dismissHandler) {\n popTop(undefined);\n return;\n }\n entry.dismissPending = true;\n try {\n await entry.dismissHandler();\n } catch (error) {\n // A failed guard must never discard the dialog's state.\n console.error(\"Dialog dismissal failed\", error);\n } finally {\n entry.dismissPending = false;\n }\n };\n\n const popTop = (result?: unknown) => {\n const top = state.stack.pop();\n if (!top) return;\n top.dispose?.();\n top.container.remove();\n\n const dialog = state.element;\n const previous = state.stack[state.stack.length - 1];\n if (previous && dialog) {\n previous.container.style.display = \"\";\n dialog.className = previous.panelClassName;\n applyPresentation(previous);\n applyAccessibleName(dialog, previous);\n applyCancelBehavior(dialog, () => void requestDismiss(previous), previous.cancelBehavior);\n schedule(() => {\n if (!focusUnclaimed(dialog)) return;\n if (top.opener?.isConnected) returnFocus(top.opener, top.openerRing);\n else resolveInitialFocusTarget(previous, dialog)?.focus();\n });\n } else if (dialog) {\n dialog.oncancel = null;\n dialog.onmousedown = null;\n dialog.onclick = null;\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (dialog.open && typeof dialog.close === \"function\") dialog.close();\n else dialog.removeAttribute(\"open\");\n dialog.remove();\n state.element = undefined;\n stopConnectionObserver();\n unlockPageScroll();\n // After the Escape that closed it: WebKit lights the ring of whatever\n // that key press leaves focused.\n schedule(() => {\n if (top.opener?.isConnected && focusUnclaimed(dialog)) returnFocus(top.opener, top.openerRing);\n });\n }\n\n top.resolve?.(result);\n };\n\n const resetDisconnectedDialog = () => {\n if (state.stack.length === 0 || state.element?.isConnected) return;\n const entries = state.stack.splice(0);\n const dialog = state.element;\n state.element = undefined;\n stopConnectionObserver();\n dialog?.remove();\n unlockPageScroll();\n for (const entry of entries.reverse()) {\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n\n const observeConnection = () => {\n if (state.connectionObserver || typeof MutationObserver === \"undefined\") return;\n document.addEventListener(\"keydown\", modelessEscape);\n state.connectionObserver = new MutationObserver(resetDisconnectedDialog);\n state.connectionObserver.observe(document.documentElement, { childList: true, subtree: true });\n };\n\n const open = <T>(view: DialogRender<T>, options: OpenDialogOptions = {}): Promise<T | undefined> => {\n if (options.signal?.aborted) return Promise.resolve(undefined);\n const dialog = ensureDialogElement();\n const previousTop = state.stack[state.stack.length - 1];\n if (previousTop) previousTop.container.style.display = \"none\";\n const activeElement = document.activeElement;\n\n const panelClassName = options.panelClassName ?? DEFAULT_PANEL_CLASS;\n const cancelBehavior = options.cancelBehavior ?? \"resolve-undefined\";\n const initialFocus = options.initialFocus ?? \"first-input\";\n dialog.className = panelClassName;\n\n const container = document.createElement(\"div\");\n container.className = options.contentClassName ?? DEFAULT_CONTENT_CLASS;\n dialog.appendChild(container);\n\n const entry: DialogStackEntry = {\n container,\n panelClassName,\n cancelBehavior,\n initialFocus,\n opener: activeElement instanceof HTMLElement ? activeElement : undefined,\n openerRing: ringOnReturn(activeElement),\n ariaLabel: options.ariaLabel,\n modal: true,\n };\n\n return new Promise((resolve, reject) => {\n const abort = () => {\n const index = state.stack.indexOf(entry);\n if (index < 0) return;\n if (index === state.stack.length - 1) popTop(undefined);\n else {\n state.stack.splice(index, 1);\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n entry.resolve = (value) => {\n options.signal?.removeEventListener(\"abort\", abort);\n resolve(value as T | undefined);\n };\n const closeTyped: DialogClose<T> = (result) => {\n if (state.stack[state.stack.length - 1] !== entry) return;\n popTop(result);\n };\n\n state.stack.push(entry);\n try {\n entry.dispose = render(\n () =>\n view(closeTyped, {\n dialog,\n setModal: (modal) => {\n entry.modal = modal;\n applyPresentation(entry);\n },\n setPosition: (position) => {\n if (position && (!Number.isFinite(position.x) || !Number.isFinite(position.y))) return;\n entry.position = position;\n applyPresentation(entry);\n },\n requestDismiss: () => requestDismiss(entry),\n setDismissHandler: (handler) => {\n entry.dismissHandler = handler;\n },\n }),\n container,\n );\n applyPresentation(entry);\n applyAccessibleName(dialog, entry);\n applyCancelBehavior(dialog, () => void requestDismiss(entry), cancelBehavior);\n\n if (state.stack.length === 1) {\n // The native dialog returns focus to the element focused when it\n // opened, with a ring of the browser's choosing. Opening from a\n // blurred document leaves the return to popTop and its opener ring.\n if (activeElement instanceof HTMLElement) activeElement.blur();\n if (typeof dialog.showModal === \"function\") {\n if (entry.modal) dialog.showModal();\n else dialog.show();\n } else dialog.setAttribute(\"open\", \"\");\n observeConnection();\n }\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n if (options.signal?.aborted) abort();\n schedule(() => {\n if (state.stack[state.stack.length - 1] === entry) resolveInitialFocusTarget(entry, dialog)?.focus();\n });\n } catch (error) {\n entry.resolve = undefined;\n if (state.stack[state.stack.length - 1] === entry) popTop(undefined);\n reject(error);\n }\n });\n };\n\n const close: DialogCore[\"close\"] = (result) => {\n let first = true;\n while (state.stack.length > 0) {\n popTop(first ? result : undefined);\n first = false;\n }\n };\n\n return {\n open,\n close,\n isOpen: () => state.stack.length > 0,\n };\n};\n\nexport const dialogCore = createDialogCore();\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { dialogCore } from "./dialog-core";
|
|
2
|
+
export { createHoverPreview, HoverPreview } from "./HoverPreview";
|
|
2
3
|
export { default as InlineGuidance } from "./InlineGuidance";
|
|
3
4
|
export { createFormState, DialogHeader, prompts } from "./prompts";
|
|
4
5
|
export { Tooltip } from "./Tooltip";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["feedback/index.ts"],"sourcesContent":["export type { DialogClose, DialogCore, DialogRender, OpenDialogOptions } from \"./dialog-core\";\nexport { dialogCore } from \"./dialog-core\";\nexport type { InlineGuidanceProps } from \"./InlineGuidance\";\nexport { default as InlineGuidance } from \"./InlineGuidance\";\nexport type {\n ConfirmOptions,\n DialogOptions,\n FieldSchema,\n PromptFieldBase,\n PromptSearchInput,\n PromptSearchItem,\n PromptSearchOptions,\n} from \"./prompts\";\nexport { createFormState, DialogHeader, prompts } from \"./prompts\";\nexport type { TooltipAnchorProps, TooltipPlacement, TooltipProps, TooltipTriggerProps } from \"./Tooltip\";\nexport { Tooltip } from \"./Tooltip\";\nexport type { ToastAction, ToastFn, ToastHandle, ToastOptions, ToastVariant } from \"./toast\";\nexport { isPointInsideToast, toast } from \"./toast\";\n"],"mappings":"AACA,SAAS,UAAU,QAAQ,eAAe;AAE1C,SAAS,OAAO,IAAI,cAAc,QAAQ,kBAAkB;AAU5D,SAAS,eAAe,EAAE,YAAY,EAAE,OAAO,QAAQ,WAAW;AAElE,SAAS,OAAO,QAAQ,WAAW;AAEnC,SAAS,kBAAkB,EAAE,KAAK,QAAQ,SAAS","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["feedback/index.ts"],"sourcesContent":["export type { DialogClose, DialogCore, DialogRender, OpenDialogOptions } from \"./dialog-core\";\nexport { dialogCore } from \"./dialog-core\";\nexport type { HoverPreviewController, HoverPreviewOptions, HoverPreviewPlacement, HoverPreviewProps } from \"./HoverPreview\";\nexport { createHoverPreview, HoverPreview } from \"./HoverPreview\";\nexport type { InlineGuidanceProps } from \"./InlineGuidance\";\nexport { default as InlineGuidance } from \"./InlineGuidance\";\nexport type {\n ConfirmOptions,\n DialogOptions,\n FieldSchema,\n PromptFieldBase,\n PromptSearchInput,\n PromptSearchItem,\n PromptSearchOptions,\n} from \"./prompts\";\nexport { createFormState, DialogHeader, prompts } from \"./prompts\";\nexport type { TooltipAnchorProps, TooltipPlacement, TooltipProps, TooltipTriggerProps } from \"./Tooltip\";\nexport { Tooltip } from \"./Tooltip\";\nexport type { ToastAction, ToastFn, ToastHandle, ToastOptions, ToastVariant } from \"./toast\";\nexport { isPointInsideToast, toast } from \"./toast\";\n"],"mappings":"AACA,SAAS,UAAU,QAAQ,eAAe;AAE1C,SAAS,kBAAkB,EAAE,YAAY,QAAQ,gBAAgB;AAEjE,SAAS,OAAO,IAAI,cAAc,QAAQ,kBAAkB;AAU5D,SAAS,eAAe,EAAE,YAAY,EAAE,OAAO,QAAQ,WAAW;AAElE,SAAS,OAAO,QAAQ,WAAW;AAEnC,SAAS,kBAAkB,EAAE,KAAK,QAAQ,SAAS","ignoreList":[]}
|
|
@@ -138,10 +138,6 @@ export function AutocompleteEditor(props) {
|
|
|
138
138
|
const maxHeight = 260;
|
|
139
139
|
const spaceBelow = window.innerHeight - rect.bottom;
|
|
140
140
|
const openAbove = spaceBelow < maxHeight && rect.top > spaceBelow;
|
|
141
|
-
const width = Math.min(280, window.innerWidth - 16);
|
|
142
|
-
const left = Math.min(rect.left, window.innerWidth - width - 8);
|
|
143
|
-
dropdown.style.setProperty("left", `${Math.max(8, left)}px`, "important");
|
|
144
|
-
dropdown.style.setProperty("width", `${width}px`, "important");
|
|
145
141
|
if (openAbove) {
|
|
146
142
|
dropdown.style.setProperty("top", "auto", "important");
|
|
147
143
|
dropdown.style.setProperty("bottom", `${window.innerHeight - rect.top + 4}px`, "important");
|
|
@@ -150,6 +146,11 @@ export function AutocompleteEditor(props) {
|
|
|
150
146
|
dropdown.style.setProperty("bottom", "auto", "important");
|
|
151
147
|
}
|
|
152
148
|
if (!dropdown.matches(":popover-open")) dropdown.showPopover();
|
|
149
|
+
// The list sizes to its suggestions in CSS; measured once shown, it is
|
|
150
|
+
// clamped into the viewport before the next paint.
|
|
151
|
+
const width = dropdown.getBoundingClientRect().width;
|
|
152
|
+
const left = Math.min(rect.left, window.innerWidth - width - 8);
|
|
153
|
+
dropdown.style.setProperty("left", `${Math.max(8, left)}px`, "important");
|
|
153
154
|
};
|
|
154
155
|
const isAbortError = error => error instanceof DOMException ? error.name === "AbortError" : Boolean(error && typeof error === "object" && "name" in error && error.name === "AbortError");
|
|
155
156
|
const applySuggestionList = (context, suggestions) => {
|