@juxtui/ui 0.6.0 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"JTooltip-CAL9lsPF.js","names":["_openBlock","_createBlock","_Teleport","_renderSlot","_createCommentVNode","_sfc_main","_hoisted_1","_openBlock","_createBlock","JPortal","_withCtx","_createVNode","_Transition","_createElementBlock","_normalizeClass","_normalizeStyle","_unref","_renderSlot","_createCommentVNode","_sfc_main","_useModel","_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","JMenuContent","_sfc_main","$slots","_hoisted_1","_hoisted_2","_hoisted_3","_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_createElementBlock","_renderSlot","_createCommentVNode","_createElementVNode","_toDisplayString","_unref","_sfc_main","$slots","_openBlock","_createElementBlock","_normalizeClass","_createBlock","_resolveDynamicComponent","_withCtx","_renderSlot","_createTextVNode","_toDisplayString","_createCommentVNode","_createElementVNode","_createVNode","_Transition","_sfc_main","_openBlock","_createElementBlock","_normalizeClass","_Fragment","_renderList","_toDisplayString","_renderSlot","_sfc_main","_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","_createTextVNode","_toDisplayString","_createCommentVNode","JPortal","_Transition","_normalizeStyle","_sfc_main"],"sources":["../src/utils/dom.ts","../src/icons.ts","../src/composables/useHotkey.ts","../src/composables/useLayer.ts","../src/components/command-palette/search.ts","../src/components/primitives/JPortal.vue","../src/components/primitives/JPortal.vue","../src/components/primitives/JSlot.ts","../src/components/dropdown-menu/context.ts","../src/composables/useFloating.ts","../src/composables/useTypeahead.ts","../src/components/dropdown-menu/JMenuContent.vue","../src/components/dropdown-menu/JMenuContent.vue","../src/components/dropdown-menu/JDropdownMenu.vue","../src/components/dropdown-menu/JDropdownMenu.vue","../src/components/dropdown-menu/JDropdownMenuItem.vue","../src/components/dropdown-menu/JDropdownMenuItem.vue","../src/components/field/JFieldShell.vue","../src/components/field/JFieldShell.vue","../src/components/field/useField.ts","../src/components/kbd/JKbd.vue","../src/components/kbd/JKbd.vue","../src/components/tooltip/JTooltip.vue","../src/components/tooltip/JTooltip.vue"],"sourcesContent":["import type { ComponentPublicInstance, MaybeRef } from 'vue'\r\nimport { unref } from 'vue'\r\n\r\nexport const isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\r\n\r\nexport type MaybeElement = HTMLElement | SVGElement | ComponentPublicInstance | null | undefined\r\n\r\n/** Resolve a template ref that may point at an element or a component instance. */\r\nexport function unrefElement(target: MaybeRef<MaybeElement>): HTMLElement | null {\r\n const value = unref(target)\r\n if (!value) return null\r\n if (value instanceof Element) return value as HTMLElement\r\n const el = (value as ComponentPublicInstance).$el as Node | null\r\n // A component whose root is a fragment exposes a text node as $el.\r\n if (el && el.nodeType !== Node.ELEMENT_NODE) {\r\n const next = el.nextSibling\r\n return next instanceof HTMLElement ? next : null\r\n }\r\n return (el as HTMLElement | null) ?? null\r\n}\r\n\r\nconst FOCUSABLE = [\r\n 'a[href]',\r\n 'area[href]',\r\n 'button:not([disabled])',\r\n 'input:not([disabled]):not([type=\"hidden\"])',\r\n 'select:not([disabled])',\r\n 'textarea:not([disabled])',\r\n 'iframe',\r\n 'audio[controls]',\r\n 'video[controls]',\r\n '[contenteditable]:not([contenteditable=\"false\"])',\r\n '[tabindex]',\r\n].join(',')\r\n\r\nfunction isVisible(el: HTMLElement): boolean {\r\n if (el.hidden) return false\r\n // `checkVisibility` is precise where supported; the rect check covers the rest.\r\n if (typeof el.checkVisibility === 'function') return el.checkVisibility({ visibilityProperty: true })\r\n for (let node: HTMLElement | null = el; node; node = node.parentElement) {\r\n const style = getComputedStyle(node)\r\n if (style.display === 'none' || style.visibility === 'hidden') return false\r\n }\r\n return true\r\n}\r\n\r\n/** Elements that can receive keyboard focus, in DOM order. */\r\nexport function getFocusableElements(container: HTMLElement): HTMLElement[] {\r\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\r\n el => el.tabIndex >= 0 && !el.closest('[inert]') && isVisible(el),\r\n )\r\n}\r\n\r\nexport function focusElement(el: HTMLElement | null | undefined, options?: FocusOptions) {\r\n if (!el) return\r\n el.focus({ preventScroll: true, ...options })\r\n}\r\n\r\nexport const isMac = () => isClient && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent)\r\n\r\nexport function prefersReducedMotion() {\r\n return isClient && window.matchMedia('(prefers-reduced-motion: reduce)').matches\r\n}\r\n","import type { FunctionalComponent, SVGAttributes } from 'vue'\r\nimport { h } from 'vue'\r\n\r\n/*\r\n * The handful of glyphs Juxt needs internally. Drawn on a 16px grid with a\r\n * 1.5px stroke so they sit at the same optical weight as 13–14px text.\r\n */\r\n\r\ntype Icon = FunctionalComponent<SVGAttributes>\r\n\r\nfunction icon(name: string, children: () => ReturnType<typeof h>[], viewBox = '0 0 16 16'): Icon {\r\n const component: Icon = (props) =>\r\n h(\r\n 'svg',\r\n {\r\n 'xmlns': 'http://www.w3.org/2000/svg',\r\n viewBox,\r\n 'width': 16,\r\n 'height': 16,\r\n 'fill': 'none',\r\n 'stroke': 'currentColor',\r\n 'stroke-width': 1.5,\r\n 'stroke-linecap': 'round',\r\n 'stroke-linejoin': 'round',\r\n 'aria-hidden': 'true',\r\n 'focusable': 'false',\r\n ...props,\r\n },\r\n children(),\r\n )\r\n component.displayName = name\r\n return component\r\n}\r\n\r\nexport const IconCheck = icon('IconCheck', () => [h('path', { d: 'M3.5 8.5l3 3 6-7' })])\r\nexport const IconChevronDown = icon('IconChevronDown', () => [h('path', { d: 'M4.5 6.25L8 9.75l3.5-3.5' })])\r\nexport const IconChevronUpDown = icon('IconChevronUpDown', () => [h('path', { d: 'M5.25 6L8 3.25 10.75 6M5.25 10L8 12.75 10.75 10' })])\r\nexport const IconChevronRight = icon('IconChevronRight', () => [h('path', { d: 'M6.25 4.5L9.75 8l-3.5 3.5' })])\r\nexport const IconX = icon('IconX', () => [h('path', { d: 'M4.5 4.5l7 7M11.5 4.5l-7 7' })])\r\nexport const IconSearch = icon('IconSearch', () => [h('circle', { cx: 7, cy: 7, r: 4.25 }), h('path', { d: 'M10.25 10.25L13 13' })])\r\nexport const IconCircleCheck = icon('IconCircleCheck', () => [h('circle', { cx: 8, cy: 8, r: 6.25 }), h('path', { d: 'M5.5 8.25l1.75 1.75L10.5 6.5' })])\r\nexport const IconCircleX = icon('IconCircleX', () => [h('circle', { cx: 8, cy: 8, r: 6.25 }), h('path', { d: 'M6.25 6.25l3.5 3.5M9.75 6.25l-3.5 3.5' })])\r\nexport const IconAlert = icon('IconAlert', () => [\r\n h('path', { d: 'M7.13 2.75a1 1 0 0 1 1.74 0l5.15 9a1 1 0 0 1-.87 1.5H2.85a1 1 0 0 1-.87-1.5z' }),\r\n h('path', { d: 'M8 6.5v2.5' }),\r\n h('path', { 'd': 'M8 11.1v.01', 'stroke-width': 1.75 }),\r\n])\r\nexport const IconInfo = icon('IconInfo', () => [\r\n h('circle', { cx: 8, cy: 8, r: 6.25 }),\r\n h('path', { d: 'M8 7.5v3.25' }),\r\n h('path', { 'd': 'M8 5.25v.01', 'stroke-width': 1.75 }),\r\n])\r\nexport const IconCornerDownLeft = icon('IconCornerDownLeft', () => [h('path', { d: 'M12.5 3.5v4.25a2 2 0 0 1-2 2h-7' }), h('path', { d: 'M6 7l-2.5 2.75L6 12.5' })])\r\nexport const IconChevronLeft = icon('IconChevronLeft', () => [h('path', { d: 'M9.75 4.5L6.25 8l3.5 3.5' })])\r\nexport const IconMoreHorizontal = icon('IconMoreHorizontal', () => [\r\n h('circle', { cx: 3.5, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n h('circle', { cx: 8, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n h('circle', { cx: 12.5, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n])\r\nexport const IconArrowUpRight = icon('IconArrowUpRight', () => [h('path', { d: 'M5 11L11 5M5.5 5h5.5v5.5' })])\r\nexport const IconArrowDownRight = icon('IconArrowDownRight', () => [h('path', { d: 'M5 5l6 6M10.5 11H5V5.5' })])\r\n\r\n/** The loading spinner used across Juxt. A quarter arc over a faint track. */\r\nexport const Spinner: FunctionalComponent<{ size?: number }> = (props) => {\r\n const size = props.size ?? 16\r\n return h(\r\n 'svg',\r\n { 'class': 'j-spinner', 'viewBox': '0 0 16 16', 'width': size, 'height': size, 'aria-hidden': 'true', 'focusable': 'false' },\r\n [\r\n h('circle', { 'class': 'j-spinner__track', 'cx': 8, 'cy': 8, 'r': 6, 'stroke-width': 1.75 }),\r\n h('circle', { 'cx': 8, 'cy': 8, 'r': 6, 'stroke-width': 1.75, 'stroke-dasharray': '9.5 28', 'stroke-dashoffset': 0 }),\r\n ],\r\n )\r\n}\r\nSpinner.displayName = 'JSpinner'\r\n","import type { MaybeRefOrGetter } from 'vue'\nimport { onBeforeUnmount, onMounted, toValue } from 'vue'\nimport { isMac } from '../utils/dom'\n\n/**\n * Parse a shortcut such as `mod+k`, `shift+/` or `alt+t`.\n * `mod` is ⌘ on Apple platforms and Ctrl elsewhere.\n */\nexport function matchesHotkey(event: KeyboardEvent, hotkey: string): boolean {\n const parts = hotkey.toLowerCase().split('+').map(part => part.trim())\n const key = parts.pop()\n if (!key) return false\n const mac = isMac()\n const want = {\n meta: parts.includes('meta') || (mac && parts.includes('mod')),\n ctrl: parts.includes('ctrl') || (!mac && parts.includes('mod')),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n }\n if (event.metaKey !== want.meta || event.ctrlKey !== want.ctrl || event.altKey !== want.alt || event.shiftKey !== want.shift)\n return false\n // `code` survives keyboard layouts and Alt/Option remapping.\n const code = event.code.toLowerCase()\n return event.key.toLowerCase() === key || code === `key${key}` || code === `digit${key}`\n}\n\n/** Human-readable parts of a shortcut, e.g. `mod+k` → `['⌘', 'K']`. */\nexport function formatHotkey(hotkey: string): string[] {\n const mac = isMac()\n const labels: Record<string, string> = mac\n ? { mod: '⌘', meta: '⌘', ctrl: '⌃', alt: '⌥', shift: '⇧', enter: '↵', escape: 'Esc' }\n : { mod: 'Ctrl', meta: 'Win', ctrl: 'Ctrl', alt: 'Alt', shift: 'Shift', enter: 'Enter', escape: 'Esc' }\n return hotkey.split('+').map((part) => {\n const lower = part.trim().toLowerCase()\n return labels[lower] ?? (lower.length === 1 ? lower.toUpperCase() : part.trim())\n })\n}\n\n/** Run `handler` whenever the shortcut is pressed anywhere on the page. */\nexport function useHotkey(hotkey: MaybeRefOrGetter<string | false | undefined>, handler: (event: KeyboardEvent) => void) {\n function onKeydown(event: KeyboardEvent) {\n const value = toValue(hotkey)\n // A focused component (e.g. the editor binding ⌘K to \"link\") already handled it.\n if (!value || event.repeat || event.isComposing || event.defaultPrevented) return\n if (!matchesHotkey(event, value)) return\n event.preventDefault()\n handler(event)\n }\n onMounted(() => document.addEventListener('keydown', onKeydown))\n onBeforeUnmount(() => document.removeEventListener('keydown', onKeydown))\n}\n","import type { Ref } from 'vue'\nimport { onBeforeUnmount, watch } from 'vue'\nimport { isClient } from '../utils/dom'\n\nexport interface LayerOptions {\n /** The layer is registered only while this is true. */\n active: Readonly<Ref<boolean>>\n /** Elements that count as \"inside\" the layer. */\n elements: () => Array<HTMLElement | null | undefined>\n onEscape?: (event: KeyboardEvent) => void\n /** Called when a pointer goes down outside every element of the top-most layer. */\n onPointerDownOutside?: (event: PointerEvent) => void\n}\n\ninterface Layer {\n options: LayerOptions\n}\n\n/*\n * Overlays stack. A select inside a dialog, a submenu inside a menu, a tooltip\n * inside anything: Escape and outside clicks belong to whichever layer is on\n * top, and only to that one.\n */\nconst layers: Layer[] = []\nlet listening = false\n\nfunction top() {\n return layers[layers.length - 1]\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (event.key !== 'Escape' || event.defaultPrevented || event.isComposing) return\n const layer = top()\n if (!layer?.options.onEscape) return\n event.preventDefault()\n event.stopPropagation()\n layer.options.onEscape(event)\n}\n\nfunction onPointerDown(event: PointerEvent) {\n const layer = top()\n if (!layer?.options.onPointerDownOutside) return\n const target = event.target as Node | null\n if (!target) return\n if ((target as HTMLElement).closest?.('[data-juxt-layer-ignore]')) return\n const inside = layer.options.elements().some(el => el?.contains(target))\n if (!inside) layer.options.onPointerDownOutside(event)\n}\n\nfunction listen() {\n if (listening || !isClient) return\n document.addEventListener('keydown', onKeydown)\n document.addEventListener('pointerdown', onPointerDown, true)\n listening = true\n}\n\nfunction unlisten() {\n if (!listening || layers.length > 0) return\n document.removeEventListener('keydown', onKeydown)\n document.removeEventListener('pointerdown', onPointerDown, true)\n listening = false\n}\n\nexport function useLayer(options: LayerOptions) {\n const layer: Layer = { options }\n\n const add = () => {\n if (layers.includes(layer)) return\n layers.push(layer)\n listen()\n }\n\n const remove = () => {\n const index = layers.indexOf(layer)\n if (index === -1) return\n layers.splice(index, 1)\n unlisten()\n }\n\n if (isClient) {\n watch(options.active, value => (value ? add() : remove()), { immediate: true })\n onBeforeUnmount(remove)\n }\n\n return {\n isTopLayer: () => top() === layer,\n }\n}\n","/**\r\n * Ranking for the command palette. Cheap enough to run on every keystroke\r\n * over a few thousand items, and ordered the way people expect:\r\n * exact › prefix › word start › substring › in-order letters.\r\n */\r\n\r\nexport type MatchRange = [start: number, end: number]\r\n\r\nexport interface MatchResult {\r\n score: number\r\n ranges: MatchRange[]\r\n}\r\n\r\nconst NO_MATCH: MatchResult = { score: 0, ranges: [] }\r\n\r\nexport function matchText(query: string, text: string): MatchResult {\r\n const q = query.trim().toLowerCase()\r\n if (!q) return { score: 1, ranges: [] }\r\n const t = text.toLowerCase()\r\n if (!t) return NO_MATCH\r\n\r\n if (t === q) return { score: 1000, ranges: [[0, t.length]] }\r\n if (t.startsWith(q)) return { score: 900 - Math.min(t.length - q.length, 100), ranges: [[0, q.length]] }\r\n\r\n const wordStart = findWordStart(t, q)\r\n if (wordStart > 0) return { score: 700 - Math.min(wordStart, 100), ranges: [[wordStart, wordStart + q.length]] }\r\n\r\n const index = t.indexOf(q)\r\n if (index > 0) return { score: 500 - Math.min(index, 100), ranges: [[index, index + q.length]] }\r\n\r\n return subsequence(q, t)\r\n}\r\n\r\nfunction findWordStart(t: string, q: string): number {\r\n let from = 0\r\n while (from < t.length) {\r\n const index = t.indexOf(q, from)\r\n if (index === -1) return -1\r\n if (index > 0 && /[\\s\\-_/.:]/.test(t[index - 1]!)) return index\r\n from = index + 1\r\n }\r\n return -1\r\n}\r\n\r\n/** Letters in order, not necessarily adjacent | \"gtst\" finds \"Go to settings\". */\r\nfunction subsequence(q: string, t: string): MatchResult {\r\n const ranges: MatchRange[] = []\r\n let ti = 0\r\n let score = 100\r\n let previous = -2\r\n for (const char of q) {\r\n if (char === ' ') continue\r\n const found = t.indexOf(char, ti)\r\n if (found === -1) return NO_MATCH\r\n if (found === previous + 1 && ranges.length) {\r\n ranges[ranges.length - 1]![1] = found + 1\r\n score += 12\r\n } else {\r\n ranges.push([found, found + 1])\r\n if (found === 0 || /[\\s\\-_/.:]/.test(t[found - 1]!)) score += 8\r\n }\r\n // Spread-out matches rank lower.\r\n score -= Math.min(found - ti, 10)\r\n previous = found\r\n ti = found + 1\r\n }\r\n return { score: Math.max(score, 1), ranges }\r\n}\r\n\r\n/** Split text into highlighted and plain runs. */\r\nexport function splitByRanges(text: string, ranges: MatchRange[]): Array<{ text: string, match: boolean }> {\r\n if (!ranges.length) return [{ text, match: false }]\r\n const parts: Array<{ text: string, match: boolean }> = []\r\n let cursor = 0\r\n for (const [start, end] of ranges) {\r\n if (start > cursor) parts.push({ text: text.slice(cursor, start), match: false })\r\n parts.push({ text: text.slice(start, end), match: true })\r\n cursor = end\r\n }\r\n if (cursor < text.length) parts.push({ text: text.slice(cursor), match: false })\r\n return parts\r\n}\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: teleports its content to `<body>`, but only once mounted.\r\n *\r\n * Server-rendered teleports to `body` never make it into the HTML, so a plain\r\n * `<Teleport>` hydrates against nothing and warns. Rendering nothing until\r\n * mount keeps server and client output identical | and overlays are closed on\r\n * first paint anyway.\r\n */\r\nimport { onMounted, ref } from 'vue'\r\n\r\nwithDefaults(defineProps<{ to?: string }>(), { to: 'body' })\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n</script>\r\n\r\n<template>\r\n <Teleport v-if=\"mounted\" :to=\"to\">\r\n <slot />\r\n </Teleport>\r\n</template>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: teleports its content to `<body>`, but only once mounted.\r\n *\r\n * Server-rendered teleports to `body` never make it into the HTML, so a plain\r\n * `<Teleport>` hydrates against nothing and warns. Rendering nothing until\r\n * mount keeps server and client output identical | and overlays are closed on\r\n * first paint anyway.\r\n */\r\nimport { onMounted, ref } from 'vue'\r\n\r\nwithDefaults(defineProps<{ to?: string }>(), { to: 'body' })\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n</script>\r\n\r\n<template>\r\n <Teleport v-if=\"mounted\" :to=\"to\">\r\n <slot />\r\n </Teleport>\r\n</template>\r\n","import type { VNode } from 'vue'\r\nimport { cloneVNode, Comment, defineComponent, Fragment, h, Text } from 'vue'\r\n\r\nfunction firstElement(nodes: VNode[] | undefined): VNode | undefined {\r\n if (!nodes) return undefined\r\n for (const node of nodes) {\r\n if (node.type === Comment) continue\r\n if (node.type === Fragment && Array.isArray(node.children)) {\r\n const found = firstElement(node.children as VNode[])\r\n if (found) return found\r\n continue\r\n }\r\n if (node.type === Text) {\r\n if (typeof node.children === 'string' && node.children.trim() === '') continue\r\n // Bare text can't hold attributes; give it an element.\r\n return h('span', null, node.children as string)\r\n }\r\n return node\r\n }\r\n return undefined\r\n}\r\n\r\n/**\r\n * Internal: renders its first child element and merges its own attributes\r\n * (ARIA, listeners, ids) onto it | no wrapper element.\r\n */\r\nexport const JSlot = defineComponent({\r\n name: 'JSlot',\r\n inheritAttrs: false,\r\n setup(_, { slots, attrs }) {\r\n return () => {\r\n const child = firstElement(slots.default?.())\r\n if (!child) return null\r\n // The consumer's own id wins; everything else is merged.\r\n const { id, ...rest } = attrs\r\n return cloneVNode(child, child.props?.id ? rest : { id, ...rest }, true)\r\n }\r\n },\r\n})\r\n","import type { InjectionKey, Ref } from 'vue'\r\n\r\nexport interface MenuRootContext {\r\n /** Close the whole menu tree. */\r\n close: (restoreFocus?: boolean) => void\r\n}\r\n\r\nexport interface MenuLevelContext {\r\n content: Ref<HTMLElement | null>\r\n /** Id of the submenu currently open at this level. */\r\n openSub: Ref<string | null>\r\n setOpenSub: (id: string | null) => void\r\n /** Close the open submenu shortly, unless the pointer is on its way into it. */\r\n scheduleSubClose: () => void\r\n cancelSubClose: () => void\r\n}\r\n\r\nexport const MENU_ROOT: InjectionKey<MenuRootContext> = Symbol('JDropdownMenu')\r\nexport const MENU_LEVEL: InjectionKey<MenuLevelContext> = Symbol('JDropdownMenuLevel')\r\n\r\nexport function getMenuItems(content: HTMLElement | null): HTMLElement[] {\r\n if (!content) return []\r\n return Array.from(content.querySelectorAll<HTMLElement>('[role^=\"menuitem\"]:not([aria-disabled=\"true\"])'))\r\n}\r\n","import type { Placement } from '@floating-ui/dom'\r\nimport type { CSSProperties, Ref } from 'vue'\r\nimport { autoUpdate, computePosition, flip, offset, shift, size } from '@floating-ui/dom'\r\nimport { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'\r\n\r\nexport type { Placement }\r\n\r\nexport interface FloatingOptions {\r\n placement?: Placement\r\n /** Gap between reference and floating element, in px. */\r\n offset?: number | { mainAxis?: number, crossAxis?: number }\r\n /** Make the floating element at least as wide as the reference. */\r\n matchWidth?: boolean\r\n /** Padding kept from the viewport edge, in px. */\r\n padding?: number\r\n}\r\n\r\nconst ORIGIN: Record<string, string> = {\r\n top: 'bottom',\r\n bottom: 'top',\r\n left: 'right',\r\n right: 'left',\r\n}\r\n\r\n/**\r\n * Position a floating element next to a reference element and keep it there\r\n * through scroll and resize. Coordinates are written to `left`/`top` so\r\n * `transform` stays free for enter/leave motion.\r\n */\r\nexport function useFloating(\r\n reference: Ref<HTMLElement | null>,\r\n floating: Ref<HTMLElement | null>,\r\n options: FloatingOptions | (() => FloatingOptions) = {},\r\n) {\r\n const read = () => (typeof options === 'function' ? options() : options)\r\n const x = ref(0)\r\n const y = ref(0)\r\n const placement = ref<Placement>(read().placement ?? 'bottom-start')\r\n const availableHeight = ref<number>()\r\n const referenceWidth = ref<number>()\r\n const stop = shallowRef<() => void>()\r\n\r\n async function update() {\r\n const referenceEl = reference.value\r\n const floatingEl = floating.value\r\n if (!referenceEl || !floatingEl) return\r\n const opts = read()\r\n const padding = opts.padding ?? 8\r\n const result = await computePosition(referenceEl, floatingEl, {\r\n strategy: 'fixed',\r\n placement: opts.placement ?? 'bottom-start',\r\n middleware: [\r\n offset(opts.offset ?? 6),\r\n flip({ padding }),\r\n shift({ padding }),\r\n size({\r\n padding,\r\n apply({ availableHeight: height, rects }) {\r\n availableHeight.value = Math.max(120, Math.floor(height))\r\n referenceWidth.value = rects.reference.width\r\n },\r\n }),\r\n ],\r\n })\r\n x.value = Math.round(result.x)\r\n y.value = Math.round(result.y)\r\n placement.value = result.placement\r\n }\r\n\r\n watch(\r\n [reference, floating],\r\n ([referenceEl, floatingEl]) => {\r\n stop.value?.()\r\n stop.value = undefined\r\n if (referenceEl && floatingEl) stop.value = autoUpdate(referenceEl, floatingEl, update)\r\n },\r\n { flush: 'post' },\r\n )\r\n\r\n onBeforeUnmount(() => stop.value?.())\r\n\r\n const side = computed(() => placement.value.split('-')[0] as 'top' | 'bottom' | 'left' | 'right')\r\n\r\n const styles = computed<CSSProperties>(() => {\r\n const align = placement.value.split('-')[1]\r\n const cross = side.value === 'top' || side.value === 'bottom'\r\n ? (align === 'start' ? 'left' : align === 'end' ? 'right' : 'center')\r\n : (align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center')\r\n const origin = side.value === 'top' || side.value === 'bottom'\r\n ? `${cross} ${ORIGIN[side.value]}`\r\n : `${ORIGIN[side.value]} ${cross}`\r\n const dir = side.value === 'top' ? 1 : side.value === 'bottom' ? -1 : 0\r\n return {\r\n 'position': 'fixed',\r\n 'left': `${x.value}px`,\r\n 'top': `${y.value}px`,\r\n 'transformOrigin': origin,\r\n 'minWidth': read().matchWidth && referenceWidth.value ? `${referenceWidth.value}px` : undefined,\r\n '--j-available-height': availableHeight.value ? `${availableHeight.value}px` : undefined,\r\n '--j-pop-dir': String(dir),\r\n '--j-pop-x': String(side.value === 'left' ? 1 : side.value === 'right' ? -1 : 0),\r\n } as CSSProperties\r\n })\r\n\r\n return { x, y, placement, side, styles, update }\r\n}\r\n","/**\r\n * Type-to-jump for lists. Characters typed in quick succession form a query;\r\n * repeating the same letter cycles through matches.\r\n */\r\nexport function useTypeahead(timeout = 500) {\r\n let query = ''\r\n let timer: ReturnType<typeof setTimeout> | undefined\r\n\r\n function search<T>(key: string, items: T[], getLabel: (item: T) => string, currentIndex: number): number {\r\n if (key.length !== 1 || (key === ' ' && query === '')) return -1\r\n clearTimeout(timer)\r\n timer = setTimeout(() => (query = ''), timeout)\r\n query += key.toLowerCase()\r\n\r\n const repeated = query.length > 1 && [...query].every(char => char === query[0])\r\n const needle = repeated ? query[0]! : query\r\n // A fresh search starts after the current item so repeated keys cycle.\r\n const start = repeated || query.length === 1 ? currentIndex + 1 : currentIndex\r\n for (let i = 0; i < items.length; i++) {\r\n const index = (start + i + items.length) % items.length\r\n if (getLabel(items[index]!).trim().toLowerCase().startsWith(needle)) return index\r\n }\r\n return -1\r\n }\r\n\r\n const isSearching = () => query.length > 0\r\n\r\n return { search, isSearching }\r\n}\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: the floating list shared by the root menu and submenus.\r\n * Owns positioning, keyboard navigation, typeahead and the layer.\r\n */\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport type { MenuLevelContext } from './context'\r\nimport { inject, nextTick, provide, ref, toRef, watch } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { useTypeahead } from '../../composables/useTypeahead'\r\nimport { focusElement } from '../../utils/dom'\r\nimport JPortal from '../primitives/JPortal.vue'\r\nimport { getMenuItems, MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nconst props = defineProps<{\r\n open: boolean\r\n reference: HTMLElement | null\r\n id: string\r\n labelledby?: string\r\n placement: Placement\r\n offset: number | { mainAxis?: number, crossAxis?: number }\r\n /** What to focus once open. */\r\n initialFocus: 'first' | 'last' | 'content' | 'none'\r\n isSub?: boolean\r\n}>()\r\n\r\nconst emit = defineEmits<{\r\n escape: []\r\n outside: [event: PointerEvent]\r\n /** Submenus only: ArrowLeft asks to go back to the parent. */\r\n back: []\r\n pointerenter: []\r\n}>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst content = ref<HTMLElement | null>(null)\r\nconst reference = toRef(props, 'reference')\r\n\r\nconst { styles } = useFloating(reference, content, () => ({ placement: props.placement, offset: props.offset }))\r\nconst typeahead = useTypeahead()\r\n\r\nuseLayer({\r\n active: toRef(props, 'open'),\r\n elements: () => [content.value, props.reference],\r\n onEscape: () => emit('escape'),\r\n onPointerDownOutside: event => emit('outside', event),\r\n})\r\n\r\n// Level context for the items inside this list.\r\nconst openSub = ref<string | null>(null)\r\nlet subTimer: ReturnType<typeof setTimeout> | undefined\r\nconst level: MenuLevelContext = {\r\n content,\r\n openSub,\r\n setOpenSub: (id) => {\r\n clearTimeout(subTimer)\r\n openSub.value = id\r\n },\r\n scheduleSubClose: () => {\r\n if (!openSub.value) return\r\n clearTimeout(subTimer)\r\n subTimer = setTimeout(() => (openSub.value = null), 180)\r\n },\r\n cancelSubClose: () => clearTimeout(subTimer),\r\n}\r\nprovide(MENU_LEVEL, level)\r\n\r\nwatch(\r\n () => props.open,\r\n async (value) => {\r\n if (!value) {\r\n openSub.value = null\r\n return\r\n }\r\n if (props.initialFocus === 'none') return\r\n await nextTick()\r\n const items = getMenuItems(content.value)\r\n if (props.initialFocus === 'first') focusElement(items[0] ?? content.value)\r\n else if (props.initialFocus === 'last') focusElement(items[items.length - 1] ?? content.value)\r\n else focusElement(content.value)\r\n },\r\n { flush: 'post' },\r\n)\r\n\r\nfunction move(delta: 1 | -1 | 'first' | 'last') {\r\n const items = getMenuItems(content.value)\r\n if (items.length === 0) return\r\n const current = items.indexOf(document.activeElement as HTMLElement)\r\n let next: number\r\n if (delta === 'first') next = 0\r\n else if (delta === 'last') next = items.length - 1\r\n else if (current === -1) next = delta === 1 ? 0 : items.length - 1\r\n else next = (current + delta + items.length) % items.length\r\n focusElement(items[next])\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n const { key } = event\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault()\r\n move(1)\r\n break\r\n case 'ArrowUp':\r\n event.preventDefault()\r\n move(-1)\r\n break\r\n case 'Home':\r\n case 'PageUp':\r\n event.preventDefault()\r\n move('first')\r\n break\r\n case 'End':\r\n case 'PageDown':\r\n event.preventDefault()\r\n move('last')\r\n break\r\n case 'ArrowLeft':\r\n if (props.isSub) {\r\n event.preventDefault()\r\n emit('back')\r\n }\r\n break\r\n case 'Tab':\r\n event.preventDefault()\r\n root.close(true)\r\n break\r\n case 'Enter':\r\n case ' ': {\r\n const active = document.activeElement as HTMLElement | null\r\n if (active && active !== content.value && content.value?.contains(active)) {\r\n event.preventDefault()\r\n active.click()\r\n }\r\n break\r\n }\r\n default:\r\n if (key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\r\n const items = getMenuItems(content.value)\r\n const index = typeahead.search(key, items, item => item.textContent ?? '', items.indexOf(document.activeElement as HTMLElement))\r\n if (index >= 0) focusElement(items[index])\r\n }\r\n }\r\n}\r\n\r\ndefineExpose({ content })\r\n</script>\r\n\r\n<template>\r\n <JPortal>\r\n <Transition name=\"j-pop\">\r\n <div\r\n v-if=\"open\"\r\n :id=\"id\"\r\n ref=\"content\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n class=\"j-menu j-popover-surface\"\r\n :class=\"{ 'j-menu--sub': isSub }\"\r\n :style=\"styles\"\r\n :aria-labelledby=\"labelledby\"\r\n aria-orientation=\"vertical\"\r\n @keydown=\"onKeydown\"\r\n @pointerenter=\"emit('pointerenter')\"\r\n >\r\n <slot />\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-menu {\r\n z-index: var(--juxt-z-popover);\r\n box-sizing: border-box;\r\n min-width: 11rem;\r\n max-width: calc(100vw - 16px);\r\n max-height: var(--j-available-height, 24rem);\r\n padding: var(--juxt-space-1);\r\n overflow-y: auto;\r\n overscroll-behavior: contain;\r\n outline: none;\r\n}\r\n\r\n.j-menu__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--juxt-space-2);\r\n min-height: var(--juxt-control-sm);\r\n padding: 0 var(--juxt-space-2);\r\n border-radius: var(--juxt-radius-xs);\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-md);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n text-decoration: none;\r\n cursor: pointer;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.j-menu__item:focus,\r\n.j-menu__item[aria-expanded='true'] {\r\n background: var(--juxt-surface-hover);\r\n}\r\n\r\n.j-menu__item[aria-disabled='true'] {\r\n color: var(--juxt-fg-disabled);\r\n cursor: not-allowed;\r\n}\r\n\r\n.j-menu__item--destructive {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-menu__item--destructive:focus {\r\n background: var(--juxt-danger-soft);\r\n}\r\n\r\n.j-menu__icon {\r\n display: inline-flex;\r\n flex: none;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__icon > svg {\r\n width: 1rem;\r\n height: 1rem;\r\n}\r\n\r\n.j-menu__item:focus .j-menu__icon {\r\n color: var(--juxt-fg-secondary);\r\n}\r\n\r\n.j-menu__item--destructive .j-menu__icon {\r\n color: inherit;\r\n}\r\n\r\n.j-menu__text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.j-menu__shortcut {\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n letter-spacing: 0.04em;\r\n}\r\n\r\n.j-menu__check {\r\n flex: none;\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-accent-text);\r\n opacity: 0;\r\n}\r\n\r\n.j-menu__check.is-checked {\r\n opacity: 1;\r\n}\r\n\r\n.j-menu__chevron {\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-right: -0.125rem;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__separator {\r\n height: 1px;\r\n margin: var(--juxt-space-1) calc(var(--juxt-space-1) * -1);\r\n background: var(--juxt-border-subtle);\r\n}\r\n\r\n.dark .j-menu__separator,\r\n[data-theme='dark'] .j-menu__separator {\r\n background: var(--juxt-border);\r\n}\r\n\r\n.j-menu__label {\r\n padding: var(--juxt-space-1-5) var(--juxt-space-2) var(--juxt-space-1);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: the floating list shared by the root menu and submenus.\r\n * Owns positioning, keyboard navigation, typeahead and the layer.\r\n */\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport type { MenuLevelContext } from './context'\r\nimport { inject, nextTick, provide, ref, toRef, watch } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { useTypeahead } from '../../composables/useTypeahead'\r\nimport { focusElement } from '../../utils/dom'\r\nimport JPortal from '../primitives/JPortal.vue'\r\nimport { getMenuItems, MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nconst props = defineProps<{\r\n open: boolean\r\n reference: HTMLElement | null\r\n id: string\r\n labelledby?: string\r\n placement: Placement\r\n offset: number | { mainAxis?: number, crossAxis?: number }\r\n /** What to focus once open. */\r\n initialFocus: 'first' | 'last' | 'content' | 'none'\r\n isSub?: boolean\r\n}>()\r\n\r\nconst emit = defineEmits<{\r\n escape: []\r\n outside: [event: PointerEvent]\r\n /** Submenus only: ArrowLeft asks to go back to the parent. */\r\n back: []\r\n pointerenter: []\r\n}>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst content = ref<HTMLElement | null>(null)\r\nconst reference = toRef(props, 'reference')\r\n\r\nconst { styles } = useFloating(reference, content, () => ({ placement: props.placement, offset: props.offset }))\r\nconst typeahead = useTypeahead()\r\n\r\nuseLayer({\r\n active: toRef(props, 'open'),\r\n elements: () => [content.value, props.reference],\r\n onEscape: () => emit('escape'),\r\n onPointerDownOutside: event => emit('outside', event),\r\n})\r\n\r\n// Level context for the items inside this list.\r\nconst openSub = ref<string | null>(null)\r\nlet subTimer: ReturnType<typeof setTimeout> | undefined\r\nconst level: MenuLevelContext = {\r\n content,\r\n openSub,\r\n setOpenSub: (id) => {\r\n clearTimeout(subTimer)\r\n openSub.value = id\r\n },\r\n scheduleSubClose: () => {\r\n if (!openSub.value) return\r\n clearTimeout(subTimer)\r\n subTimer = setTimeout(() => (openSub.value = null), 180)\r\n },\r\n cancelSubClose: () => clearTimeout(subTimer),\r\n}\r\nprovide(MENU_LEVEL, level)\r\n\r\nwatch(\r\n () => props.open,\r\n async (value) => {\r\n if (!value) {\r\n openSub.value = null\r\n return\r\n }\r\n if (props.initialFocus === 'none') return\r\n await nextTick()\r\n const items = getMenuItems(content.value)\r\n if (props.initialFocus === 'first') focusElement(items[0] ?? content.value)\r\n else if (props.initialFocus === 'last') focusElement(items[items.length - 1] ?? content.value)\r\n else focusElement(content.value)\r\n },\r\n { flush: 'post' },\r\n)\r\n\r\nfunction move(delta: 1 | -1 | 'first' | 'last') {\r\n const items = getMenuItems(content.value)\r\n if (items.length === 0) return\r\n const current = items.indexOf(document.activeElement as HTMLElement)\r\n let next: number\r\n if (delta === 'first') next = 0\r\n else if (delta === 'last') next = items.length - 1\r\n else if (current === -1) next = delta === 1 ? 0 : items.length - 1\r\n else next = (current + delta + items.length) % items.length\r\n focusElement(items[next])\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n const { key } = event\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault()\r\n move(1)\r\n break\r\n case 'ArrowUp':\r\n event.preventDefault()\r\n move(-1)\r\n break\r\n case 'Home':\r\n case 'PageUp':\r\n event.preventDefault()\r\n move('first')\r\n break\r\n case 'End':\r\n case 'PageDown':\r\n event.preventDefault()\r\n move('last')\r\n break\r\n case 'ArrowLeft':\r\n if (props.isSub) {\r\n event.preventDefault()\r\n emit('back')\r\n }\r\n break\r\n case 'Tab':\r\n event.preventDefault()\r\n root.close(true)\r\n break\r\n case 'Enter':\r\n case ' ': {\r\n const active = document.activeElement as HTMLElement | null\r\n if (active && active !== content.value && content.value?.contains(active)) {\r\n event.preventDefault()\r\n active.click()\r\n }\r\n break\r\n }\r\n default:\r\n if (key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\r\n const items = getMenuItems(content.value)\r\n const index = typeahead.search(key, items, item => item.textContent ?? '', items.indexOf(document.activeElement as HTMLElement))\r\n if (index >= 0) focusElement(items[index])\r\n }\r\n }\r\n}\r\n\r\ndefineExpose({ content })\r\n</script>\r\n\r\n<template>\r\n <JPortal>\r\n <Transition name=\"j-pop\">\r\n <div\r\n v-if=\"open\"\r\n :id=\"id\"\r\n ref=\"content\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n class=\"j-menu j-popover-surface\"\r\n :class=\"{ 'j-menu--sub': isSub }\"\r\n :style=\"styles\"\r\n :aria-labelledby=\"labelledby\"\r\n aria-orientation=\"vertical\"\r\n @keydown=\"onKeydown\"\r\n @pointerenter=\"emit('pointerenter')\"\r\n >\r\n <slot />\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-menu {\r\n z-index: var(--juxt-z-popover);\r\n box-sizing: border-box;\r\n min-width: 11rem;\r\n max-width: calc(100vw - 16px);\r\n max-height: var(--j-available-height, 24rem);\r\n padding: var(--juxt-space-1);\r\n overflow-y: auto;\r\n overscroll-behavior: contain;\r\n outline: none;\r\n}\r\n\r\n.j-menu__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--juxt-space-2);\r\n min-height: var(--juxt-control-sm);\r\n padding: 0 var(--juxt-space-2);\r\n border-radius: var(--juxt-radius-xs);\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-md);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n text-decoration: none;\r\n cursor: pointer;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.j-menu__item:focus,\r\n.j-menu__item[aria-expanded='true'] {\r\n background: var(--juxt-surface-hover);\r\n}\r\n\r\n.j-menu__item[aria-disabled='true'] {\r\n color: var(--juxt-fg-disabled);\r\n cursor: not-allowed;\r\n}\r\n\r\n.j-menu__item--destructive {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-menu__item--destructive:focus {\r\n background: var(--juxt-danger-soft);\r\n}\r\n\r\n.j-menu__icon {\r\n display: inline-flex;\r\n flex: none;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__icon > svg {\r\n width: 1rem;\r\n height: 1rem;\r\n}\r\n\r\n.j-menu__item:focus .j-menu__icon {\r\n color: var(--juxt-fg-secondary);\r\n}\r\n\r\n.j-menu__item--destructive .j-menu__icon {\r\n color: inherit;\r\n}\r\n\r\n.j-menu__text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.j-menu__shortcut {\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n letter-spacing: 0.04em;\r\n}\r\n\r\n.j-menu__check {\r\n flex: none;\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-accent-text);\r\n opacity: 0;\r\n}\r\n\r\n.j-menu__check.is-checked {\r\n opacity: 1;\r\n}\r\n\r\n.j-menu__chevron {\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-right: -0.125rem;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__separator {\r\n height: 1px;\r\n margin: var(--juxt-space-1) calc(var(--juxt-space-1) * -1);\r\n background: var(--juxt-border-subtle);\r\n}\r\n\r\n.dark .j-menu__separator,\r\n[data-theme='dark'] .j-menu__separator {\r\n background: var(--juxt-border);\r\n}\r\n\r\n.j-menu__label {\r\n padding: var(--juxt-space-1-5) var(--juxt-space-2) var(--juxt-space-1);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport { computed, nextTick, provide, ref, useId } from 'vue'\r\nimport { focusElement, unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport { MENU_ROOT } from './context'\r\nimport JMenuContent from './JMenuContent.vue'\r\n\r\nexport interface DropdownMenuProps {\r\n placement?: Placement\r\n /** Distance from the trigger, in px. */\r\n offset?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuProps>(), {\r\n placement: 'bottom-start',\r\n offset: 6,\r\n})\r\n\r\nconst open = defineModel<boolean>('open', { default: false })\r\n\r\ndefineSlots<{\r\n /** The element that opens the menu | usually a `JButton`. */\r\n trigger?: (props: { open: boolean }) => unknown\r\n default?: () => unknown\r\n}>()\r\n\r\nconst id = useId()\r\nconst triggerId = `j-${id}-trigger`\r\nconst menuId = `j-${id}-menu`\r\n\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst initialFocus = ref<'first' | 'last' | 'content'>('content')\r\n\r\nfunction show(focus: 'first' | 'last' | 'content') {\r\n if (props.disabled) return\r\n initialFocus.value = focus\r\n open.value = true\r\n}\r\n\r\nfunction close(restoreFocus = true) {\r\n if (!open.value) return\r\n open.value = false\r\n if (restoreFocus) nextTick(() => focusElement(triggerEl.value))\r\n}\r\n\r\nprovide(MENU_ROOT, { close })\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (open.value) return close(false)\r\n // `detail` is 0 when a click came from the keyboard (Enter / Space).\r\n show(event.detail === 0 ? 'first' : 'content')\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\r\n event.preventDefault()\r\n show(event.key === 'ArrowDown' ? 'first' : 'last')\r\n }\r\n}\r\n\r\nconst triggerProps = computed(() => ({\r\n 'id': triggerId,\r\n 'aria-haspopup': 'menu',\r\n 'aria-expanded': open.value,\r\n 'aria-controls': open.value ? menuId : undefined,\r\n 'data-state': open.value ? 'open' : 'closed',\r\n 'onClick': onClick,\r\n 'onKeydown': onKeydown,\r\n}))\r\n\r\ndefineExpose({ open: () => show('content'), close })\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot name=\"trigger\" :open=\"open\" />\r\n </JSlot>\r\n <JMenuContent\r\n :id=\"menuId\"\r\n :open=\"open\"\r\n :reference=\"triggerEl\"\r\n :labelledby=\"triggerEl?.id || triggerId\"\r\n :placement=\"placement\"\r\n :offset=\"offset\"\r\n :initial-focus=\"initialFocus\"\r\n @escape=\"close(true)\"\r\n @outside=\"close(false)\"\r\n >\r\n <slot />\r\n </JMenuContent>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport { computed, nextTick, provide, ref, useId } from 'vue'\r\nimport { focusElement, unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport { MENU_ROOT } from './context'\r\nimport JMenuContent from './JMenuContent.vue'\r\n\r\nexport interface DropdownMenuProps {\r\n placement?: Placement\r\n /** Distance from the trigger, in px. */\r\n offset?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuProps>(), {\r\n placement: 'bottom-start',\r\n offset: 6,\r\n})\r\n\r\nconst open = defineModel<boolean>('open', { default: false })\r\n\r\ndefineSlots<{\r\n /** The element that opens the menu | usually a `JButton`. */\r\n trigger?: (props: { open: boolean }) => unknown\r\n default?: () => unknown\r\n}>()\r\n\r\nconst id = useId()\r\nconst triggerId = `j-${id}-trigger`\r\nconst menuId = `j-${id}-menu`\r\n\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst initialFocus = ref<'first' | 'last' | 'content'>('content')\r\n\r\nfunction show(focus: 'first' | 'last' | 'content') {\r\n if (props.disabled) return\r\n initialFocus.value = focus\r\n open.value = true\r\n}\r\n\r\nfunction close(restoreFocus = true) {\r\n if (!open.value) return\r\n open.value = false\r\n if (restoreFocus) nextTick(() => focusElement(triggerEl.value))\r\n}\r\n\r\nprovide(MENU_ROOT, { close })\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (open.value) return close(false)\r\n // `detail` is 0 when a click came from the keyboard (Enter / Space).\r\n show(event.detail === 0 ? 'first' : 'content')\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\r\n event.preventDefault()\r\n show(event.key === 'ArrowDown' ? 'first' : 'last')\r\n }\r\n}\r\n\r\nconst triggerProps = computed(() => ({\r\n 'id': triggerId,\r\n 'aria-haspopup': 'menu',\r\n 'aria-expanded': open.value,\r\n 'aria-controls': open.value ? menuId : undefined,\r\n 'data-state': open.value ? 'open' : 'closed',\r\n 'onClick': onClick,\r\n 'onKeydown': onKeydown,\r\n}))\r\n\r\ndefineExpose({ open: () => show('content'), close })\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot name=\"trigger\" :open=\"open\" />\r\n </JSlot>\r\n <JMenuContent\r\n :id=\"menuId\"\r\n :open=\"open\"\r\n :reference=\"triggerEl\"\r\n :labelledby=\"triggerEl?.id || triggerId\"\r\n :placement=\"placement\"\r\n :offset=\"offset\"\r\n :initial-focus=\"initialFocus\"\r\n @escape=\"close(true)\"\r\n @outside=\"close(false)\"\r\n >\r\n <slot />\r\n </JMenuContent>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue'\r\nimport { inject, ref } from 'vue'\r\nimport { IconCheck } from '../../icons'\r\nimport { focusElement } from '../../utils/dom'\r\nimport { MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nexport interface DropdownMenuItemProps {\r\n disabled?: boolean\r\n /** Styles the item as a destructive action. */\r\n destructive?: boolean\r\n /** A keyboard shortcut to display, e.g. `⌘D`. Display only. */\r\n shortcut?: string\r\n /** Render as another element, e.g. `a` or `NuxtLink` for navigation items. */\r\n as?: string | Component\r\n /**\r\n * Makes the item one choice in a set (e.g. a theme picker). `true` shows a\r\n * check at the end of the row. Leave undefined for a plain action.\r\n */\r\n checked?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuItemProps>(), { as: 'div', checked: undefined })\r\n\r\nconst emit = defineEmits<{\r\n /** Fired when the item is chosen. Call `event.preventDefault()` to keep the menu open. */\r\n select: [event: Event]\r\n}>()\r\n\r\ndefineSlots<{ default?: () => unknown, leading?: () => unknown }>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst level = inject(MENU_LEVEL)!\r\nconst el = ref<HTMLElement | null>(null)\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (props.disabled) {\r\n event.preventDefault()\r\n return\r\n }\r\n const selectEvent = new Event('select', { cancelable: true })\r\n emit('select', selectEvent)\r\n if (!selectEvent.defaultPrevented) root.close(true)\r\n}\r\n\r\nfunction resolve(target: unknown): HTMLElement | null {\r\n const value = target as { $el?: HTMLElement } | HTMLElement | null\r\n return value instanceof HTMLElement ? value : (value?.$el ?? null)\r\n}\r\n\r\n// Hover moves real focus, so pointer and keyboard always agree on one item.\r\nfunction onPointerMove() {\r\n level.scheduleSubClose()\r\n const node = resolve(el.value)\r\n if (props.disabled || !node || document.activeElement === node) return\r\n focusElement(node)\r\n}\r\n\r\nfunction onPointerLeave() {\r\n const node = resolve(el.value)\r\n if (node && document.activeElement === node) focusElement(level.content.value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <component\r\n :is=\"as\"\r\n ref=\"el\"\r\n :role=\"checked === undefined ? 'menuitem' : 'menuitemradio'\"\r\n :aria-checked=\"checked === undefined ? undefined : checked\"\r\n tabindex=\"-1\"\r\n class=\"j-menu__item\"\r\n :class=\"{ 'j-menu__item--destructive': destructive }\"\r\n :aria-disabled=\"disabled || undefined\"\r\n @click=\"onClick\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerleave=\"onPointerLeave\"\r\n >\r\n <span v-if=\"$slots.leading\" class=\"j-menu__icon\"><slot name=\"leading\" /></span>\r\n <span class=\"j-menu__text\"><slot /></span>\r\n <span v-if=\"shortcut\" class=\"j-menu__shortcut\">{{ shortcut }}</span>\r\n <IconCheck v-if=\"checked !== undefined\" class=\"j-menu__check\" :class=\"{ 'is-checked': checked }\" />\r\n </component>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue'\r\nimport { inject, ref } from 'vue'\r\nimport { IconCheck } from '../../icons'\r\nimport { focusElement } from '../../utils/dom'\r\nimport { MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nexport interface DropdownMenuItemProps {\r\n disabled?: boolean\r\n /** Styles the item as a destructive action. */\r\n destructive?: boolean\r\n /** A keyboard shortcut to display, e.g. `⌘D`. Display only. */\r\n shortcut?: string\r\n /** Render as another element, e.g. `a` or `NuxtLink` for navigation items. */\r\n as?: string | Component\r\n /**\r\n * Makes the item one choice in a set (e.g. a theme picker). `true` shows a\r\n * check at the end of the row. Leave undefined for a plain action.\r\n */\r\n checked?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuItemProps>(), { as: 'div', checked: undefined })\r\n\r\nconst emit = defineEmits<{\r\n /** Fired when the item is chosen. Call `event.preventDefault()` to keep the menu open. */\r\n select: [event: Event]\r\n}>()\r\n\r\ndefineSlots<{ default?: () => unknown, leading?: () => unknown }>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst level = inject(MENU_LEVEL)!\r\nconst el = ref<HTMLElement | null>(null)\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (props.disabled) {\r\n event.preventDefault()\r\n return\r\n }\r\n const selectEvent = new Event('select', { cancelable: true })\r\n emit('select', selectEvent)\r\n if (!selectEvent.defaultPrevented) root.close(true)\r\n}\r\n\r\nfunction resolve(target: unknown): HTMLElement | null {\r\n const value = target as { $el?: HTMLElement } | HTMLElement | null\r\n return value instanceof HTMLElement ? value : (value?.$el ?? null)\r\n}\r\n\r\n// Hover moves real focus, so pointer and keyboard always agree on one item.\r\nfunction onPointerMove() {\r\n level.scheduleSubClose()\r\n const node = resolve(el.value)\r\n if (props.disabled || !node || document.activeElement === node) return\r\n focusElement(node)\r\n}\r\n\r\nfunction onPointerLeave() {\r\n const node = resolve(el.value)\r\n if (node && document.activeElement === node) focusElement(level.content.value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <component\r\n :is=\"as\"\r\n ref=\"el\"\r\n :role=\"checked === undefined ? 'menuitem' : 'menuitemradio'\"\r\n :aria-checked=\"checked === undefined ? undefined : checked\"\r\n tabindex=\"-1\"\r\n class=\"j-menu__item\"\r\n :class=\"{ 'j-menu__item--destructive': destructive }\"\r\n :aria-disabled=\"disabled || undefined\"\r\n @click=\"onClick\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerleave=\"onPointerLeave\"\r\n >\r\n <span v-if=\"$slots.leading\" class=\"j-menu__icon\"><slot name=\"leading\" /></span>\r\n <span class=\"j-menu__text\"><slot /></span>\r\n <span v-if=\"shortcut\" class=\"j-menu__shortcut\">{{ shortcut }}</span>\r\n <IconCheck v-if=\"checked !== undefined\" class=\"j-menu__check\" :class=\"{ 'is-checked': checked }\" />\r\n </component>\r\n</template>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: lays out label, control, description and error for form fields.\r\n * Not exported | every field component composes it.\r\n */\r\ndefineProps<{\r\n id: string\r\n labelId: string\r\n descriptionId: string\r\n errorId: string\r\n label?: string\r\n description?: string\r\n errorMessage?: string\r\n showDescription?: boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Render the label as a plain element when the control isn't labelable (e.g. a button). */\r\n labelFor?: string | null\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div class=\"j-field\" :class=\"{ 'is-disabled': disabled }\">\r\n <component\r\n :is=\"labelFor === null ? 'span' : 'label'\"\r\n v-if=\"label || $slots.label\"\r\n :id=\"labelId\"\r\n class=\"j-field__label\"\r\n :for=\"labelFor === null ? undefined : labelFor ?? id\"\r\n >\r\n <slot name=\"label\">{{ label }}</slot>\r\n <span v-if=\"required\" class=\"j-field__required\" aria-hidden=\"true\">*</span>\r\n </component>\r\n <slot />\r\n <div class=\"j-field__messages\">\r\n <Transition name=\"j-field-message\" mode=\"out-in\">\r\n <p v-if=\"errorMessage\" :id=\"errorId\" :key=\"errorMessage\" class=\"j-field__error\">\r\n {{ errorMessage }}\r\n </p>\r\n <p v-else-if=\"showDescription\" :id=\"descriptionId\" class=\"j-field__description\">\r\n {{ description }}\r\n </p>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--juxt-space-1-5);\r\n min-width: 0;\r\n font-family: var(--juxt-font-sans);\r\n}\r\n\r\n.j-field__label {\r\n display: inline-flex;\r\n align-items: baseline;\r\n gap: var(--juxt-space-0-5);\r\n width: fit-content;\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-sm);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n}\r\n\r\n.j-field.is-disabled .j-field__label {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__required {\r\n color: var(--juxt-fg-muted);\r\n font-weight: var(--juxt-weight-regular);\r\n}\r\n\r\n.j-field__messages:empty {\r\n display: none;\r\n}\r\n\r\n.j-field__description,\r\n.j-field__error {\r\n margin: 0;\r\n font-size: var(--juxt-text-xs);\r\n line-height: var(--juxt-leading-normal);\r\n}\r\n\r\n.j-field__description {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__error {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-field-message-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-normal) var(--juxt-ease-out);\r\n}\r\n\r\n.j-field-message-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-field-message-enter-from {\r\n opacity: 0;\r\n transform: translateY(calc(var(--juxt-motion-shift) * -0.5));\r\n}\r\n\r\n.j-field-message-leave-to {\r\n opacity: 0;\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: lays out label, control, description and error for form fields.\r\n * Not exported | every field component composes it.\r\n */\r\ndefineProps<{\r\n id: string\r\n labelId: string\r\n descriptionId: string\r\n errorId: string\r\n label?: string\r\n description?: string\r\n errorMessage?: string\r\n showDescription?: boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Render the label as a plain element when the control isn't labelable (e.g. a button). */\r\n labelFor?: string | null\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div class=\"j-field\" :class=\"{ 'is-disabled': disabled }\">\r\n <component\r\n :is=\"labelFor === null ? 'span' : 'label'\"\r\n v-if=\"label || $slots.label\"\r\n :id=\"labelId\"\r\n class=\"j-field__label\"\r\n :for=\"labelFor === null ? undefined : labelFor ?? id\"\r\n >\r\n <slot name=\"label\">{{ label }}</slot>\r\n <span v-if=\"required\" class=\"j-field__required\" aria-hidden=\"true\">*</span>\r\n </component>\r\n <slot />\r\n <div class=\"j-field__messages\">\r\n <Transition name=\"j-field-message\" mode=\"out-in\">\r\n <p v-if=\"errorMessage\" :id=\"errorId\" :key=\"errorMessage\" class=\"j-field__error\">\r\n {{ errorMessage }}\r\n </p>\r\n <p v-else-if=\"showDescription\" :id=\"descriptionId\" class=\"j-field__description\">\r\n {{ description }}\r\n </p>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--juxt-space-1-5);\r\n min-width: 0;\r\n font-family: var(--juxt-font-sans);\r\n}\r\n\r\n.j-field__label {\r\n display: inline-flex;\r\n align-items: baseline;\r\n gap: var(--juxt-space-0-5);\r\n width: fit-content;\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-sm);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n}\r\n\r\n.j-field.is-disabled .j-field__label {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__required {\r\n color: var(--juxt-fg-muted);\r\n font-weight: var(--juxt-weight-regular);\r\n}\r\n\r\n.j-field__messages:empty {\r\n display: none;\r\n}\r\n\r\n.j-field__description,\r\n.j-field__error {\r\n margin: 0;\r\n font-size: var(--juxt-text-xs);\r\n line-height: var(--juxt-leading-normal);\r\n}\r\n\r\n.j-field__description {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__error {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-field-message-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-normal) var(--juxt-ease-out);\r\n}\r\n\r\n.j-field-message-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-field-message-enter-from {\r\n opacity: 0;\r\n transform: translateY(calc(var(--juxt-motion-shift) * -0.5));\r\n}\r\n\r\n.j-field-message-leave-to {\r\n opacity: 0;\r\n}\r\n}\r\n</style>\r\n","import type { MaybeRefOrGetter } from 'vue'\r\nimport { computed, toValue, useId } from 'vue'\r\n\r\nexport interface FieldProps {\r\n /** Visible label. Also used as the accessible name. */\r\n label?: string\r\n /** Supporting text under the control. Hidden while an error message is shown. */\r\n description?: string\r\n /** An error message, or `true` to mark the field invalid without a message. */\r\n error?: string | boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Id for the control. Generated when omitted. */\r\n id?: string\r\n}\r\n\r\n/** Ids and ARIA wiring shared by every form control. */\r\nexport function useField(props: MaybeRefOrGetter<FieldProps>) {\r\n const generated = useId()\r\n const p = () => toValue(props)\r\n\r\n const id = computed(() => p().id ?? `j-${generated}`)\r\n const labelId = computed(() => `${id.value}-label`)\r\n const descriptionId = computed(() => `${id.value}-description`)\r\n const errorId = computed(() => `${id.value}-error`)\r\n\r\n const invalid = computed(() => !!p().error)\r\n const errorMessage = computed(() => (typeof p().error === 'string' ? (p().error as string) : ''))\r\n const showDescription = computed(() => !!p().description && !errorMessage.value)\r\n\r\n const describedBy = computed(() => {\r\n const ids: string[] = []\r\n if (errorMessage.value) ids.push(errorId.value)\r\n else if (p().description) ids.push(descriptionId.value)\r\n return ids.length ? ids.join(' ') : undefined\r\n })\r\n\r\n return { id, labelId, descriptionId, errorId, invalid, errorMessage, showDescription, describedBy }\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { computed, onMounted, ref } from 'vue'\r\nimport { formatHotkey } from '../../composables/useHotkey'\r\n\r\nexport interface KbdProps {\r\n /**\r\n * A shortcut in hotkey syntax, e.g. `mod+k` or `shift+enter`. `mod` renders\r\n * as ⌘ on Apple platforms and Ctrl elsewhere. Use the slot for literal keys.\r\n */\r\n keys?: string\r\n size?: 'sm' | 'md'\r\n}\r\n\r\nconst props = withDefaults(defineProps<KbdProps>(), { size: 'md' })\r\n\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\n// Platform glyphs are only known in the browser; resolve after mount so\r\n// server and client render the same markup.\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n\r\nconst parts = computed(() => {\r\n if (!props.keys) return []\r\n if (!mounted.value) return props.keys.split('+').map(part => (part === 'mod' ? 'Ctrl' : part.length === 1 ? part.toUpperCase() : part))\r\n return formatHotkey(props.keys)\r\n})\r\n</script>\r\n\r\n<template>\r\n <span v-if=\"keys\" class=\"j-kbd-group\" :class=\"`j-kbd-group--${size}`\">\r\n <kbd v-for=\"(part, i) in parts\" :key=\"i\" class=\"j-kbd\">{{ part }}</kbd>\r\n </span>\r\n <kbd v-else class=\"j-kbd\" :class=\"{ 'j-kbd--sm': size === 'sm' }\"><slot /></kbd>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-kbd-group {\r\n display: inline-flex;\r\n gap: 3px;\r\n vertical-align: middle;\r\n}\r\n\r\n.j-kbd-group--sm .j-kbd,\r\n.j-kbd--sm {\r\n min-width: 1.0625rem;\r\n height: 1.0625rem;\r\n font-size: 0.625rem;\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { computed, onMounted, ref } from 'vue'\r\nimport { formatHotkey } from '../../composables/useHotkey'\r\n\r\nexport interface KbdProps {\r\n /**\r\n * A shortcut in hotkey syntax, e.g. `mod+k` or `shift+enter`. `mod` renders\r\n * as ⌘ on Apple platforms and Ctrl elsewhere. Use the slot for literal keys.\r\n */\r\n keys?: string\r\n size?: 'sm' | 'md'\r\n}\r\n\r\nconst props = withDefaults(defineProps<KbdProps>(), { size: 'md' })\r\n\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\n// Platform glyphs are only known in the browser; resolve after mount so\r\n// server and client render the same markup.\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n\r\nconst parts = computed(() => {\r\n if (!props.keys) return []\r\n if (!mounted.value) return props.keys.split('+').map(part => (part === 'mod' ? 'Ctrl' : part.length === 1 ? part.toUpperCase() : part))\r\n return formatHotkey(props.keys)\r\n})\r\n</script>\r\n\r\n<template>\r\n <span v-if=\"keys\" class=\"j-kbd-group\" :class=\"`j-kbd-group--${size}`\">\r\n <kbd v-for=\"(part, i) in parts\" :key=\"i\" class=\"j-kbd\">{{ part }}</kbd>\r\n </span>\r\n <kbd v-else class=\"j-kbd\" :class=\"{ 'j-kbd--sm': size === 'sm' }\"><slot /></kbd>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-kbd-group {\r\n display: inline-flex;\r\n gap: 3px;\r\n vertical-align: middle;\r\n}\r\n\r\n.j-kbd-group--sm .j-kbd,\r\n.j-kbd--sm {\r\n min-width: 1.0625rem;\r\n height: 1.0625rem;\r\n font-size: 0.625rem;\r\n}\r\n}\r\n</style>\r\n","<script lang=\"ts\">\r\n// Shared across every tooltip: once one has been shown, neighbours open\r\n// instantly for a moment. Scanning a toolbar shouldn't mean waiting at each icon.\r\nlet warmUntil = 0\r\nconst WARM_WINDOW = 400\r\n</script>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onBeforeUnmount, ref, useId } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport JPortal from '../primitives/JPortal.vue'\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip text. Use the `content` slot for richer content. */\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n /** Hover delay before opening, in ms. Keyboard focus opens immediately. */\r\n delay?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<TooltipProps>(), {\r\n side: 'top',\r\n align: 'center',\r\n delay: 450,\r\n})\r\n\r\ndefineSlots<{\r\n default?: () => unknown\r\n content?: () => unknown\r\n}>()\r\n\r\nconst id = `j-${useId()}-tooltip`\r\nconst open = ref(false)\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst floating = ref<HTMLElement | null>(null)\r\n\r\nconst placement = computed(() => (props.align === 'center' ? props.side : `${props.side}-${props.align}` as const))\r\nconst { styles } = useFloating(triggerEl, floating, () => ({ placement: placement.value, offset: 6 }))\r\n\r\nuseLayer({\r\n active: open,\r\n elements: () => [triggerEl.value, floating.value],\r\n onEscape: () => hide(true),\r\n})\r\n\r\nlet openTimer: ReturnType<typeof setTimeout> | undefined\r\nlet closeTimer: ReturnType<typeof setTimeout> | undefined\r\n// After a click, stay quiet until the pointer leaves | the user is acting, not reading.\r\nlet suppressed = false\r\n\r\nfunction show(immediate = false) {\r\n if (props.disabled || suppressed) return\r\n clearTimeout(closeTimer)\r\n if (open.value) return\r\n clearTimeout(openTimer)\r\n if (immediate || Date.now() < warmUntil) open.value = true\r\n else openTimer = setTimeout(() => (open.value = true), props.delay)\r\n}\r\n\r\nfunction hide(immediate = false) {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n const close = () => {\r\n if (open.value) warmUntil = Date.now() + WARM_WINDOW\r\n open.value = false\r\n }\r\n if (immediate) close()\r\n // A short grace period lets the pointer travel onto the tooltip itself.\r\n else closeTimer = setTimeout(close, 80)\r\n}\r\n\r\nonBeforeUnmount(() => {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n})\r\n\r\nconst triggerProps = computed(() => ({\r\n 'aria-describedby': props.disabled ? undefined : id,\r\n 'onPointerenter': (event: PointerEvent) => event.pointerType === 'mouse' && show(),\r\n 'onPointerleave': (event: PointerEvent) => {\r\n suppressed = false\r\n if (event.pointerType === 'mouse') hide()\r\n },\r\n 'onPointerdown': () => {\r\n suppressed = true\r\n hide(true)\r\n },\r\n 'onFocus': (event: FocusEvent) => {\r\n const target = event.target as HTMLElement\r\n if (target.matches(':focus-visible')) show(true)\r\n },\r\n 'onBlur': () => hide(true),\r\n}))\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot />\r\n </JSlot>\r\n <span v-if=\"!disabled\" :id=\"id\" class=\"j-sr-only\">\r\n <slot name=\"content\">{{ content }}</slot>\r\n </span>\r\n <JPortal>\r\n <Transition name=\"j-tooltip\">\r\n <div\r\n v-if=\"open\"\r\n ref=\"floating\"\r\n class=\"j-tooltip\"\r\n :style=\"styles\"\r\n aria-hidden=\"true\"\r\n data-juxt-layer-ignore\r\n @pointerenter=\"show(true)\"\r\n @pointerleave=\"hide()\"\r\n >\r\n <slot name=\"content\">\r\n {{ content }}\r\n </slot>\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-tooltip {\r\n z-index: var(--juxt-z-tooltip);\r\n box-sizing: border-box;\r\n max-width: min(17.5rem, calc(100vw - 16px));\r\n padding: var(--juxt-space-1) var(--juxt-space-2);\r\n border: 1px solid var(--juxt-tooltip-border);\r\n border-radius: var(--juxt-radius-sm);\r\n background: var(--juxt-tooltip-bg);\r\n box-shadow: var(--juxt-shadow-sm);\r\n color: var(--juxt-tooltip-fg);\r\n font-family: var(--juxt-font-sans);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: 0;\r\n overflow-wrap: break-word;\r\n pointer-events: auto;\r\n}\r\n\r\n.j-tooltip .j-kbd {\r\n height: 1rem;\r\n min-width: 1rem;\r\n margin-left: var(--juxt-space-1);\r\n border-color: rgb(255 255 255 / 0.14);\r\n background: rgb(255 255 255 / 0.08);\r\n color: rgb(255 255 255 / 0.72);\r\n}\r\n\r\n.j-tooltip-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-fast) var(--juxt-ease-out);\r\n}\r\n\r\n.j-tooltip-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-tooltip-enter-from,\r\n.j-tooltip-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.j-tooltip-enter-from {\r\n transform: translate(\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-x, 0)),\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-dir, 0))\r\n );\r\n}\r\n}\r\n</style>\r\n","<script lang=\"ts\">\r\n// Shared across every tooltip: once one has been shown, neighbours open\r\n// instantly for a moment. Scanning a toolbar shouldn't mean waiting at each icon.\r\nlet warmUntil = 0\r\nconst WARM_WINDOW = 400\r\n</script>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onBeforeUnmount, ref, useId } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport JPortal from '../primitives/JPortal.vue'\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip text. Use the `content` slot for richer content. */\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n /** Hover delay before opening, in ms. Keyboard focus opens immediately. */\r\n delay?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<TooltipProps>(), {\r\n side: 'top',\r\n align: 'center',\r\n delay: 450,\r\n})\r\n\r\ndefineSlots<{\r\n default?: () => unknown\r\n content?: () => unknown\r\n}>()\r\n\r\nconst id = `j-${useId()}-tooltip`\r\nconst open = ref(false)\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst floating = ref<HTMLElement | null>(null)\r\n\r\nconst placement = computed(() => (props.align === 'center' ? props.side : `${props.side}-${props.align}` as const))\r\nconst { styles } = useFloating(triggerEl, floating, () => ({ placement: placement.value, offset: 6 }))\r\n\r\nuseLayer({\r\n active: open,\r\n elements: () => [triggerEl.value, floating.value],\r\n onEscape: () => hide(true),\r\n})\r\n\r\nlet openTimer: ReturnType<typeof setTimeout> | undefined\r\nlet closeTimer: ReturnType<typeof setTimeout> | undefined\r\n// After a click, stay quiet until the pointer leaves | the user is acting, not reading.\r\nlet suppressed = false\r\n\r\nfunction show(immediate = false) {\r\n if (props.disabled || suppressed) return\r\n clearTimeout(closeTimer)\r\n if (open.value) return\r\n clearTimeout(openTimer)\r\n if (immediate || Date.now() < warmUntil) open.value = true\r\n else openTimer = setTimeout(() => (open.value = true), props.delay)\r\n}\r\n\r\nfunction hide(immediate = false) {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n const close = () => {\r\n if (open.value) warmUntil = Date.now() + WARM_WINDOW\r\n open.value = false\r\n }\r\n if (immediate) close()\r\n // A short grace period lets the pointer travel onto the tooltip itself.\r\n else closeTimer = setTimeout(close, 80)\r\n}\r\n\r\nonBeforeUnmount(() => {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n})\r\n\r\nconst triggerProps = computed(() => ({\r\n 'aria-describedby': props.disabled ? undefined : id,\r\n 'onPointerenter': (event: PointerEvent) => event.pointerType === 'mouse' && show(),\r\n 'onPointerleave': (event: PointerEvent) => {\r\n suppressed = false\r\n if (event.pointerType === 'mouse') hide()\r\n },\r\n 'onPointerdown': () => {\r\n suppressed = true\r\n hide(true)\r\n },\r\n 'onFocus': (event: FocusEvent) => {\r\n const target = event.target as HTMLElement\r\n if (target.matches(':focus-visible')) show(true)\r\n },\r\n 'onBlur': () => hide(true),\r\n}))\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot />\r\n </JSlot>\r\n <span v-if=\"!disabled\" :id=\"id\" class=\"j-sr-only\">\r\n <slot name=\"content\">{{ content }}</slot>\r\n </span>\r\n <JPortal>\r\n <Transition name=\"j-tooltip\">\r\n <div\r\n v-if=\"open\"\r\n ref=\"floating\"\r\n class=\"j-tooltip\"\r\n :style=\"styles\"\r\n aria-hidden=\"true\"\r\n data-juxt-layer-ignore\r\n @pointerenter=\"show(true)\"\r\n @pointerleave=\"hide()\"\r\n >\r\n <slot name=\"content\">\r\n {{ content }}\r\n </slot>\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-tooltip {\r\n z-index: var(--juxt-z-tooltip);\r\n box-sizing: border-box;\r\n max-width: min(17.5rem, calc(100vw - 16px));\r\n padding: var(--juxt-space-1) var(--juxt-space-2);\r\n border: 1px solid var(--juxt-tooltip-border);\r\n border-radius: var(--juxt-radius-sm);\r\n background: var(--juxt-tooltip-bg);\r\n box-shadow: var(--juxt-shadow-sm);\r\n color: var(--juxt-tooltip-fg);\r\n font-family: var(--juxt-font-sans);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: 0;\r\n overflow-wrap: break-word;\r\n pointer-events: auto;\r\n}\r\n\r\n.j-tooltip .j-kbd {\r\n height: 1rem;\r\n min-width: 1rem;\r\n margin-left: var(--juxt-space-1);\r\n border-color: rgb(255 255 255 / 0.14);\r\n background: rgb(255 255 255 / 0.08);\r\n color: rgb(255 255 255 / 0.72);\r\n}\r\n\r\n.j-tooltip-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-fast) var(--juxt-ease-out);\r\n}\r\n\r\n.j-tooltip-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-tooltip-enter-from,\r\n.j-tooltip-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.j-tooltip-enter-from {\r\n transform: translate(\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-x, 0)),\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-dir, 0))\r\n );\r\n}\r\n}\r\n</style>\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"JTooltip-CAL9lsPF.js","names":["_openBlock","_createBlock","_Teleport","_renderSlot","_createCommentVNode","_sfc_main","_hoisted_1","_openBlock","_createBlock","JPortal","_withCtx","_createVNode","_Transition","_createElementBlock","_normalizeClass","_normalizeStyle","_unref","_renderSlot","_createCommentVNode","_sfc_main","_useModel","_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","JMenuContent","_sfc_main","$slots","_hoisted_1","_hoisted_2","_hoisted_3","_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_createElementBlock","_renderSlot","_createCommentVNode","_createElementVNode","_toDisplayString","_unref","_sfc_main","$slots","_openBlock","_createElementBlock","_normalizeClass","_createBlock","_resolveDynamicComponent","_withCtx","_renderSlot","_createTextVNode","_toDisplayString","_createCommentVNode","_createElementVNode","_createVNode","_Transition","_sfc_main","_openBlock","_createElementBlock","_normalizeClass","_Fragment","_renderList","_toDisplayString","_renderSlot","_sfc_main","_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","_mergeProps","_withCtx","_renderSlot","_createTextVNode","_toDisplayString","_createCommentVNode","JPortal","_Transition","_normalizeStyle","_sfc_main"],"sources":["../src/utils/dom.ts","../src/icons.ts","../src/composables/useHotkey.ts","../src/composables/useLayer.ts","../src/components/command-palette/search.ts","../src/components/primitives/JPortal.vue","../src/components/primitives/JPortal.vue","../src/components/primitives/JSlot.ts","../src/components/dropdown-menu/context.ts","../src/composables/useFloating.ts","../src/composables/useTypeahead.ts","../src/components/dropdown-menu/JMenuContent.vue","../src/components/dropdown-menu/JMenuContent.vue","../src/components/dropdown-menu/JDropdownMenu.vue","../src/components/dropdown-menu/JDropdownMenu.vue","../src/components/dropdown-menu/JDropdownMenuItem.vue","../src/components/dropdown-menu/JDropdownMenuItem.vue","../src/components/field/JFieldShell.vue","../src/components/field/JFieldShell.vue","../src/components/field/useField.ts","../src/components/kbd/JKbd.vue","../src/components/kbd/JKbd.vue","../src/components/tooltip/JTooltip.vue","../src/components/tooltip/JTooltip.vue"],"sourcesContent":["import type { ComponentPublicInstance, MaybeRef } from 'vue'\r\nimport { unref } from 'vue'\r\n\r\nexport const isClient = typeof window !== 'undefined' && typeof document !== 'undefined'\r\n\r\nexport type MaybeElement = HTMLElement | SVGElement | ComponentPublicInstance | null | undefined\r\n\r\n/** Resolve a template ref that may point at an element or a component instance. */\r\nexport function unrefElement(target: MaybeRef<MaybeElement>): HTMLElement | null {\r\n const value = unref(target)\r\n if (!value) return null\r\n if (value instanceof Element) return value as HTMLElement\r\n const el = (value as ComponentPublicInstance).$el as Node | null\r\n // A component whose root is a fragment exposes a text node as $el.\r\n if (el && el.nodeType !== Node.ELEMENT_NODE) {\r\n const next = el.nextSibling\r\n return next instanceof HTMLElement ? next : null\r\n }\r\n return (el as HTMLElement | null) ?? null\r\n}\r\n\r\nconst FOCUSABLE = [\r\n 'a[href]',\r\n 'area[href]',\r\n 'button:not([disabled])',\r\n 'input:not([disabled]):not([type=\"hidden\"])',\r\n 'select:not([disabled])',\r\n 'textarea:not([disabled])',\r\n 'iframe',\r\n 'audio[controls]',\r\n 'video[controls]',\r\n '[contenteditable]:not([contenteditable=\"false\"])',\r\n '[tabindex]',\r\n].join(',')\r\n\r\nfunction isVisible(el: HTMLElement): boolean {\r\n if (el.hidden) return false\r\n // `checkVisibility` is precise where supported; the rect check covers the rest.\r\n if (typeof el.checkVisibility === 'function') return el.checkVisibility({ visibilityProperty: true })\r\n for (let node: HTMLElement | null = el; node; node = node.parentElement) {\r\n const style = getComputedStyle(node)\r\n if (style.display === 'none' || style.visibility === 'hidden') return false\r\n }\r\n return true\r\n}\r\n\r\n/** Elements that can receive keyboard focus, in DOM order. */\r\nexport function getFocusableElements(container: HTMLElement): HTMLElement[] {\r\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\r\n el => el.tabIndex >= 0 && !el.closest('[inert]') && isVisible(el),\r\n )\r\n}\r\n\r\nexport function focusElement(el: HTMLElement | null | undefined, options?: FocusOptions) {\r\n if (!el) return\r\n el.focus({ preventScroll: true, ...options })\r\n}\r\n\r\nexport const isMac = () => isClient && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent)\r\n\r\nexport function prefersReducedMotion() {\r\n return isClient && window.matchMedia('(prefers-reduced-motion: reduce)').matches\r\n}\r\n","import type { FunctionalComponent, SVGAttributes } from 'vue'\r\nimport { h } from 'vue'\r\n\r\n/*\r\n * The handful of glyphs Juxt needs internally. Drawn on a 16px grid with a\r\n * 1.5px stroke so they sit at the same optical weight as 13–14px text.\r\n */\r\n\r\ntype Icon = FunctionalComponent<SVGAttributes>\r\n\r\nfunction icon(name: string, children: () => ReturnType<typeof h>[], viewBox = '0 0 16 16'): Icon {\r\n const component: Icon = (props) =>\r\n h(\r\n 'svg',\r\n {\r\n 'xmlns': 'http://www.w3.org/2000/svg',\r\n viewBox,\r\n 'width': 16,\r\n 'height': 16,\r\n 'fill': 'none',\r\n 'stroke': 'currentColor',\r\n 'stroke-width': 1.5,\r\n 'stroke-linecap': 'round',\r\n 'stroke-linejoin': 'round',\r\n 'aria-hidden': 'true',\r\n 'focusable': 'false',\r\n ...props,\r\n },\r\n children(),\r\n )\r\n component.displayName = name\r\n return component\r\n}\r\n\r\nexport const IconCheck = icon('IconCheck', () => [h('path', { d: 'M3.5 8.5l3 3 6-7' })])\r\nexport const IconChevronDown = icon('IconChevronDown', () => [h('path', { d: 'M4.5 6.25L8 9.75l3.5-3.5' })])\r\nexport const IconChevronUpDown = icon('IconChevronUpDown', () => [h('path', { d: 'M5.25 6L8 3.25 10.75 6M5.25 10L8 12.75 10.75 10' })])\r\nexport const IconChevronRight = icon('IconChevronRight', () => [h('path', { d: 'M6.25 4.5L9.75 8l-3.5 3.5' })])\r\nexport const IconX = icon('IconX', () => [h('path', { d: 'M4.5 4.5l7 7M11.5 4.5l-7 7' })])\r\nexport const IconSearch = icon('IconSearch', () => [h('circle', { cx: 7, cy: 7, r: 4.25 }), h('path', { d: 'M10.25 10.25L13 13' })])\r\nexport const IconCircleCheck = icon('IconCircleCheck', () => [h('circle', { cx: 8, cy: 8, r: 6.25 }), h('path', { d: 'M5.5 8.25l1.75 1.75L10.5 6.5' })])\r\nexport const IconCircleX = icon('IconCircleX', () => [h('circle', { cx: 8, cy: 8, r: 6.25 }), h('path', { d: 'M6.25 6.25l3.5 3.5M9.75 6.25l-3.5 3.5' })])\r\nexport const IconAlert = icon('IconAlert', () => [\r\n h('path', { d: 'M7.13 2.75a1 1 0 0 1 1.74 0l5.15 9a1 1 0 0 1-.87 1.5H2.85a1 1 0 0 1-.87-1.5z' }),\r\n h('path', { d: 'M8 6.5v2.5' }),\r\n h('path', { 'd': 'M8 11.1v.01', 'stroke-width': 1.75 }),\r\n])\r\nexport const IconInfo = icon('IconInfo', () => [\r\n h('circle', { cx: 8, cy: 8, r: 6.25 }),\r\n h('path', { d: 'M8 7.5v3.25' }),\r\n h('path', { 'd': 'M8 5.25v.01', 'stroke-width': 1.75 }),\r\n])\r\nexport const IconCornerDownLeft = icon('IconCornerDownLeft', () => [h('path', { d: 'M12.5 3.5v4.25a2 2 0 0 1-2 2h-7' }), h('path', { d: 'M6 7l-2.5 2.75L6 12.5' })])\r\nexport const IconChevronLeft = icon('IconChevronLeft', () => [h('path', { d: 'M9.75 4.5L6.25 8l3.5 3.5' })])\r\nexport const IconMoreHorizontal = icon('IconMoreHorizontal', () => [\r\n h('circle', { cx: 3.5, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n h('circle', { cx: 8, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n h('circle', { cx: 12.5, cy: 8, r: 1, 'fill': 'currentColor', 'stroke': 'none' }),\r\n])\r\nexport const IconArrowUpRight = icon('IconArrowUpRight', () => [h('path', { d: 'M5 11L11 5M5.5 5h5.5v5.5' })])\r\nexport const IconArrowDownRight = icon('IconArrowDownRight', () => [h('path', { d: 'M5 5l6 6M10.5 11H5V5.5' })])\r\n\r\n/** The loading spinner used across Juxt. A quarter arc over a faint track. */\r\nexport const Spinner: FunctionalComponent<{ size?: number }> = (props) => {\r\n const size = props.size ?? 16\r\n return h(\r\n 'svg',\r\n { 'class': 'j-spinner', 'viewBox': '0 0 16 16', 'width': size, 'height': size, 'aria-hidden': 'true', 'focusable': 'false' },\r\n [\r\n h('circle', { 'class': 'j-spinner__track', 'cx': 8, 'cy': 8, 'r': 6, 'stroke-width': 1.75 }),\r\n h('circle', { 'cx': 8, 'cy': 8, 'r': 6, 'stroke-width': 1.75, 'stroke-dasharray': '9.5 28', 'stroke-dashoffset': 0 }),\r\n ],\r\n )\r\n}\r\nSpinner.displayName = 'JSpinner'\r\n","import type { MaybeRefOrGetter } from 'vue'\r\nimport { onBeforeUnmount, onMounted, toValue } from 'vue'\r\nimport { isMac } from '../utils/dom'\r\n\r\n/**\r\n * Parse a shortcut such as `mod+k`, `shift+/` or `alt+t`.\r\n * `mod` is ⌘ on Apple platforms and Ctrl elsewhere.\r\n */\r\nexport function matchesHotkey(event: KeyboardEvent, hotkey: string): boolean {\r\n const parts = hotkey.toLowerCase().split('+').map(part => part.trim())\r\n const key = parts.pop()\r\n if (!key) return false\r\n const mac = isMac()\r\n const want = {\r\n meta: parts.includes('meta') || (mac && parts.includes('mod')),\r\n ctrl: parts.includes('ctrl') || (!mac && parts.includes('mod')),\r\n alt: parts.includes('alt'),\r\n shift: parts.includes('shift'),\r\n }\r\n if (event.metaKey !== want.meta || event.ctrlKey !== want.ctrl || event.altKey !== want.alt || event.shiftKey !== want.shift)\r\n return false\r\n // `code` survives keyboard layouts and Alt/Option remapping.\r\n const code = event.code.toLowerCase()\r\n return event.key.toLowerCase() === key || code === `key${key}` || code === `digit${key}`\r\n}\r\n\r\n/** Human-readable parts of a shortcut, e.g. `mod+k` → `['⌘', 'K']`. */\r\nexport function formatHotkey(hotkey: string): string[] {\r\n const mac = isMac()\r\n const labels: Record<string, string> = mac\r\n ? { mod: '⌘', meta: '⌘', ctrl: '⌃', alt: '⌥', shift: '⇧', enter: '↵', escape: 'Esc' }\r\n : { mod: 'Ctrl', meta: 'Win', ctrl: 'Ctrl', alt: 'Alt', shift: 'Shift', enter: 'Enter', escape: 'Esc' }\r\n return hotkey.split('+').map((part) => {\r\n const lower = part.trim().toLowerCase()\r\n return labels[lower] ?? (lower.length === 1 ? lower.toUpperCase() : part.trim())\r\n })\r\n}\r\n\r\n/** Run `handler` whenever the shortcut is pressed anywhere on the page. */\r\nexport function useHotkey(hotkey: MaybeRefOrGetter<string | false | undefined>, handler: (event: KeyboardEvent) => void) {\r\n function onKeydown(event: KeyboardEvent) {\r\n const value = toValue(hotkey)\r\n // A focused component (e.g. the editor binding ⌘K to \"link\") already handled it.\r\n if (!value || event.repeat || event.isComposing || event.defaultPrevented) return\r\n if (!matchesHotkey(event, value)) return\r\n event.preventDefault()\r\n handler(event)\r\n }\r\n onMounted(() => document.addEventListener('keydown', onKeydown))\r\n onBeforeUnmount(() => document.removeEventListener('keydown', onKeydown))\r\n}\r\n","import type { Ref } from 'vue'\r\nimport { onBeforeUnmount, watch } from 'vue'\r\nimport { isClient } from '../utils/dom'\r\n\r\nexport interface LayerOptions {\r\n /** The layer is registered only while this is true. */\r\n active: Readonly<Ref<boolean>>\r\n /** Elements that count as \"inside\" the layer. */\r\n elements: () => Array<HTMLElement | null | undefined>\r\n onEscape?: (event: KeyboardEvent) => void\r\n /** Called when a pointer goes down outside every element of the top-most layer. */\r\n onPointerDownOutside?: (event: PointerEvent) => void\r\n}\r\n\r\ninterface Layer {\r\n options: LayerOptions\r\n}\r\n\r\n/*\r\n * Overlays stack. A select inside a dialog, a submenu inside a menu, a tooltip\r\n * inside anything: Escape and outside clicks belong to whichever layer is on\r\n * top, and only to that one.\r\n */\r\nconst layers: Layer[] = []\r\nlet listening = false\r\n\r\nfunction top() {\r\n return layers[layers.length - 1]\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n if (event.key !== 'Escape' || event.defaultPrevented || event.isComposing) return\r\n const layer = top()\r\n if (!layer?.options.onEscape) return\r\n event.preventDefault()\r\n event.stopPropagation()\r\n layer.options.onEscape(event)\r\n}\r\n\r\nfunction onPointerDown(event: PointerEvent) {\r\n const layer = top()\r\n if (!layer?.options.onPointerDownOutside) return\r\n const target = event.target as Node | null\r\n if (!target) return\r\n if ((target as HTMLElement).closest?.('[data-juxt-layer-ignore]')) return\r\n const inside = layer.options.elements().some(el => el?.contains(target))\r\n if (!inside) layer.options.onPointerDownOutside(event)\r\n}\r\n\r\nfunction listen() {\r\n if (listening || !isClient) return\r\n document.addEventListener('keydown', onKeydown)\r\n document.addEventListener('pointerdown', onPointerDown, true)\r\n listening = true\r\n}\r\n\r\nfunction unlisten() {\r\n if (!listening || layers.length > 0) return\r\n document.removeEventListener('keydown', onKeydown)\r\n document.removeEventListener('pointerdown', onPointerDown, true)\r\n listening = false\r\n}\r\n\r\nexport function useLayer(options: LayerOptions) {\r\n const layer: Layer = { options }\r\n\r\n const add = () => {\r\n if (layers.includes(layer)) return\r\n layers.push(layer)\r\n listen()\r\n }\r\n\r\n const remove = () => {\r\n const index = layers.indexOf(layer)\r\n if (index === -1) return\r\n layers.splice(index, 1)\r\n unlisten()\r\n }\r\n\r\n if (isClient) {\r\n watch(options.active, value => (value ? add() : remove()), { immediate: true })\r\n onBeforeUnmount(remove)\r\n }\r\n\r\n return {\r\n isTopLayer: () => top() === layer,\r\n }\r\n}\r\n","/**\r\n * Ranking for the command palette. Cheap enough to run on every keystroke\r\n * over a few thousand items, and ordered the way people expect:\r\n * exact › prefix › word start › substring › in-order letters.\r\n */\r\n\r\nexport type MatchRange = [start: number, end: number]\r\n\r\nexport interface MatchResult {\r\n score: number\r\n ranges: MatchRange[]\r\n}\r\n\r\nconst NO_MATCH: MatchResult = { score: 0, ranges: [] }\r\n\r\nexport function matchText(query: string, text: string): MatchResult {\r\n const q = query.trim().toLowerCase()\r\n if (!q) return { score: 1, ranges: [] }\r\n const t = text.toLowerCase()\r\n if (!t) return NO_MATCH\r\n\r\n if (t === q) return { score: 1000, ranges: [[0, t.length]] }\r\n if (t.startsWith(q)) return { score: 900 - Math.min(t.length - q.length, 100), ranges: [[0, q.length]] }\r\n\r\n const wordStart = findWordStart(t, q)\r\n if (wordStart > 0) return { score: 700 - Math.min(wordStart, 100), ranges: [[wordStart, wordStart + q.length]] }\r\n\r\n const index = t.indexOf(q)\r\n if (index > 0) return { score: 500 - Math.min(index, 100), ranges: [[index, index + q.length]] }\r\n\r\n return subsequence(q, t)\r\n}\r\n\r\nfunction findWordStart(t: string, q: string): number {\r\n let from = 0\r\n while (from < t.length) {\r\n const index = t.indexOf(q, from)\r\n if (index === -1) return -1\r\n if (index > 0 && /[\\s\\-_/.:]/.test(t[index - 1]!)) return index\r\n from = index + 1\r\n }\r\n return -1\r\n}\r\n\r\n/** Letters in order, not necessarily adjacent | \"gtst\" finds \"Go to settings\". */\r\nfunction subsequence(q: string, t: string): MatchResult {\r\n const ranges: MatchRange[] = []\r\n let ti = 0\r\n let score = 100\r\n let previous = -2\r\n for (const char of q) {\r\n if (char === ' ') continue\r\n const found = t.indexOf(char, ti)\r\n if (found === -1) return NO_MATCH\r\n if (found === previous + 1 && ranges.length) {\r\n ranges[ranges.length - 1]![1] = found + 1\r\n score += 12\r\n } else {\r\n ranges.push([found, found + 1])\r\n if (found === 0 || /[\\s\\-_/.:]/.test(t[found - 1]!)) score += 8\r\n }\r\n // Spread-out matches rank lower.\r\n score -= Math.min(found - ti, 10)\r\n previous = found\r\n ti = found + 1\r\n }\r\n return { score: Math.max(score, 1), ranges }\r\n}\r\n\r\n/** Split text into highlighted and plain runs. */\r\nexport function splitByRanges(text: string, ranges: MatchRange[]): Array<{ text: string, match: boolean }> {\r\n if (!ranges.length) return [{ text, match: false }]\r\n const parts: Array<{ text: string, match: boolean }> = []\r\n let cursor = 0\r\n for (const [start, end] of ranges) {\r\n if (start > cursor) parts.push({ text: text.slice(cursor, start), match: false })\r\n parts.push({ text: text.slice(start, end), match: true })\r\n cursor = end\r\n }\r\n if (cursor < text.length) parts.push({ text: text.slice(cursor), match: false })\r\n return parts\r\n}\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: teleports its content to `<body>`, but only once mounted.\r\n *\r\n * Server-rendered teleports to `body` never make it into the HTML, so a plain\r\n * `<Teleport>` hydrates against nothing and warns. Rendering nothing until\r\n * mount keeps server and client output identical | and overlays are closed on\r\n * first paint anyway.\r\n */\r\nimport { onMounted, ref } from 'vue'\r\n\r\nwithDefaults(defineProps<{ to?: string }>(), { to: 'body' })\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n</script>\r\n\r\n<template>\r\n <Teleport v-if=\"mounted\" :to=\"to\">\r\n <slot />\r\n </Teleport>\r\n</template>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: teleports its content to `<body>`, but only once mounted.\r\n *\r\n * Server-rendered teleports to `body` never make it into the HTML, so a plain\r\n * `<Teleport>` hydrates against nothing and warns. Rendering nothing until\r\n * mount keeps server and client output identical | and overlays are closed on\r\n * first paint anyway.\r\n */\r\nimport { onMounted, ref } from 'vue'\r\n\r\nwithDefaults(defineProps<{ to?: string }>(), { to: 'body' })\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n</script>\r\n\r\n<template>\r\n <Teleport v-if=\"mounted\" :to=\"to\">\r\n <slot />\r\n </Teleport>\r\n</template>\r\n","import type { VNode } from 'vue'\r\nimport { cloneVNode, Comment, defineComponent, Fragment, h, Text } from 'vue'\r\n\r\nfunction firstElement(nodes: VNode[] | undefined): VNode | undefined {\r\n if (!nodes) return undefined\r\n for (const node of nodes) {\r\n if (node.type === Comment) continue\r\n if (node.type === Fragment && Array.isArray(node.children)) {\r\n const found = firstElement(node.children as VNode[])\r\n if (found) return found\r\n continue\r\n }\r\n if (node.type === Text) {\r\n if (typeof node.children === 'string' && node.children.trim() === '') continue\r\n // Bare text can't hold attributes; give it an element.\r\n return h('span', null, node.children as string)\r\n }\r\n return node\r\n }\r\n return undefined\r\n}\r\n\r\n/**\r\n * Internal: renders its first child element and merges its own attributes\r\n * (ARIA, listeners, ids) onto it | no wrapper element.\r\n */\r\nexport const JSlot = defineComponent({\r\n name: 'JSlot',\r\n inheritAttrs: false,\r\n setup(_, { slots, attrs }) {\r\n return () => {\r\n const child = firstElement(slots.default?.())\r\n if (!child) return null\r\n // The consumer's own id wins; everything else is merged.\r\n const { id, ...rest } = attrs\r\n return cloneVNode(child, child.props?.id ? rest : { id, ...rest }, true)\r\n }\r\n },\r\n})\r\n","import type { InjectionKey, Ref } from 'vue'\r\n\r\nexport interface MenuRootContext {\r\n /** Close the whole menu tree. */\r\n close: (restoreFocus?: boolean) => void\r\n}\r\n\r\nexport interface MenuLevelContext {\r\n content: Ref<HTMLElement | null>\r\n /** Id of the submenu currently open at this level. */\r\n openSub: Ref<string | null>\r\n setOpenSub: (id: string | null) => void\r\n /** Close the open submenu shortly, unless the pointer is on its way into it. */\r\n scheduleSubClose: () => void\r\n cancelSubClose: () => void\r\n}\r\n\r\nexport const MENU_ROOT: InjectionKey<MenuRootContext> = Symbol('JDropdownMenu')\r\nexport const MENU_LEVEL: InjectionKey<MenuLevelContext> = Symbol('JDropdownMenuLevel')\r\n\r\nexport function getMenuItems(content: HTMLElement | null): HTMLElement[] {\r\n if (!content) return []\r\n return Array.from(content.querySelectorAll<HTMLElement>('[role^=\"menuitem\"]:not([aria-disabled=\"true\"])'))\r\n}\r\n","import type { Placement } from '@floating-ui/dom'\r\nimport type { CSSProperties, Ref } from 'vue'\r\nimport { autoUpdate, computePosition, flip, offset, shift, size } from '@floating-ui/dom'\r\nimport { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'\r\n\r\nexport type { Placement }\r\n\r\nexport interface FloatingOptions {\r\n placement?: Placement\r\n /** Gap between reference and floating element, in px. */\r\n offset?: number | { mainAxis?: number, crossAxis?: number }\r\n /** Make the floating element at least as wide as the reference. */\r\n matchWidth?: boolean\r\n /** Padding kept from the viewport edge, in px. */\r\n padding?: number\r\n}\r\n\r\nconst ORIGIN: Record<string, string> = {\r\n top: 'bottom',\r\n bottom: 'top',\r\n left: 'right',\r\n right: 'left',\r\n}\r\n\r\n/**\r\n * Position a floating element next to a reference element and keep it there\r\n * through scroll and resize. Coordinates are written to `left`/`top` so\r\n * `transform` stays free for enter/leave motion.\r\n */\r\nexport function useFloating(\r\n reference: Ref<HTMLElement | null>,\r\n floating: Ref<HTMLElement | null>,\r\n options: FloatingOptions | (() => FloatingOptions) = {},\r\n) {\r\n const read = () => (typeof options === 'function' ? options() : options)\r\n const x = ref(0)\r\n const y = ref(0)\r\n const placement = ref<Placement>(read().placement ?? 'bottom-start')\r\n const availableHeight = ref<number>()\r\n const referenceWidth = ref<number>()\r\n const stop = shallowRef<() => void>()\r\n\r\n async function update() {\r\n const referenceEl = reference.value\r\n const floatingEl = floating.value\r\n if (!referenceEl || !floatingEl) return\r\n const opts = read()\r\n const padding = opts.padding ?? 8\r\n const result = await computePosition(referenceEl, floatingEl, {\r\n strategy: 'fixed',\r\n placement: opts.placement ?? 'bottom-start',\r\n middleware: [\r\n offset(opts.offset ?? 6),\r\n flip({ padding }),\r\n shift({ padding }),\r\n size({\r\n padding,\r\n apply({ availableHeight: height, rects }) {\r\n availableHeight.value = Math.max(120, Math.floor(height))\r\n referenceWidth.value = rects.reference.width\r\n },\r\n }),\r\n ],\r\n })\r\n x.value = Math.round(result.x)\r\n y.value = Math.round(result.y)\r\n placement.value = result.placement\r\n }\r\n\r\n watch(\r\n [reference, floating],\r\n ([referenceEl, floatingEl]) => {\r\n stop.value?.()\r\n stop.value = undefined\r\n if (referenceEl && floatingEl) stop.value = autoUpdate(referenceEl, floatingEl, update)\r\n },\r\n { flush: 'post' },\r\n )\r\n\r\n onBeforeUnmount(() => stop.value?.())\r\n\r\n const side = computed(() => placement.value.split('-')[0] as 'top' | 'bottom' | 'left' | 'right')\r\n\r\n const styles = computed<CSSProperties>(() => {\r\n const align = placement.value.split('-')[1]\r\n const cross = side.value === 'top' || side.value === 'bottom'\r\n ? (align === 'start' ? 'left' : align === 'end' ? 'right' : 'center')\r\n : (align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center')\r\n const origin = side.value === 'top' || side.value === 'bottom'\r\n ? `${cross} ${ORIGIN[side.value]}`\r\n : `${ORIGIN[side.value]} ${cross}`\r\n const dir = side.value === 'top' ? 1 : side.value === 'bottom' ? -1 : 0\r\n return {\r\n 'position': 'fixed',\r\n 'left': `${x.value}px`,\r\n 'top': `${y.value}px`,\r\n 'transformOrigin': origin,\r\n 'minWidth': read().matchWidth && referenceWidth.value ? `${referenceWidth.value}px` : undefined,\r\n '--j-available-height': availableHeight.value ? `${availableHeight.value}px` : undefined,\r\n '--j-pop-dir': String(dir),\r\n '--j-pop-x': String(side.value === 'left' ? 1 : side.value === 'right' ? -1 : 0),\r\n } as CSSProperties\r\n })\r\n\r\n return { x, y, placement, side, styles, update }\r\n}\r\n","/**\r\n * Type-to-jump for lists. Characters typed in quick succession form a query;\r\n * repeating the same letter cycles through matches.\r\n */\r\nexport function useTypeahead(timeout = 500) {\r\n let query = ''\r\n let timer: ReturnType<typeof setTimeout> | undefined\r\n\r\n function search<T>(key: string, items: T[], getLabel: (item: T) => string, currentIndex: number): number {\r\n if (key.length !== 1 || (key === ' ' && query === '')) return -1\r\n clearTimeout(timer)\r\n timer = setTimeout(() => (query = ''), timeout)\r\n query += key.toLowerCase()\r\n\r\n const repeated = query.length > 1 && [...query].every(char => char === query[0])\r\n const needle = repeated ? query[0]! : query\r\n // A fresh search starts after the current item so repeated keys cycle.\r\n const start = repeated || query.length === 1 ? currentIndex + 1 : currentIndex\r\n for (let i = 0; i < items.length; i++) {\r\n const index = (start + i + items.length) % items.length\r\n if (getLabel(items[index]!).trim().toLowerCase().startsWith(needle)) return index\r\n }\r\n return -1\r\n }\r\n\r\n const isSearching = () => query.length > 0\r\n\r\n return { search, isSearching }\r\n}\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: the floating list shared by the root menu and submenus.\r\n * Owns positioning, keyboard navigation, typeahead and the layer.\r\n */\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport type { MenuLevelContext } from './context'\r\nimport { inject, nextTick, provide, ref, toRef, watch } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { useTypeahead } from '../../composables/useTypeahead'\r\nimport { focusElement } from '../../utils/dom'\r\nimport JPortal from '../primitives/JPortal.vue'\r\nimport { getMenuItems, MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nconst props = defineProps<{\r\n open: boolean\r\n reference: HTMLElement | null\r\n id: string\r\n labelledby?: string\r\n placement: Placement\r\n offset: number | { mainAxis?: number, crossAxis?: number }\r\n /** What to focus once open. */\r\n initialFocus: 'first' | 'last' | 'content' | 'none'\r\n isSub?: boolean\r\n}>()\r\n\r\nconst emit = defineEmits<{\r\n escape: []\r\n outside: [event: PointerEvent]\r\n /** Submenus only: ArrowLeft asks to go back to the parent. */\r\n back: []\r\n pointerenter: []\r\n}>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst content = ref<HTMLElement | null>(null)\r\nconst reference = toRef(props, 'reference')\r\n\r\nconst { styles } = useFloating(reference, content, () => ({ placement: props.placement, offset: props.offset }))\r\nconst typeahead = useTypeahead()\r\n\r\nuseLayer({\r\n active: toRef(props, 'open'),\r\n elements: () => [content.value, props.reference],\r\n onEscape: () => emit('escape'),\r\n onPointerDownOutside: event => emit('outside', event),\r\n})\r\n\r\n// Level context for the items inside this list.\r\nconst openSub = ref<string | null>(null)\r\nlet subTimer: ReturnType<typeof setTimeout> | undefined\r\nconst level: MenuLevelContext = {\r\n content,\r\n openSub,\r\n setOpenSub: (id) => {\r\n clearTimeout(subTimer)\r\n openSub.value = id\r\n },\r\n scheduleSubClose: () => {\r\n if (!openSub.value) return\r\n clearTimeout(subTimer)\r\n subTimer = setTimeout(() => (openSub.value = null), 180)\r\n },\r\n cancelSubClose: () => clearTimeout(subTimer),\r\n}\r\nprovide(MENU_LEVEL, level)\r\n\r\nwatch(\r\n () => props.open,\r\n async (value) => {\r\n if (!value) {\r\n openSub.value = null\r\n return\r\n }\r\n if (props.initialFocus === 'none') return\r\n await nextTick()\r\n const items = getMenuItems(content.value)\r\n if (props.initialFocus === 'first') focusElement(items[0] ?? content.value)\r\n else if (props.initialFocus === 'last') focusElement(items[items.length - 1] ?? content.value)\r\n else focusElement(content.value)\r\n },\r\n { flush: 'post' },\r\n)\r\n\r\nfunction move(delta: 1 | -1 | 'first' | 'last') {\r\n const items = getMenuItems(content.value)\r\n if (items.length === 0) return\r\n const current = items.indexOf(document.activeElement as HTMLElement)\r\n let next: number\r\n if (delta === 'first') next = 0\r\n else if (delta === 'last') next = items.length - 1\r\n else if (current === -1) next = delta === 1 ? 0 : items.length - 1\r\n else next = (current + delta + items.length) % items.length\r\n focusElement(items[next])\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n const { key } = event\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault()\r\n move(1)\r\n break\r\n case 'ArrowUp':\r\n event.preventDefault()\r\n move(-1)\r\n break\r\n case 'Home':\r\n case 'PageUp':\r\n event.preventDefault()\r\n move('first')\r\n break\r\n case 'End':\r\n case 'PageDown':\r\n event.preventDefault()\r\n move('last')\r\n break\r\n case 'ArrowLeft':\r\n if (props.isSub) {\r\n event.preventDefault()\r\n emit('back')\r\n }\r\n break\r\n case 'Tab':\r\n event.preventDefault()\r\n root.close(true)\r\n break\r\n case 'Enter':\r\n case ' ': {\r\n const active = document.activeElement as HTMLElement | null\r\n if (active && active !== content.value && content.value?.contains(active)) {\r\n event.preventDefault()\r\n active.click()\r\n }\r\n break\r\n }\r\n default:\r\n if (key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\r\n const items = getMenuItems(content.value)\r\n const index = typeahead.search(key, items, item => item.textContent ?? '', items.indexOf(document.activeElement as HTMLElement))\r\n if (index >= 0) focusElement(items[index])\r\n }\r\n }\r\n}\r\n\r\ndefineExpose({ content })\r\n</script>\r\n\r\n<template>\r\n <JPortal>\r\n <Transition name=\"j-pop\">\r\n <div\r\n v-if=\"open\"\r\n :id=\"id\"\r\n ref=\"content\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n class=\"j-menu j-popover-surface\"\r\n :class=\"{ 'j-menu--sub': isSub }\"\r\n :style=\"styles\"\r\n :aria-labelledby=\"labelledby\"\r\n aria-orientation=\"vertical\"\r\n @keydown=\"onKeydown\"\r\n @pointerenter=\"emit('pointerenter')\"\r\n >\r\n <slot />\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-menu {\r\n z-index: var(--juxt-z-popover);\r\n box-sizing: border-box;\r\n min-width: 11rem;\r\n max-width: calc(100vw - 16px);\r\n max-height: var(--j-available-height, 24rem);\r\n padding: var(--juxt-space-1);\r\n overflow-y: auto;\r\n overscroll-behavior: contain;\r\n outline: none;\r\n}\r\n\r\n.j-menu__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--juxt-space-2);\r\n min-height: var(--juxt-control-sm);\r\n padding: 0 var(--juxt-space-2);\r\n border-radius: var(--juxt-radius-xs);\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-md);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n text-decoration: none;\r\n cursor: pointer;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.j-menu__item:focus,\r\n.j-menu__item[aria-expanded='true'] {\r\n background: var(--juxt-surface-hover);\r\n}\r\n\r\n.j-menu__item[aria-disabled='true'] {\r\n color: var(--juxt-fg-disabled);\r\n cursor: not-allowed;\r\n}\r\n\r\n.j-menu__item--destructive {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-menu__item--destructive:focus {\r\n background: var(--juxt-danger-soft);\r\n}\r\n\r\n.j-menu__icon {\r\n display: inline-flex;\r\n flex: none;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__icon > svg {\r\n width: 1rem;\r\n height: 1rem;\r\n}\r\n\r\n.j-menu__item:focus .j-menu__icon {\r\n color: var(--juxt-fg-secondary);\r\n}\r\n\r\n.j-menu__item--destructive .j-menu__icon {\r\n color: inherit;\r\n}\r\n\r\n.j-menu__text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.j-menu__shortcut {\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n letter-spacing: 0.04em;\r\n}\r\n\r\n.j-menu__check {\r\n flex: none;\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-accent-text);\r\n opacity: 0;\r\n}\r\n\r\n.j-menu__check.is-checked {\r\n opacity: 1;\r\n}\r\n\r\n.j-menu__chevron {\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-right: -0.125rem;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__separator {\r\n height: 1px;\r\n margin: var(--juxt-space-1) calc(var(--juxt-space-1) * -1);\r\n background: var(--juxt-border-subtle);\r\n}\r\n\r\n.dark .j-menu__separator,\r\n[data-theme='dark'] .j-menu__separator {\r\n background: var(--juxt-border);\r\n}\r\n\r\n.j-menu__label {\r\n padding: var(--juxt-space-1-5) var(--juxt-space-2) var(--juxt-space-1);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: the floating list shared by the root menu and submenus.\r\n * Owns positioning, keyboard navigation, typeahead and the layer.\r\n */\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport type { MenuLevelContext } from './context'\r\nimport { inject, nextTick, provide, ref, toRef, watch } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { useTypeahead } from '../../composables/useTypeahead'\r\nimport { focusElement } from '../../utils/dom'\r\nimport JPortal from '../primitives/JPortal.vue'\r\nimport { getMenuItems, MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nconst props = defineProps<{\r\n open: boolean\r\n reference: HTMLElement | null\r\n id: string\r\n labelledby?: string\r\n placement: Placement\r\n offset: number | { mainAxis?: number, crossAxis?: number }\r\n /** What to focus once open. */\r\n initialFocus: 'first' | 'last' | 'content' | 'none'\r\n isSub?: boolean\r\n}>()\r\n\r\nconst emit = defineEmits<{\r\n escape: []\r\n outside: [event: PointerEvent]\r\n /** Submenus only: ArrowLeft asks to go back to the parent. */\r\n back: []\r\n pointerenter: []\r\n}>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst content = ref<HTMLElement | null>(null)\r\nconst reference = toRef(props, 'reference')\r\n\r\nconst { styles } = useFloating(reference, content, () => ({ placement: props.placement, offset: props.offset }))\r\nconst typeahead = useTypeahead()\r\n\r\nuseLayer({\r\n active: toRef(props, 'open'),\r\n elements: () => [content.value, props.reference],\r\n onEscape: () => emit('escape'),\r\n onPointerDownOutside: event => emit('outside', event),\r\n})\r\n\r\n// Level context for the items inside this list.\r\nconst openSub = ref<string | null>(null)\r\nlet subTimer: ReturnType<typeof setTimeout> | undefined\r\nconst level: MenuLevelContext = {\r\n content,\r\n openSub,\r\n setOpenSub: (id) => {\r\n clearTimeout(subTimer)\r\n openSub.value = id\r\n },\r\n scheduleSubClose: () => {\r\n if (!openSub.value) return\r\n clearTimeout(subTimer)\r\n subTimer = setTimeout(() => (openSub.value = null), 180)\r\n },\r\n cancelSubClose: () => clearTimeout(subTimer),\r\n}\r\nprovide(MENU_LEVEL, level)\r\n\r\nwatch(\r\n () => props.open,\r\n async (value) => {\r\n if (!value) {\r\n openSub.value = null\r\n return\r\n }\r\n if (props.initialFocus === 'none') return\r\n await nextTick()\r\n const items = getMenuItems(content.value)\r\n if (props.initialFocus === 'first') focusElement(items[0] ?? content.value)\r\n else if (props.initialFocus === 'last') focusElement(items[items.length - 1] ?? content.value)\r\n else focusElement(content.value)\r\n },\r\n { flush: 'post' },\r\n)\r\n\r\nfunction move(delta: 1 | -1 | 'first' | 'last') {\r\n const items = getMenuItems(content.value)\r\n if (items.length === 0) return\r\n const current = items.indexOf(document.activeElement as HTMLElement)\r\n let next: number\r\n if (delta === 'first') next = 0\r\n else if (delta === 'last') next = items.length - 1\r\n else if (current === -1) next = delta === 1 ? 0 : items.length - 1\r\n else next = (current + delta + items.length) % items.length\r\n focusElement(items[next])\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n const { key } = event\r\n switch (key) {\r\n case 'ArrowDown':\r\n event.preventDefault()\r\n move(1)\r\n break\r\n case 'ArrowUp':\r\n event.preventDefault()\r\n move(-1)\r\n break\r\n case 'Home':\r\n case 'PageUp':\r\n event.preventDefault()\r\n move('first')\r\n break\r\n case 'End':\r\n case 'PageDown':\r\n event.preventDefault()\r\n move('last')\r\n break\r\n case 'ArrowLeft':\r\n if (props.isSub) {\r\n event.preventDefault()\r\n emit('back')\r\n }\r\n break\r\n case 'Tab':\r\n event.preventDefault()\r\n root.close(true)\r\n break\r\n case 'Enter':\r\n case ' ': {\r\n const active = document.activeElement as HTMLElement | null\r\n if (active && active !== content.value && content.value?.contains(active)) {\r\n event.preventDefault()\r\n active.click()\r\n }\r\n break\r\n }\r\n default:\r\n if (key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey) {\r\n const items = getMenuItems(content.value)\r\n const index = typeahead.search(key, items, item => item.textContent ?? '', items.indexOf(document.activeElement as HTMLElement))\r\n if (index >= 0) focusElement(items[index])\r\n }\r\n }\r\n}\r\n\r\ndefineExpose({ content })\r\n</script>\r\n\r\n<template>\r\n <JPortal>\r\n <Transition name=\"j-pop\">\r\n <div\r\n v-if=\"open\"\r\n :id=\"id\"\r\n ref=\"content\"\r\n role=\"menu\"\r\n tabindex=\"-1\"\r\n class=\"j-menu j-popover-surface\"\r\n :class=\"{ 'j-menu--sub': isSub }\"\r\n :style=\"styles\"\r\n :aria-labelledby=\"labelledby\"\r\n aria-orientation=\"vertical\"\r\n @keydown=\"onKeydown\"\r\n @pointerenter=\"emit('pointerenter')\"\r\n >\r\n <slot />\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-menu {\r\n z-index: var(--juxt-z-popover);\r\n box-sizing: border-box;\r\n min-width: 11rem;\r\n max-width: calc(100vw - 16px);\r\n max-height: var(--j-available-height, 24rem);\r\n padding: var(--juxt-space-1);\r\n overflow-y: auto;\r\n overscroll-behavior: contain;\r\n outline: none;\r\n}\r\n\r\n.j-menu__item {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--juxt-space-2);\r\n min-height: var(--juxt-control-sm);\r\n padding: 0 var(--juxt-space-2);\r\n border-radius: var(--juxt-radius-xs);\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-md);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n text-decoration: none;\r\n cursor: pointer;\r\n outline: none;\r\n user-select: none;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.j-menu__item:focus,\r\n.j-menu__item[aria-expanded='true'] {\r\n background: var(--juxt-surface-hover);\r\n}\r\n\r\n.j-menu__item[aria-disabled='true'] {\r\n color: var(--juxt-fg-disabled);\r\n cursor: not-allowed;\r\n}\r\n\r\n.j-menu__item--destructive {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-menu__item--destructive:focus {\r\n background: var(--juxt-danger-soft);\r\n}\r\n\r\n.j-menu__icon {\r\n display: inline-flex;\r\n flex: none;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__icon > svg {\r\n width: 1rem;\r\n height: 1rem;\r\n}\r\n\r\n.j-menu__item:focus .j-menu__icon {\r\n color: var(--juxt-fg-secondary);\r\n}\r\n\r\n.j-menu__item--destructive .j-menu__icon {\r\n color: inherit;\r\n}\r\n\r\n.j-menu__text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n\r\n.j-menu__shortcut {\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n letter-spacing: 0.04em;\r\n}\r\n\r\n.j-menu__check {\r\n flex: none;\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-left: var(--juxt-space-4);\r\n color: var(--juxt-accent-text);\r\n opacity: 0;\r\n}\r\n\r\n.j-menu__check.is-checked {\r\n opacity: 1;\r\n}\r\n\r\n.j-menu__chevron {\r\n width: 0.875rem;\r\n height: 0.875rem;\r\n margin-right: -0.125rem;\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-menu__separator {\r\n height: 1px;\r\n margin: var(--juxt-space-1) calc(var(--juxt-space-1) * -1);\r\n background: var(--juxt-border-subtle);\r\n}\r\n\r\n.dark .j-menu__separator,\r\n[data-theme='dark'] .j-menu__separator {\r\n background: var(--juxt-border);\r\n}\r\n\r\n.j-menu__label {\r\n padding: var(--juxt-space-1-5) var(--juxt-space-2) var(--juxt-space-1);\r\n color: var(--juxt-fg-muted);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport { computed, nextTick, provide, ref, useId } from 'vue'\r\nimport { focusElement, unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport { MENU_ROOT } from './context'\r\nimport JMenuContent from './JMenuContent.vue'\r\n\r\nexport interface DropdownMenuProps {\r\n placement?: Placement\r\n /** Distance from the trigger, in px. */\r\n offset?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuProps>(), {\r\n placement: 'bottom-start',\r\n offset: 6,\r\n})\r\n\r\nconst open = defineModel<boolean>('open', { default: false })\r\n\r\ndefineSlots<{\r\n /** The element that opens the menu | usually a `JButton`. */\r\n trigger?: (props: { open: boolean }) => unknown\r\n default?: () => unknown\r\n}>()\r\n\r\nconst id = useId()\r\nconst triggerId = `j-${id}-trigger`\r\nconst menuId = `j-${id}-menu`\r\n\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst initialFocus = ref<'first' | 'last' | 'content'>('content')\r\n\r\nfunction show(focus: 'first' | 'last' | 'content') {\r\n if (props.disabled) return\r\n initialFocus.value = focus\r\n open.value = true\r\n}\r\n\r\nfunction close(restoreFocus = true) {\r\n if (!open.value) return\r\n open.value = false\r\n if (restoreFocus) nextTick(() => focusElement(triggerEl.value))\r\n}\r\n\r\nprovide(MENU_ROOT, { close })\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (open.value) return close(false)\r\n // `detail` is 0 when a click came from the keyboard (Enter / Space).\r\n show(event.detail === 0 ? 'first' : 'content')\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\r\n event.preventDefault()\r\n show(event.key === 'ArrowDown' ? 'first' : 'last')\r\n }\r\n}\r\n\r\nconst triggerProps = computed(() => ({\r\n 'id': triggerId,\r\n 'aria-haspopup': 'menu',\r\n 'aria-expanded': open.value,\r\n 'aria-controls': open.value ? menuId : undefined,\r\n 'data-state': open.value ? 'open' : 'closed',\r\n 'onClick': onClick,\r\n 'onKeydown': onKeydown,\r\n}))\r\n\r\ndefineExpose({ open: () => show('content'), close })\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot name=\"trigger\" :open=\"open\" />\r\n </JSlot>\r\n <JMenuContent\r\n :id=\"menuId\"\r\n :open=\"open\"\r\n :reference=\"triggerEl\"\r\n :labelledby=\"triggerEl?.id || triggerId\"\r\n :placement=\"placement\"\r\n :offset=\"offset\"\r\n :initial-focus=\"initialFocus\"\r\n @escape=\"close(true)\"\r\n @outside=\"close(false)\"\r\n >\r\n <slot />\r\n </JMenuContent>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Placement } from '../../composables/useFloating'\r\nimport { computed, nextTick, provide, ref, useId } from 'vue'\r\nimport { focusElement, unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport { MENU_ROOT } from './context'\r\nimport JMenuContent from './JMenuContent.vue'\r\n\r\nexport interface DropdownMenuProps {\r\n placement?: Placement\r\n /** Distance from the trigger, in px. */\r\n offset?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuProps>(), {\r\n placement: 'bottom-start',\r\n offset: 6,\r\n})\r\n\r\nconst open = defineModel<boolean>('open', { default: false })\r\n\r\ndefineSlots<{\r\n /** The element that opens the menu | usually a `JButton`. */\r\n trigger?: (props: { open: boolean }) => unknown\r\n default?: () => unknown\r\n}>()\r\n\r\nconst id = useId()\r\nconst triggerId = `j-${id}-trigger`\r\nconst menuId = `j-${id}-menu`\r\n\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst initialFocus = ref<'first' | 'last' | 'content'>('content')\r\n\r\nfunction show(focus: 'first' | 'last' | 'content') {\r\n if (props.disabled) return\r\n initialFocus.value = focus\r\n open.value = true\r\n}\r\n\r\nfunction close(restoreFocus = true) {\r\n if (!open.value) return\r\n open.value = false\r\n if (restoreFocus) nextTick(() => focusElement(triggerEl.value))\r\n}\r\n\r\nprovide(MENU_ROOT, { close })\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (open.value) return close(false)\r\n // `detail` is 0 when a click came from the keyboard (Enter / Space).\r\n show(event.detail === 0 ? 'first' : 'content')\r\n}\r\n\r\nfunction onKeydown(event: KeyboardEvent) {\r\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\r\n event.preventDefault()\r\n show(event.key === 'ArrowDown' ? 'first' : 'last')\r\n }\r\n}\r\n\r\nconst triggerProps = computed(() => ({\r\n 'id': triggerId,\r\n 'aria-haspopup': 'menu',\r\n 'aria-expanded': open.value,\r\n 'aria-controls': open.value ? menuId : undefined,\r\n 'data-state': open.value ? 'open' : 'closed',\r\n 'onClick': onClick,\r\n 'onKeydown': onKeydown,\r\n}))\r\n\r\ndefineExpose({ open: () => show('content'), close })\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot name=\"trigger\" :open=\"open\" />\r\n </JSlot>\r\n <JMenuContent\r\n :id=\"menuId\"\r\n :open=\"open\"\r\n :reference=\"triggerEl\"\r\n :labelledby=\"triggerEl?.id || triggerId\"\r\n :placement=\"placement\"\r\n :offset=\"offset\"\r\n :initial-focus=\"initialFocus\"\r\n @escape=\"close(true)\"\r\n @outside=\"close(false)\"\r\n >\r\n <slot />\r\n </JMenuContent>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue'\r\nimport { inject, ref } from 'vue'\r\nimport { IconCheck } from '../../icons'\r\nimport { focusElement } from '../../utils/dom'\r\nimport { MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nexport interface DropdownMenuItemProps {\r\n disabled?: boolean\r\n /** Styles the item as a destructive action. */\r\n destructive?: boolean\r\n /** A keyboard shortcut to display, e.g. `⌘D`. Display only. */\r\n shortcut?: string\r\n /** Render as another element, e.g. `a` or `NuxtLink` for navigation items. */\r\n as?: string | Component\r\n /**\r\n * Makes the item one choice in a set (e.g. a theme picker). `true` shows a\r\n * check at the end of the row. Leave undefined for a plain action.\r\n */\r\n checked?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuItemProps>(), { as: 'div', checked: undefined })\r\n\r\nconst emit = defineEmits<{\r\n /** Fired when the item is chosen. Call `event.preventDefault()` to keep the menu open. */\r\n select: [event: Event]\r\n}>()\r\n\r\ndefineSlots<{ default?: () => unknown, leading?: () => unknown }>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst level = inject(MENU_LEVEL)!\r\nconst el = ref<HTMLElement | null>(null)\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (props.disabled) {\r\n event.preventDefault()\r\n return\r\n }\r\n const selectEvent = new Event('select', { cancelable: true })\r\n emit('select', selectEvent)\r\n if (!selectEvent.defaultPrevented) root.close(true)\r\n}\r\n\r\nfunction resolve(target: unknown): HTMLElement | null {\r\n const value = target as { $el?: HTMLElement } | HTMLElement | null\r\n return value instanceof HTMLElement ? value : (value?.$el ?? null)\r\n}\r\n\r\n// Hover moves real focus, so pointer and keyboard always agree on one item.\r\nfunction onPointerMove() {\r\n level.scheduleSubClose()\r\n const node = resolve(el.value)\r\n if (props.disabled || !node || document.activeElement === node) return\r\n focusElement(node)\r\n}\r\n\r\nfunction onPointerLeave() {\r\n const node = resolve(el.value)\r\n if (node && document.activeElement === node) focusElement(level.content.value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <component\r\n :is=\"as\"\r\n ref=\"el\"\r\n :role=\"checked === undefined ? 'menuitem' : 'menuitemradio'\"\r\n :aria-checked=\"checked === undefined ? undefined : checked\"\r\n tabindex=\"-1\"\r\n class=\"j-menu__item\"\r\n :class=\"{ 'j-menu__item--destructive': destructive }\"\r\n :aria-disabled=\"disabled || undefined\"\r\n @click=\"onClick\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerleave=\"onPointerLeave\"\r\n >\r\n <span v-if=\"$slots.leading\" class=\"j-menu__icon\"><slot name=\"leading\" /></span>\r\n <span class=\"j-menu__text\"><slot /></span>\r\n <span v-if=\"shortcut\" class=\"j-menu__shortcut\">{{ shortcut }}</span>\r\n <IconCheck v-if=\"checked !== undefined\" class=\"j-menu__check\" :class=\"{ 'is-checked': checked }\" />\r\n </component>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue'\r\nimport { inject, ref } from 'vue'\r\nimport { IconCheck } from '../../icons'\r\nimport { focusElement } from '../../utils/dom'\r\nimport { MENU_LEVEL, MENU_ROOT } from './context'\r\n\r\nexport interface DropdownMenuItemProps {\r\n disabled?: boolean\r\n /** Styles the item as a destructive action. */\r\n destructive?: boolean\r\n /** A keyboard shortcut to display, e.g. `⌘D`. Display only. */\r\n shortcut?: string\r\n /** Render as another element, e.g. `a` or `NuxtLink` for navigation items. */\r\n as?: string | Component\r\n /**\r\n * Makes the item one choice in a set (e.g. a theme picker). `true` shows a\r\n * check at the end of the row. Leave undefined for a plain action.\r\n */\r\n checked?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<DropdownMenuItemProps>(), { as: 'div', checked: undefined })\r\n\r\nconst emit = defineEmits<{\r\n /** Fired when the item is chosen. Call `event.preventDefault()` to keep the menu open. */\r\n select: [event: Event]\r\n}>()\r\n\r\ndefineSlots<{ default?: () => unknown, leading?: () => unknown }>()\r\n\r\nconst root = inject(MENU_ROOT)!\r\nconst level = inject(MENU_LEVEL)!\r\nconst el = ref<HTMLElement | null>(null)\r\n\r\nfunction onClick(event: MouseEvent) {\r\n if (props.disabled) {\r\n event.preventDefault()\r\n return\r\n }\r\n const selectEvent = new Event('select', { cancelable: true })\r\n emit('select', selectEvent)\r\n if (!selectEvent.defaultPrevented) root.close(true)\r\n}\r\n\r\nfunction resolve(target: unknown): HTMLElement | null {\r\n const value = target as { $el?: HTMLElement } | HTMLElement | null\r\n return value instanceof HTMLElement ? value : (value?.$el ?? null)\r\n}\r\n\r\n// Hover moves real focus, so pointer and keyboard always agree on one item.\r\nfunction onPointerMove() {\r\n level.scheduleSubClose()\r\n const node = resolve(el.value)\r\n if (props.disabled || !node || document.activeElement === node) return\r\n focusElement(node)\r\n}\r\n\r\nfunction onPointerLeave() {\r\n const node = resolve(el.value)\r\n if (node && document.activeElement === node) focusElement(level.content.value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <component\r\n :is=\"as\"\r\n ref=\"el\"\r\n :role=\"checked === undefined ? 'menuitem' : 'menuitemradio'\"\r\n :aria-checked=\"checked === undefined ? undefined : checked\"\r\n tabindex=\"-1\"\r\n class=\"j-menu__item\"\r\n :class=\"{ 'j-menu__item--destructive': destructive }\"\r\n :aria-disabled=\"disabled || undefined\"\r\n @click=\"onClick\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerleave=\"onPointerLeave\"\r\n >\r\n <span v-if=\"$slots.leading\" class=\"j-menu__icon\"><slot name=\"leading\" /></span>\r\n <span class=\"j-menu__text\"><slot /></span>\r\n <span v-if=\"shortcut\" class=\"j-menu__shortcut\">{{ shortcut }}</span>\r\n <IconCheck v-if=\"checked !== undefined\" class=\"j-menu__check\" :class=\"{ 'is-checked': checked }\" />\r\n </component>\r\n</template>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: lays out label, control, description and error for form fields.\r\n * Not exported | every field component composes it.\r\n */\r\ndefineProps<{\r\n id: string\r\n labelId: string\r\n descriptionId: string\r\n errorId: string\r\n label?: string\r\n description?: string\r\n errorMessage?: string\r\n showDescription?: boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Render the label as a plain element when the control isn't labelable (e.g. a button). */\r\n labelFor?: string | null\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div class=\"j-field\" :class=\"{ 'is-disabled': disabled }\">\r\n <component\r\n :is=\"labelFor === null ? 'span' : 'label'\"\r\n v-if=\"label || $slots.label\"\r\n :id=\"labelId\"\r\n class=\"j-field__label\"\r\n :for=\"labelFor === null ? undefined : labelFor ?? id\"\r\n >\r\n <slot name=\"label\">{{ label }}</slot>\r\n <span v-if=\"required\" class=\"j-field__required\" aria-hidden=\"true\">*</span>\r\n </component>\r\n <slot />\r\n <div class=\"j-field__messages\">\r\n <Transition name=\"j-field-message\" mode=\"out-in\">\r\n <p v-if=\"errorMessage\" :id=\"errorId\" :key=\"errorMessage\" class=\"j-field__error\">\r\n {{ errorMessage }}\r\n </p>\r\n <p v-else-if=\"showDescription\" :id=\"descriptionId\" class=\"j-field__description\">\r\n {{ description }}\r\n </p>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--juxt-space-1-5);\r\n min-width: 0;\r\n font-family: var(--juxt-font-sans);\r\n}\r\n\r\n.j-field__label {\r\n display: inline-flex;\r\n align-items: baseline;\r\n gap: var(--juxt-space-0-5);\r\n width: fit-content;\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-sm);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n}\r\n\r\n.j-field.is-disabled .j-field__label {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__required {\r\n color: var(--juxt-fg-muted);\r\n font-weight: var(--juxt-weight-regular);\r\n}\r\n\r\n.j-field__messages:empty {\r\n display: none;\r\n}\r\n\r\n.j-field__description,\r\n.j-field__error {\r\n margin: 0;\r\n font-size: var(--juxt-text-xs);\r\n line-height: var(--juxt-leading-normal);\r\n}\r\n\r\n.j-field__description {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__error {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-field-message-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-normal) var(--juxt-ease-out);\r\n}\r\n\r\n.j-field-message-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-field-message-enter-from {\r\n opacity: 0;\r\n transform: translateY(calc(var(--juxt-motion-shift) * -0.5));\r\n}\r\n\r\n.j-field-message-leave-to {\r\n opacity: 0;\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\n/**\r\n * Internal: lays out label, control, description and error for form fields.\r\n * Not exported | every field component composes it.\r\n */\r\ndefineProps<{\r\n id: string\r\n labelId: string\r\n descriptionId: string\r\n errorId: string\r\n label?: string\r\n description?: string\r\n errorMessage?: string\r\n showDescription?: boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Render the label as a plain element when the control isn't labelable (e.g. a button). */\r\n labelFor?: string | null\r\n}>()\r\n</script>\r\n\r\n<template>\r\n <div class=\"j-field\" :class=\"{ 'is-disabled': disabled }\">\r\n <component\r\n :is=\"labelFor === null ? 'span' : 'label'\"\r\n v-if=\"label || $slots.label\"\r\n :id=\"labelId\"\r\n class=\"j-field__label\"\r\n :for=\"labelFor === null ? undefined : labelFor ?? id\"\r\n >\r\n <slot name=\"label\">{{ label }}</slot>\r\n <span v-if=\"required\" class=\"j-field__required\" aria-hidden=\"true\">*</span>\r\n </component>\r\n <slot />\r\n <div class=\"j-field__messages\">\r\n <Transition name=\"j-field-message\" mode=\"out-in\">\r\n <p v-if=\"errorMessage\" :id=\"errorId\" :key=\"errorMessage\" class=\"j-field__error\">\r\n {{ errorMessage }}\r\n </p>\r\n <p v-else-if=\"showDescription\" :id=\"descriptionId\" class=\"j-field__description\">\r\n {{ description }}\r\n </p>\r\n </Transition>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-field {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--juxt-space-1-5);\r\n min-width: 0;\r\n font-family: var(--juxt-font-sans);\r\n}\r\n\r\n.j-field__label {\r\n display: inline-flex;\r\n align-items: baseline;\r\n gap: var(--juxt-space-0-5);\r\n width: fit-content;\r\n color: var(--juxt-fg);\r\n font-size: var(--juxt-text-sm);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: var(--juxt-tracking-tight);\r\n}\r\n\r\n.j-field.is-disabled .j-field__label {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__required {\r\n color: var(--juxt-fg-muted);\r\n font-weight: var(--juxt-weight-regular);\r\n}\r\n\r\n.j-field__messages:empty {\r\n display: none;\r\n}\r\n\r\n.j-field__description,\r\n.j-field__error {\r\n margin: 0;\r\n font-size: var(--juxt-text-xs);\r\n line-height: var(--juxt-leading-normal);\r\n}\r\n\r\n.j-field__description {\r\n color: var(--juxt-fg-muted);\r\n}\r\n\r\n.j-field__error {\r\n color: var(--juxt-danger-text);\r\n}\r\n\r\n.j-field-message-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-normal) var(--juxt-ease-out);\r\n}\r\n\r\n.j-field-message-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-field-message-enter-from {\r\n opacity: 0;\r\n transform: translateY(calc(var(--juxt-motion-shift) * -0.5));\r\n}\r\n\r\n.j-field-message-leave-to {\r\n opacity: 0;\r\n}\r\n}\r\n</style>\r\n","import type { MaybeRefOrGetter } from 'vue'\r\nimport { computed, toValue, useId } from 'vue'\r\n\r\nexport interface FieldProps {\r\n /** Visible label. Also used as the accessible name. */\r\n label?: string\r\n /** Supporting text under the control. Hidden while an error message is shown. */\r\n description?: string\r\n /** An error message, or `true` to mark the field invalid without a message. */\r\n error?: string | boolean\r\n required?: boolean\r\n disabled?: boolean\r\n /** Id for the control. Generated when omitted. */\r\n id?: string\r\n}\r\n\r\n/** Ids and ARIA wiring shared by every form control. */\r\nexport function useField(props: MaybeRefOrGetter<FieldProps>) {\r\n const generated = useId()\r\n const p = () => toValue(props)\r\n\r\n const id = computed(() => p().id ?? `j-${generated}`)\r\n const labelId = computed(() => `${id.value}-label`)\r\n const descriptionId = computed(() => `${id.value}-description`)\r\n const errorId = computed(() => `${id.value}-error`)\r\n\r\n const invalid = computed(() => !!p().error)\r\n const errorMessage = computed(() => (typeof p().error === 'string' ? (p().error as string) : ''))\r\n const showDescription = computed(() => !!p().description && !errorMessage.value)\r\n\r\n const describedBy = computed(() => {\r\n const ids: string[] = []\r\n if (errorMessage.value) ids.push(errorId.value)\r\n else if (p().description) ids.push(descriptionId.value)\r\n return ids.length ? ids.join(' ') : undefined\r\n })\r\n\r\n return { id, labelId, descriptionId, errorId, invalid, errorMessage, showDescription, describedBy }\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { computed, onMounted, ref } from 'vue'\r\nimport { formatHotkey } from '../../composables/useHotkey'\r\n\r\nexport interface KbdProps {\r\n /**\r\n * A shortcut in hotkey syntax, e.g. `mod+k` or `shift+enter`. `mod` renders\r\n * as ⌘ on Apple platforms and Ctrl elsewhere. Use the slot for literal keys.\r\n */\r\n keys?: string\r\n size?: 'sm' | 'md'\r\n}\r\n\r\nconst props = withDefaults(defineProps<KbdProps>(), { size: 'md' })\r\n\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\n// Platform glyphs are only known in the browser; resolve after mount so\r\n// server and client render the same markup.\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n\r\nconst parts = computed(() => {\r\n if (!props.keys) return []\r\n if (!mounted.value) return props.keys.split('+').map(part => (part === 'mod' ? 'Ctrl' : part.length === 1 ? part.toUpperCase() : part))\r\n return formatHotkey(props.keys)\r\n})\r\n</script>\r\n\r\n<template>\r\n <span v-if=\"keys\" class=\"j-kbd-group\" :class=\"`j-kbd-group--${size}`\">\r\n <kbd v-for=\"(part, i) in parts\" :key=\"i\" class=\"j-kbd\">{{ part }}</kbd>\r\n </span>\r\n <kbd v-else class=\"j-kbd\" :class=\"{ 'j-kbd--sm': size === 'sm' }\"><slot /></kbd>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-kbd-group {\r\n display: inline-flex;\r\n gap: 3px;\r\n vertical-align: middle;\r\n}\r\n\r\n.j-kbd-group--sm .j-kbd,\r\n.j-kbd--sm {\r\n min-width: 1.0625rem;\r\n height: 1.0625rem;\r\n font-size: 0.625rem;\r\n}\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { computed, onMounted, ref } from 'vue'\r\nimport { formatHotkey } from '../../composables/useHotkey'\r\n\r\nexport interface KbdProps {\r\n /**\r\n * A shortcut in hotkey syntax, e.g. `mod+k` or `shift+enter`. `mod` renders\r\n * as ⌘ on Apple platforms and Ctrl elsewhere. Use the slot for literal keys.\r\n */\r\n keys?: string\r\n size?: 'sm' | 'md'\r\n}\r\n\r\nconst props = withDefaults(defineProps<KbdProps>(), { size: 'md' })\r\n\r\ndefineSlots<{ default?: () => unknown }>()\r\n\r\n// Platform glyphs are only known in the browser; resolve after mount so\r\n// server and client render the same markup.\r\nconst mounted = ref(false)\r\nonMounted(() => (mounted.value = true))\r\n\r\nconst parts = computed(() => {\r\n if (!props.keys) return []\r\n if (!mounted.value) return props.keys.split('+').map(part => (part === 'mod' ? 'Ctrl' : part.length === 1 ? part.toUpperCase() : part))\r\n return formatHotkey(props.keys)\r\n})\r\n</script>\r\n\r\n<template>\r\n <span v-if=\"keys\" class=\"j-kbd-group\" :class=\"`j-kbd-group--${size}`\">\r\n <kbd v-for=\"(part, i) in parts\" :key=\"i\" class=\"j-kbd\">{{ part }}</kbd>\r\n </span>\r\n <kbd v-else class=\"j-kbd\" :class=\"{ 'j-kbd--sm': size === 'sm' }\"><slot /></kbd>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-kbd-group {\r\n display: inline-flex;\r\n gap: 3px;\r\n vertical-align: middle;\r\n}\r\n\r\n.j-kbd-group--sm .j-kbd,\r\n.j-kbd--sm {\r\n min-width: 1.0625rem;\r\n height: 1.0625rem;\r\n font-size: 0.625rem;\r\n}\r\n}\r\n</style>\r\n","<script lang=\"ts\">\r\n// Shared across every tooltip: once one has been shown, neighbours open\r\n// instantly for a moment. Scanning a toolbar shouldn't mean waiting at each icon.\r\nlet warmUntil = 0\r\nconst WARM_WINDOW = 400\r\n</script>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onBeforeUnmount, ref, useId } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport JPortal from '../primitives/JPortal.vue'\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip text. Use the `content` slot for richer content. */\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n /** Hover delay before opening, in ms. Keyboard focus opens immediately. */\r\n delay?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<TooltipProps>(), {\r\n side: 'top',\r\n align: 'center',\r\n delay: 450,\r\n})\r\n\r\ndefineSlots<{\r\n default?: () => unknown\r\n content?: () => unknown\r\n}>()\r\n\r\nconst id = `j-${useId()}-tooltip`\r\nconst open = ref(false)\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst floating = ref<HTMLElement | null>(null)\r\n\r\nconst placement = computed(() => (props.align === 'center' ? props.side : `${props.side}-${props.align}` as const))\r\nconst { styles } = useFloating(triggerEl, floating, () => ({ placement: placement.value, offset: 6 }))\r\n\r\nuseLayer({\r\n active: open,\r\n elements: () => [triggerEl.value, floating.value],\r\n onEscape: () => hide(true),\r\n})\r\n\r\nlet openTimer: ReturnType<typeof setTimeout> | undefined\r\nlet closeTimer: ReturnType<typeof setTimeout> | undefined\r\n// After a click, stay quiet until the pointer leaves | the user is acting, not reading.\r\nlet suppressed = false\r\n\r\nfunction show(immediate = false) {\r\n if (props.disabled || suppressed) return\r\n clearTimeout(closeTimer)\r\n if (open.value) return\r\n clearTimeout(openTimer)\r\n if (immediate || Date.now() < warmUntil) open.value = true\r\n else openTimer = setTimeout(() => (open.value = true), props.delay)\r\n}\r\n\r\nfunction hide(immediate = false) {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n const close = () => {\r\n if (open.value) warmUntil = Date.now() + WARM_WINDOW\r\n open.value = false\r\n }\r\n if (immediate) close()\r\n // A short grace period lets the pointer travel onto the tooltip itself.\r\n else closeTimer = setTimeout(close, 80)\r\n}\r\n\r\nonBeforeUnmount(() => {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n})\r\n\r\nconst triggerProps = computed(() => ({\r\n 'aria-describedby': props.disabled ? undefined : id,\r\n 'onPointerenter': (event: PointerEvent) => event.pointerType === 'mouse' && show(),\r\n 'onPointerleave': (event: PointerEvent) => {\r\n suppressed = false\r\n if (event.pointerType === 'mouse') hide()\r\n },\r\n 'onPointerdown': () => {\r\n suppressed = true\r\n hide(true)\r\n },\r\n 'onFocus': (event: FocusEvent) => {\r\n const target = event.target as HTMLElement\r\n if (target.matches(':focus-visible')) show(true)\r\n },\r\n 'onBlur': () => hide(true),\r\n}))\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot />\r\n </JSlot>\r\n <span v-if=\"!disabled\" :id=\"id\" class=\"j-sr-only\">\r\n <slot name=\"content\">{{ content }}</slot>\r\n </span>\r\n <JPortal>\r\n <Transition name=\"j-tooltip\">\r\n <div\r\n v-if=\"open\"\r\n ref=\"floating\"\r\n class=\"j-tooltip\"\r\n :style=\"styles\"\r\n aria-hidden=\"true\"\r\n data-juxt-layer-ignore\r\n @pointerenter=\"show(true)\"\r\n @pointerleave=\"hide()\"\r\n >\r\n <slot name=\"content\">\r\n {{ content }}\r\n </slot>\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-tooltip {\r\n z-index: var(--juxt-z-tooltip);\r\n box-sizing: border-box;\r\n max-width: min(17.5rem, calc(100vw - 16px));\r\n padding: var(--juxt-space-1) var(--juxt-space-2);\r\n border: 1px solid var(--juxt-tooltip-border);\r\n border-radius: var(--juxt-radius-sm);\r\n background: var(--juxt-tooltip-bg);\r\n box-shadow: var(--juxt-shadow-sm);\r\n color: var(--juxt-tooltip-fg);\r\n font-family: var(--juxt-font-sans);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: 0;\r\n overflow-wrap: break-word;\r\n pointer-events: auto;\r\n}\r\n\r\n.j-tooltip .j-kbd {\r\n height: 1rem;\r\n min-width: 1rem;\r\n margin-left: var(--juxt-space-1);\r\n border-color: rgb(255 255 255 / 0.14);\r\n background: rgb(255 255 255 / 0.08);\r\n color: rgb(255 255 255 / 0.72);\r\n}\r\n\r\n.j-tooltip-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-fast) var(--juxt-ease-out);\r\n}\r\n\r\n.j-tooltip-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-tooltip-enter-from,\r\n.j-tooltip-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.j-tooltip-enter-from {\r\n transform: translate(\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-x, 0)),\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-dir, 0))\r\n );\r\n}\r\n}\r\n</style>\r\n","<script lang=\"ts\">\r\n// Shared across every tooltip: once one has been shown, neighbours open\r\n// instantly for a moment. Scanning a toolbar shouldn't mean waiting at each icon.\r\nlet warmUntil = 0\r\nconst WARM_WINDOW = 400\r\n</script>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, onBeforeUnmount, ref, useId } from 'vue'\r\nimport { useFloating } from '../../composables/useFloating'\r\nimport { useLayer } from '../../composables/useLayer'\r\nimport { unrefElement } from '../../utils/dom'\r\nimport { JSlot } from '../primitives/JSlot'\r\nimport JPortal from '../primitives/JPortal.vue'\r\n\r\nexport interface TooltipProps {\r\n /** Tooltip text. Use the `content` slot for richer content. */\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n /** Hover delay before opening, in ms. Keyboard focus opens immediately. */\r\n delay?: number\r\n disabled?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<TooltipProps>(), {\r\n side: 'top',\r\n align: 'center',\r\n delay: 450,\r\n})\r\n\r\ndefineSlots<{\r\n default?: () => unknown\r\n content?: () => unknown\r\n}>()\r\n\r\nconst id = `j-${useId()}-tooltip`\r\nconst open = ref(false)\r\nconst triggerRef = ref()\r\nconst triggerEl = computed(() => unrefElement(triggerRef.value))\r\nconst floating = ref<HTMLElement | null>(null)\r\n\r\nconst placement = computed(() => (props.align === 'center' ? props.side : `${props.side}-${props.align}` as const))\r\nconst { styles } = useFloating(triggerEl, floating, () => ({ placement: placement.value, offset: 6 }))\r\n\r\nuseLayer({\r\n active: open,\r\n elements: () => [triggerEl.value, floating.value],\r\n onEscape: () => hide(true),\r\n})\r\n\r\nlet openTimer: ReturnType<typeof setTimeout> | undefined\r\nlet closeTimer: ReturnType<typeof setTimeout> | undefined\r\n// After a click, stay quiet until the pointer leaves | the user is acting, not reading.\r\nlet suppressed = false\r\n\r\nfunction show(immediate = false) {\r\n if (props.disabled || suppressed) return\r\n clearTimeout(closeTimer)\r\n if (open.value) return\r\n clearTimeout(openTimer)\r\n if (immediate || Date.now() < warmUntil) open.value = true\r\n else openTimer = setTimeout(() => (open.value = true), props.delay)\r\n}\r\n\r\nfunction hide(immediate = false) {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n const close = () => {\r\n if (open.value) warmUntil = Date.now() + WARM_WINDOW\r\n open.value = false\r\n }\r\n if (immediate) close()\r\n // A short grace period lets the pointer travel onto the tooltip itself.\r\n else closeTimer = setTimeout(close, 80)\r\n}\r\n\r\nonBeforeUnmount(() => {\r\n clearTimeout(openTimer)\r\n clearTimeout(closeTimer)\r\n})\r\n\r\nconst triggerProps = computed(() => ({\r\n 'aria-describedby': props.disabled ? undefined : id,\r\n 'onPointerenter': (event: PointerEvent) => event.pointerType === 'mouse' && show(),\r\n 'onPointerleave': (event: PointerEvent) => {\r\n suppressed = false\r\n if (event.pointerType === 'mouse') hide()\r\n },\r\n 'onPointerdown': () => {\r\n suppressed = true\r\n hide(true)\r\n },\r\n 'onFocus': (event: FocusEvent) => {\r\n const target = event.target as HTMLElement\r\n if (target.matches(':focus-visible')) show(true)\r\n },\r\n 'onBlur': () => hide(true),\r\n}))\r\n</script>\r\n\r\n<template>\r\n <JSlot ref=\"triggerRef\" v-bind=\"triggerProps\">\r\n <slot />\r\n </JSlot>\r\n <span v-if=\"!disabled\" :id=\"id\" class=\"j-sr-only\">\r\n <slot name=\"content\">{{ content }}</slot>\r\n </span>\r\n <JPortal>\r\n <Transition name=\"j-tooltip\">\r\n <div\r\n v-if=\"open\"\r\n ref=\"floating\"\r\n class=\"j-tooltip\"\r\n :style=\"styles\"\r\n aria-hidden=\"true\"\r\n data-juxt-layer-ignore\r\n @pointerenter=\"show(true)\"\r\n @pointerleave=\"hide()\"\r\n >\r\n <slot name=\"content\">\r\n {{ content }}\r\n </slot>\r\n </div>\r\n </Transition>\r\n </JPortal>\r\n</template>\r\n\r\n<style>\r\n@layer theme, base, juxt, components, utilities;\r\n@layer juxt {\r\n.j-tooltip {\r\n z-index: var(--juxt-z-tooltip);\r\n box-sizing: border-box;\r\n max-width: min(17.5rem, calc(100vw - 16px));\r\n padding: var(--juxt-space-1) var(--juxt-space-2);\r\n border: 1px solid var(--juxt-tooltip-border);\r\n border-radius: var(--juxt-radius-sm);\r\n background: var(--juxt-tooltip-bg);\r\n box-shadow: var(--juxt-shadow-sm);\r\n color: var(--juxt-tooltip-fg);\r\n font-family: var(--juxt-font-sans);\r\n font-size: var(--juxt-text-xs);\r\n font-weight: var(--juxt-weight-medium);\r\n line-height: var(--juxt-leading-snug);\r\n letter-spacing: 0;\r\n overflow-wrap: break-word;\r\n pointer-events: auto;\r\n}\r\n\r\n.j-tooltip .j-kbd {\r\n height: 1rem;\r\n min-width: 1rem;\r\n margin-left: var(--juxt-space-1);\r\n border-color: rgb(255 255 255 / 0.14);\r\n background: rgb(255 255 255 / 0.08);\r\n color: rgb(255 255 255 / 0.72);\r\n}\r\n\r\n.j-tooltip-enter-active {\r\n transition:\r\n opacity var(--juxt-duration-fast) var(--juxt-ease-out),\r\n transform var(--juxt-duration-fast) var(--juxt-ease-out);\r\n}\r\n\r\n.j-tooltip-leave-active {\r\n transition: opacity var(--juxt-duration-instant) var(--juxt-ease-in);\r\n}\r\n\r\n.j-tooltip-enter-from,\r\n.j-tooltip-leave-to {\r\n opacity: 0;\r\n}\r\n\r\n.j-tooltip-enter-from {\r\n transform: translate(\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-x, 0)),\r\n calc(var(--juxt-motion-shift) * 0.5 * var(--j-pop-dir, 0))\r\n );\r\n}\r\n}\r\n</style>\r\n"],"mappings":"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"}