@bazza-ui/react 0.1.0-canary.10 → 0.1.0-canary.11

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,"sources":["../src/utils/item-equality.ts","../src/utils/items.ts"],"names":["defaultItemEquality","item","value","compareItemEquality","comparer","itemIncludes","collection","removeItem","entryKey","resolveItemFromItems","items","valueKey","entry","i","label","resolveLabelFromItems","mergeKeywords","keywords","extra","additions","k","merged","keyword"],"mappings":"AAaO,qrBAAMA,CAAAA,CAA4C,CAACC,CAAAA,CAAMC,CAAAA,CAAAA,EAC9D,MAAA,CAAO,EAAA,CAAGD,CAAAA,CAAMC,CAAK,CAAA,CAMhB,SAASC,CAAAA,CACdF,CAAAA,CACAC,CAAAA,CACAE,CAAAA,CACS,CAET,OAAIH,CAAAA,EAAQ,IAAA,EAAQC,CAAAA,EAAS,IAAA,CACpB,MAAA,CAAO,EAAA,CAAGD,CAAAA,CAAMC,CAAK,CAAA,CAEvBE,CAAAA,CAASH,CAAAA,CAAMC,CAAK,CAC7B,CAKO,SAASG,CAAAA,CACdC,CAAAA,CACAJ,CAAAA,CACAE,CAAAA,CACS,CACT,MAAI,CAACE,CAAAA,EAAcA,CAAAA,CAAW,MAAA,GAAW,CAAA,CAChC,CAAA,CAAA,CAEFA,CAAAA,CAAW,IAAA,CAAML,CAAAA,EAClBA,CAAAA,GAAS,KAAA,CAAA,CACJ,CAAA,CAAA,CAEFE,CAAAA,CAAoBF,CAAAA,CAAMC,CAAAA,CAAOE,CAAQ,CACjD,CACH,CA0BO,SAASG,CAAAA,CACdD,CAAAA,CACAJ,CAAAA,CACAE,CAAAA,CACS,CACT,OAAOE,CAAAA,CAAW,MAAA,CACfL,CAAAA,EAAS,CAACE,CAAAA,CAAoBF,CAAAA,CAAMC,CAAAA,CAAOE,CAAQ,CACtD,CACF,CC3CA,SAASI,CAAAA,CAASN,CAAAA,CAA8B,CAC9C,wBAAOA,CAAAA,SAAgB,IACzB,CAMO,SAASO,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAC0B,CAC1B,EAAA,CAAI,CAACD,CAAAA,CAAO,MAAA,CAEZ,EAAA,CAAI,KAAA,CAAM,OAAA,CAAQA,CAAK,CAAA,CAAG,CACxB,IAAME,CAAAA,CAAQF,CAAAA,CAAM,IAAA,CAAMG,CAAAA,EAAML,CAAAA,CAASK,CAAAA,CAAE,KAAK,CAAA,GAAMF,CAAQ,CAAA,CAC9D,OAAKC,CAAAA,CACE,CAAE,KAAA,CAAOA,CAAAA,CAAM,KAAA,CAAO,QAAA,CAAUA,CAAAA,CAAM,QAAS,CAAA,CAD1C,KAAA,CAEd,CAEA,IAAME,CAAAA,CAAQJ,CAAAA,CAAMC,CAAQ,CAAA,CAC5B,EAAA,CAAIG,CAAAA,GAAU,KAAA,CAAA,CACd,MAAO,CAAE,KAAA,CAAAA,CAAM,CACjB,CAMO,SAASC,CAAAA,CACdL,CAAAA,CACAC,CAAAA,CAC6B,CAC7B,uBAAOF,CAAAA,iBAAqBC,CAAAA,CAAOC,CAAQ,CAAA,6BAAG,OAChD,CAOO,SAASK,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACsB,CACtB,IAAMC,CAAAA,CAAYD,CAAAA,CAAM,MAAA,CAAQE,CAAAA,EAAmB,CAAA,CAAQA,CAAE,CAAA,CAC7D,EAAA,CAAID,CAAAA,CAAU,MAAA,GAAW,CAAA,CAAG,OAAOF,CAAAA,CAEnC,IAAMI,CAAAA,CAASJ,CAAAA,CAAW,CAAC,GAAGA,CAAQ,CAAA,CAAI,CAAC,CAAA,CAC3C,GAAA,CAAA,IAAWK,EAAAA,GAAWH,CAAAA,CACfE,CAAAA,CAAO,QAAA,CAASC,CAAO,CAAA,EAAGD,CAAAA,CAAO,IAAA,CAAKC,CAAO,CAAA,CAEpD,OAAOD,CACT,CAAA,wGAAA","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-5T5B5SPR.cjs","sourcesContent":["/**\n * Type for custom item equality comparison functions.\n * Used to compare object values in Select and Combobox components.\n */\nexport type ItemEqualityComparer<Value = unknown> = (\n itemValue: Value,\n value: Value,\n) => boolean\n\n/**\n * Default equality comparer using Object.is.\n * Handles primitives and object reference equality.\n */\nexport const defaultItemEquality: ItemEqualityComparer = (item, value) =>\n Object.is(item, value)\n\n/**\n * Compare two items for equality using a custom comparer.\n * Handles null/undefined values separately using Object.is.\n */\nexport function compareItemEquality<Value>(\n item: Value | null | undefined,\n value: Value | null | undefined,\n comparer: ItemEqualityComparer<Value>,\n): boolean {\n // Handle null/undefined with Object.is for consistent behavior\n if (item == null || value == null) {\n return Object.is(item, value)\n }\n return comparer(item, value)\n}\n\n/**\n * Check if a collection includes a specific value using custom equality.\n */\nexport function itemIncludes<Value>(\n collection: readonly Value[] | undefined | null,\n value: Value | null | undefined,\n comparer: ItemEqualityComparer<Value>,\n): boolean {\n if (!collection || collection.length === 0) {\n return false\n }\n return collection.some((item) => {\n if (item === undefined) {\n return false\n }\n return compareItemEquality(item, value, comparer)\n })\n}\n\n/**\n * Find the index of a value in a collection using custom equality.\n * Returns -1 if not found.\n */\nexport function findItemIndex<Value>(\n collection: readonly Value[] | undefined | null,\n value: Value,\n comparer: ItemEqualityComparer<Value>,\n): number {\n if (!collection || collection.length === 0) {\n return -1\n }\n return collection.findIndex((item) => {\n if (item === undefined) {\n return false\n }\n return compareItemEquality(item, value, comparer)\n })\n}\n\n/**\n * Remove a value from a collection using custom equality.\n * Returns a new array without the matching item.\n */\nexport function removeItem<Value>(\n collection: readonly Value[],\n value: Value,\n comparer: ItemEqualityComparer<Value>,\n): Value[] {\n return collection.filter(\n (item) => !compareItemEquality(item, value, comparer),\n )\n}\n","import type * as React from 'react'\n\n/**\n * A single entry in the array form of the `items` prop passed to\n * `Select.Root` / `Combobox.Root`.\n */\nexport interface ItemsEntry {\n /**\n * The item's value.\n *\n * Use `null` to describe a clearable/placeholder item (its label is used as\n * the trigger placeholder and selecting it clears the value).\n */\n value: string | null\n /** The label to display for this item. */\n label: React.ReactNode\n /**\n * Additional keywords to match against when filtering, on top of the label.\n * Useful for aliases or synonyms.\n */\n keywords?: string[]\n}\n\n/**\n * Data structure describing the items rendered in a Select/Combobox popup.\n *\n * Either a record mapping a value to its label, or an array of entries. Only\n * the array form can express `keywords` or a `null` (clearable) value.\n */\nexport type Items = Record<string, React.ReactNode> | Array<ItemsEntry>\n\n/**\n * The resolved metadata for a single item looked up from the `items` prop.\n */\nexport interface ResolvedItem {\n label: React.ReactNode\n keywords?: string[]\n}\n\n/** Serialize an entry value to the string key used for registry lookups. */\nfunction entryKey(value: string | null): string {\n return value == null ? '' : value\n}\n\n/**\n * Resolve the full entry (label + keywords) from the `items` prop for a given\n * serialized value key. Returns `undefined` when there is no match.\n */\nexport function resolveItemFromItems(\n items: Items | undefined,\n valueKey: string,\n): ResolvedItem | undefined {\n if (!items) return undefined\n\n if (Array.isArray(items)) {\n const entry = items.find((i) => entryKey(i.value) === valueKey)\n if (!entry) return undefined\n return { label: entry.label, keywords: entry.keywords }\n }\n\n const label = items[valueKey]\n if (label === undefined) return undefined\n return { label }\n}\n\n/**\n * Resolve just the label from the `items` prop for a given serialized value\n * key. Returns `undefined` when there is no match.\n */\nexport function resolveLabelFromItems(\n items: Items | undefined,\n valueKey: string,\n): React.ReactNode | undefined {\n return resolveItemFromItems(items, valueKey)?.label\n}\n\n/**\n * Merge a set of extra keyword strings into an existing keywords array,\n * preserving order and removing duplicates. Returns the original `keywords`\n * reference untouched when there is nothing to add.\n */\nexport function mergeKeywords(\n keywords: string[] | undefined,\n extra: Array<string | undefined>,\n): string[] | undefined {\n const additions = extra.filter((k): k is string => Boolean(k))\n if (additions.length === 0) return keywords\n\n const merged = keywords ? [...keywords] : []\n for (const keyword of additions) {\n if (!merged.includes(keyword)) merged.push(keyword)\n }\n return merged\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/item-equality.ts","../src/utils/items.ts"],"names":["defaultItemEquality","item","value","compareItemEquality","comparer","itemIncludes","collection","removeItem","entryKey","resolveItemFromItems","items","valueKey","entry","i","label","resolveLabelFromItems","mergeKeywords","keywords","extra","additions","k","merged","keyword"],"mappings":"AAaO,qrBAAMA,CAAAA,CAA4C,CAACC,CAAAA,CAAMC,CAAAA,CAAAA,EAC9D,MAAA,CAAO,EAAA,CAAGD,CAAAA,CAAMC,CAAK,CAAA,CAMhB,SAASC,CAAAA,CACdF,CAAAA,CACAC,CAAAA,CACAE,CAAAA,CACS,CAET,OAAIH,CAAAA,EAAQ,IAAA,EAAQC,CAAAA,EAAS,IAAA,CACpB,MAAA,CAAO,EAAA,CAAGD,CAAAA,CAAMC,CAAK,CAAA,CAEvBE,CAAAA,CAASH,CAAAA,CAAMC,CAAK,CAC7B,CAKO,SAASG,CAAAA,CACdC,CAAAA,CACAJ,CAAAA,CACAE,CAAAA,CACS,CACT,MAAI,CAACE,CAAAA,EAAcA,CAAAA,CAAW,MAAA,GAAW,CAAA,CAChC,CAAA,CAAA,CAEFA,CAAAA,CAAW,IAAA,CAAML,CAAAA,EAClBA,CAAAA,GAAS,KAAA,CAAA,CACJ,CAAA,CAAA,CAEFE,CAAAA,CAAoBF,CAAAA,CAAMC,CAAAA,CAAOE,CAAQ,CACjD,CACH,CA0BO,SAASG,CAAAA,CACdD,CAAAA,CACAJ,CAAAA,CACAE,CAAAA,CACS,CACT,OAAOE,CAAAA,CAAW,MAAA,CACfL,CAAAA,EAAS,CAACE,CAAAA,CAAoBF,CAAAA,CAAMC,CAAAA,CAAOE,CAAQ,CACtD,CACF,CC3CA,SAASI,CAAAA,CAASN,CAAAA,CAA8B,CAC9C,wBAAOA,CAAAA,SAAgB,IACzB,CAMO,SAASO,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAC0B,CAC1B,EAAA,CAAI,CAACD,CAAAA,CAAO,MAAA,CAEZ,EAAA,CAAI,KAAA,CAAM,OAAA,CAAQA,CAAK,CAAA,CAAG,CACxB,IAAME,CAAAA,CAAQF,CAAAA,CAAM,IAAA,CAAMG,CAAAA,EAAML,CAAAA,CAASK,CAAAA,CAAE,KAAK,CAAA,GAAMF,CAAQ,CAAA,CAC9D,OAAKC,CAAAA,CACE,CAAE,KAAA,CAAOA,CAAAA,CAAM,KAAA,CAAO,QAAA,CAAUA,CAAAA,CAAM,QAAS,CAAA,CAD1C,KAAA,CAEd,CAEA,IAAME,CAAAA,CAAQJ,CAAAA,CAAMC,CAAQ,CAAA,CAC5B,EAAA,CAAIG,CAAAA,GAAU,KAAA,CAAA,CACd,MAAO,CAAE,KAAA,CAAAA,CAAM,CACjB,CAMO,SAASC,CAAAA,CACdL,CAAAA,CACAC,CAAAA,CAC6B,CAC7B,uBAAOF,CAAAA,iBAAqBC,CAAAA,CAAOC,CAAQ,CAAA,6BAAG,OAChD,CAOO,SAASK,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACsB,CACtB,IAAMC,CAAAA,CAAYD,CAAAA,CAAM,MAAA,CAAQE,CAAAA,EAAmB,CAAA,CAAQA,CAAE,CAAA,CAC7D,EAAA,CAAID,CAAAA,CAAU,MAAA,GAAW,CAAA,CAAG,OAAOF,CAAAA,CAEnC,IAAMI,CAAAA,CAASJ,CAAAA,CAAW,CAAC,GAAGA,CAAQ,CAAA,CAAI,CAAC,CAAA,CAC3C,GAAA,CAAA,IAAWK,EAAAA,GAAWH,CAAAA,CACfE,CAAAA,CAAO,QAAA,CAASC,CAAO,CAAA,EAAGD,CAAAA,CAAO,IAAA,CAAKC,CAAO,CAAA,CAEpD,OAAOD,CACT,CAAA,wGAAA","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-5T5B5SPR.cjs","sourcesContent":["/**\n * Type for custom item equality comparison functions.\n * Used to compare object values in Select and Combobox components.\n */\nexport type ItemEqualityComparer<Value = unknown> = (\n itemValue: Value,\n value: Value,\n) => boolean\n\n/**\n * Default equality comparer using Object.is.\n * Handles primitives and object reference equality.\n */\nexport const defaultItemEquality: ItemEqualityComparer = (item, value) =>\n Object.is(item, value)\n\n/**\n * Compare two items for equality using a custom comparer.\n * Handles null/undefined values separately using Object.is.\n */\nexport function compareItemEquality<Value>(\n item: Value | null | undefined,\n value: Value | null | undefined,\n comparer: ItemEqualityComparer<Value>,\n): boolean {\n // Handle null/undefined with Object.is for consistent behavior\n if (item == null || value == null) {\n return Object.is(item, value)\n }\n return comparer(item, value)\n}\n\n/**\n * Check if a collection includes a specific value using custom equality.\n */\nexport function itemIncludes<Value>(\n collection: readonly Value[] | undefined | null,\n value: Value | null | undefined,\n comparer: ItemEqualityComparer<Value>,\n): boolean {\n if (!collection || collection.length === 0) {\n return false\n }\n return collection.some((item) => {\n if (item === undefined) {\n return false\n }\n return compareItemEquality(item, value, comparer)\n })\n}\n\n/**\n * Find the index of a value in a collection using custom equality.\n * Returns -1 if not found.\n */\nexport function findItemIndex<Value>(\n collection: readonly Value[] | undefined | null,\n value: Value,\n comparer: ItemEqualityComparer<Value>,\n): number {\n if (!collection || collection.length === 0) {\n return -1\n }\n return collection.findIndex((item) => {\n if (item === undefined) {\n return false\n }\n return compareItemEquality(item, value, comparer)\n })\n}\n\n/**\n * Remove a value from a collection using custom equality.\n * Returns a new array without the matching item.\n */\nexport function removeItem<Value>(\n collection: readonly Value[],\n value: Value,\n comparer: ItemEqualityComparer<Value>,\n): Value[] {\n return collection.filter(\n (item) => !compareItemEquality(item, value, comparer),\n )\n}\n","import type * as React from 'react'\n\n/**\n * A single entry in the array form of the `items` prop passed to\n * `Select.Root` / `Combobox.Root`.\n */\nexport interface ItemsEntry {\n /**\n * The item's value.\n *\n * Use `null` to describe a clearable/placeholder item (its label is used as\n * the trigger placeholder and selecting it clears the value).\n */\n value: string | null\n /** The label to display for this item. */\n label: React.ReactNode\n /**\n * Additional keywords to match against when filtering, on top of the label.\n * Useful for aliases or synonyms.\n */\n keywords?: string[]\n}\n\n/**\n * Data structure describing the items rendered in a Select/Combobox popup.\n *\n * Either a record mapping a value to its label, or an array of entries. Only\n * the array form can express `keywords` or a `null` (clearable) value.\n */\nexport type Items = Record<string, React.ReactNode> | Array<ItemsEntry>\n\n/**\n * The resolved metadata for a single item looked up from the `items` prop.\n */\nexport interface ResolvedItem {\n label: React.ReactNode\n keywords?: string[]\n}\n\n/** Serialize an entry value to the string key used for registry lookups. */\nfunction entryKey(value: string | null): string {\n return value == null ? '' : value\n}\n\n/**\n * Resolve the full entry (label + keywords) from the `items` prop for a given\n * serialized value key. Returns `undefined` when there is no match.\n */\nexport function resolveItemFromItems(\n items: Items | undefined,\n valueKey: string,\n): ResolvedItem | undefined {\n if (!items) return undefined\n\n if (Array.isArray(items)) {\n const entry = items.find((i) => entryKey(i.value) === valueKey)\n if (!entry) return undefined\n return { label: entry.label, keywords: entry.keywords }\n }\n\n const label = items[valueKey]\n if (label === undefined) return undefined\n return { label }\n}\n\n/**\n * Resolve just the label from the `items` prop for a given serialized value\n * key. Returns `undefined` when there is no match.\n */\nexport function resolveLabelFromItems(\n items: Items | undefined,\n valueKey: string,\n): React.ReactNode | undefined {\n return resolveItemFromItems(items, valueKey)?.label\n}\n\n/**\n * Merge a set of extra keyword strings into an existing keywords array,\n * preserving order and removing duplicates. Returns the original `keywords`\n * reference untouched when there is nothing to add.\n */\nexport function mergeKeywords(\n keywords: string[] | undefined,\n extra: Array<string | undefined>,\n): string[] | undefined {\n const additions = extra.filter((k): k is string => Boolean(k))\n if (additions.length === 0) return keywords\n\n const merged = keywords ? [...keywords] : []\n for (const keyword of additions) {\n if (!merged.includes(keyword)) merged.push(keyword)\n }\n return merged\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/kbd/utils/parse-keybinding.ts","../src/kbd/utils/platform.ts"],"names":["keyAliases","normalizeKey","key","createChord","parseKeybinding","keys","trimmed","chordValue","chord","tokenValue","token","getKeyLabel","platform","normalizedKey","getChordLabels","isCtrl","isMeta","labels","isApplePlatform","nav","usePlatform","override","setPlatform"],"mappings":"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","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-JFEVUUPC.cjs","sourcesContent":["export interface KeyChord {\n meta: boolean\n ctrl: boolean\n alt: boolean\n shift: boolean\n mod: boolean\n key: string | null\n}\n\nexport interface Keybinding {\n chords: KeyChord[]\n}\n\ntype Platform = 'apple' | 'other'\n\nconst keyAliases: Record<string, string> = {\n esc: 'escape',\n return: 'enter',\n del: 'delete',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n space: 'space',\n spacebar: 'space',\n plus: '+',\n}\n\nfunction normalizeKey(key: string): string {\n return keyAliases[key] ?? key\n}\n\nfunction createChord(): KeyChord {\n return {\n meta: false,\n ctrl: false,\n alt: false,\n shift: false,\n mod: false,\n key: null,\n }\n}\n\nexport function parseKeybinding(keys: string): Keybinding {\n const trimmed = keys.trim()\n\n if (trimmed.length === 0) {\n return { chords: [] }\n }\n\n return {\n chords: trimmed.split(/\\s+/).map((chordValue) => {\n const chord = createChord()\n\n for (const tokenValue of chordValue.split('+')) {\n const token = tokenValue.trim().toLowerCase()\n\n if (token === '') {\n // Skip empty tokens from trailing/leading/double \"+\" (e.g. \"mod+\").\n // A literal \"+\" key is expressed with the \"plus\" alias.\n continue\n }\n\n if (token === 'mod') {\n chord.mod = true\n } else if (\n token === 'meta' ||\n token === 'cmd' ||\n token === 'command' ||\n token === 'win' ||\n token === 'super'\n ) {\n chord.meta = true\n } else if (token === 'ctrl' || token === 'control') {\n chord.ctrl = true\n } else if (token === 'alt' || token === 'option' || token === 'opt') {\n chord.alt = true\n } else if (token === 'shift') {\n chord.shift = true\n } else {\n if (chord.key !== null) {\n throw new Error(\n `Keybinding chord \"${chordValue}\" contains multiple keys: \"${chord.key}\" and \"${token}\"`,\n )\n }\n\n chord.key = normalizeKey(token)\n }\n }\n\n return chord\n }),\n }\n}\n\nexport function getKeyLabel(key: string, platform: Platform): string {\n const normalizedKey = key.toLowerCase()\n\n switch (normalizedKey) {\n case 'enter':\n return platform === 'apple' ? '↵' : 'Enter'\n case 'escape':\n return 'Esc'\n case 'backspace':\n return platform === 'apple' ? '⌫' : 'Backspace'\n case 'delete':\n return platform === 'apple' ? '⌦' : 'Del'\n case 'tab':\n return platform === 'apple' ? '⇥' : 'Tab'\n case 'space':\n return 'Space'\n case 'arrowup':\n return '↑'\n case 'arrowdown':\n return '↓'\n case 'arrowleft':\n return '←'\n case 'arrowright':\n return '→'\n default:\n if (normalizedKey.length === 1) {\n return normalizedKey.toUpperCase()\n }\n\n return normalizedKey.charAt(0).toUpperCase() + normalizedKey.slice(1)\n }\n}\n\nexport function getChordLabels(chord: KeyChord, platform: Platform): string[] {\n const isCtrl = chord.ctrl || (platform === 'other' && chord.mod)\n const isMeta = chord.meta || (platform === 'apple' && chord.mod)\n const labels: string[] = []\n\n if (isCtrl) {\n labels.push(platform === 'apple' ? '⌃' : 'Ctrl')\n }\n\n if (chord.alt) {\n labels.push(platform === 'apple' ? '⌥' : 'Alt')\n }\n\n if (chord.shift) {\n labels.push(platform === 'apple' ? '⇧' : 'Shift')\n }\n\n if (isMeta) {\n labels.push(platform === 'apple' ? '⌘' : 'Win')\n }\n\n if (chord.key !== null) {\n labels.push(getKeyLabel(chord.key, platform))\n }\n\n return labels\n}\n","'use client'\n\nimport * as React from 'react'\n\ntype Platform = 'apple' | 'other'\n\ninterface NavigatorWithUserAgentData extends Navigator {\n userAgentData?: {\n platform?: string\n }\n}\n\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined') {\n return false\n }\n\n const nav = navigator as NavigatorWithUserAgentData\n const platform = nav.userAgentData?.platform || nav.platform || nav.userAgent\n\n return /mac|iphone|ipad|ipod/i.test(platform)\n}\n\n/**\n * Returns the current platform while keeping the first client render aligned with\n * SSR. Without an override, this starts as \"other\" and corrects to \"apple\" after\n * mount when appropriate, avoiding hydration mismatches.\n */\nexport function usePlatform(override?: Platform): Platform {\n const [platform, setPlatform] = React.useState<Platform>('other')\n\n React.useEffect(() => {\n if (override === undefined && isApplePlatform()) {\n setPlatform('apple')\n }\n }, [override])\n\n return override ?? platform\n}\n"]}
1
+ {"version":3,"sources":["../src/kbd/utils/parse-keybinding.ts","../src/kbd/utils/platform.ts"],"names":["keyAliases","normalizeKey","key","createChord","parseKeybinding","keys","trimmed","chordValue","chord","tokenValue","token","getKeyLabel","platform","normalizedKey","getChordLabels","isCtrl","isMeta","labels","isApplePlatform","nav","usePlatform","override","setPlatform"],"mappings":"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","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-JFEVUUPC.cjs","sourcesContent":["export interface KeyChord {\n meta: boolean\n ctrl: boolean\n alt: boolean\n shift: boolean\n mod: boolean\n key: string | null\n}\n\nexport interface Keybinding {\n chords: KeyChord[]\n}\n\ntype Platform = 'apple' | 'other'\n\nconst keyAliases: Record<string, string> = {\n esc: 'escape',\n return: 'enter',\n del: 'delete',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n space: 'space',\n spacebar: 'space',\n plus: '+',\n}\n\nfunction normalizeKey(key: string): string {\n return keyAliases[key] ?? key\n}\n\nfunction createChord(): KeyChord {\n return {\n meta: false,\n ctrl: false,\n alt: false,\n shift: false,\n mod: false,\n key: null,\n }\n}\n\nexport function parseKeybinding(keys: string): Keybinding {\n const trimmed = keys.trim()\n\n if (trimmed.length === 0) {\n return { chords: [] }\n }\n\n return {\n chords: trimmed.split(/\\s+/).map((chordValue) => {\n const chord = createChord()\n\n for (const tokenValue of chordValue.split('+')) {\n const token = tokenValue.trim().toLowerCase()\n\n if (token === '') {\n // Skip empty tokens from trailing/leading/double \"+\" (e.g. \"mod+\").\n // A literal \"+\" key is expressed with the \"plus\" alias.\n continue\n }\n\n if (token === 'mod') {\n chord.mod = true\n } else if (\n token === 'meta' ||\n token === 'cmd' ||\n token === 'command' ||\n token === 'win' ||\n token === 'super'\n ) {\n chord.meta = true\n } else if (token === 'ctrl' || token === 'control') {\n chord.ctrl = true\n } else if (token === 'alt' || token === 'option' || token === 'opt') {\n chord.alt = true\n } else if (token === 'shift') {\n chord.shift = true\n } else {\n if (chord.key !== null) {\n throw new Error(\n `Keybinding chord \"${chordValue}\" contains multiple keys: \"${chord.key}\" and \"${token}\"`,\n )\n }\n\n chord.key = normalizeKey(token)\n }\n }\n\n return chord\n }),\n }\n}\n\nexport function getKeyLabel(key: string, platform: Platform): string {\n const normalizedKey = key.toLowerCase()\n\n switch (normalizedKey) {\n case 'enter':\n return platform === 'apple' ? '↵' : 'Enter'\n case 'escape':\n return 'Esc'\n case 'backspace':\n return platform === 'apple' ? '⌫' : 'Backspace'\n case 'delete':\n return platform === 'apple' ? '⌦' : 'Del'\n case 'tab':\n return platform === 'apple' ? '⇥' : 'Tab'\n case 'space':\n return 'Space'\n case 'arrowup':\n return '↑'\n case 'arrowdown':\n return '↓'\n case 'arrowleft':\n return '←'\n case 'arrowright':\n return '→'\n default:\n if (normalizedKey.length === 1) {\n return normalizedKey.toUpperCase()\n }\n\n return normalizedKey.charAt(0).toUpperCase() + normalizedKey.slice(1)\n }\n}\n\nexport function getChordLabels(chord: KeyChord, platform: Platform): string[] {\n const isCtrl = chord.ctrl || (platform === 'other' && chord.mod)\n const isMeta = chord.meta || (platform === 'apple' && chord.mod)\n const labels: string[] = []\n\n if (isCtrl) {\n labels.push(platform === 'apple' ? '⌃' : 'Ctrl')\n }\n\n if (chord.alt) {\n labels.push(platform === 'apple' ? '⌥' : 'Alt')\n }\n\n if (chord.shift) {\n labels.push(platform === 'apple' ? '⇧' : 'Shift')\n }\n\n if (isMeta) {\n labels.push(platform === 'apple' ? '⌘' : 'Win')\n }\n\n if (chord.key !== null) {\n labels.push(getKeyLabel(chord.key, platform))\n }\n\n return labels\n}\n","'use client'\n\nimport * as React from 'react'\n\ntype Platform = 'apple' | 'other'\n\ninterface NavigatorWithUserAgentData extends Navigator {\n userAgentData?: {\n platform?: string\n }\n}\n\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined') {\n return false\n }\n\n const nav = navigator as NavigatorWithUserAgentData\n const platform = nav.userAgentData?.platform || nav.platform || nav.userAgent\n\n return /mac|iphone|ipad|ipod/i.test(platform)\n}\n\n/**\n * Returns the current platform while keeping the first client render aligned with\n * SSR. Without an override, this starts as \"other\" and corrects to \"apple\" after\n * mount when appropriate, avoiding hydration mismatches.\n */\nexport function usePlatform(override?: Platform): Platform {\n const [platform, setPlatform] = React.useState<Platform>('other')\n\n React.useEffect(() => {\n if (override === undefined && isApplePlatform()) {\n setPlatform('apple')\n }\n }, [override])\n\n return override ?? platform\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-M4G6J7DP.cjs"],"names":[],"mappings":"AAAA,6EAAI,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-M4G6J7DP.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/ui/ui/packages/react/dist/chunk-M4G6J7DP.cjs"],"names":[],"mappings":"AAAA,6EAAI,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-M4G6J7DP.cjs"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/merge-element-props.ts"],"names":["mergeElementProps","internalProps","externalProps","mergeProps","wrapEventHandlers","props","wrappedProps","propName","propValue","isEventHandler","event","args","makeEventPreventable","key","value"],"mappings":"AAAA,iIAAiD,SAMjCA,CAAAA,CAIdC,CAAAA,CAA8BC,CAAAA,CAA8B,CAC5D,OAAOC,oCAAAA,CACLF,CACAG,CAAAA,CAAqBF,CAAa,CACpC,CACF,CAEA,SAASE,CAAAA,CACPC,CAAAA,CACA,CACA,IAAMC,CAAAA,CAAe,CAAE,GAAGD,CAAM,CAAA,CAEhC,GAAA,CAAA,IAAWE,EAAAA,GAAYD,CAAAA,CAAc,CACnC,IAAME,CAAAA,CAAYF,CAAAA,CAAaC,CAAQ,CAAA,CACnCE,CAAAA,CAAeF,CAAAA,CAAUC,CAAS,CAAA,EAAA,CACpCF,CAAAA,CAAaC,CAAQ,CAAA,CAAI,CACvBG,CAAAA,CAAAA,GACGC,CAAAA,CAAAA,EAAAA,CAEHC,8CAAAA,CAEA,CAAA,CACOJ,CAAAA,CAAUE,CAAAA,CAAO,GAAGC,CAAI,CAAA,CAAA,CAGrC,CAEA,OAAOL,CACT,CAEA,SAASG,CAAAA,CACPI,CAAAA,CACAC,CAAAA,CACuE,CACvE,OACED,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,GAAM,GAAA,EACtBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,GAAM,GAAA,EACtBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,EAAK,EAAA,EACrBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,EAAK,EAAA,EACrB,OAAOC,CAAAA,EAAU,UAErB,CAAA,cAAA","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-SCDHQZFI.cjs","sourcesContent":["import { makeEventPreventable, mergeProps } from '@base-ui/react/merge-props'\nimport type * as React from 'react'\n\ntype ElementType = React.ElementType\ntype ElementProps<T extends ElementType> = React.ComponentPropsWithRef<T>\n\nexport function mergeElementProps<\n T extends ElementType,\n InternalProps extends Record<string, unknown> = ElementProps<T>,\n ExternalProps extends Partial<ElementProps<T>> = Partial<ElementProps<T>>,\n>(internalProps: InternalProps, externalProps: ExternalProps) {\n return mergeProps<T>(\n internalProps as ElementProps<T>,\n wrapEventHandlers<T>(externalProps) as ElementProps<T>,\n ) as InternalProps & ExternalProps\n}\n\nfunction wrapEventHandlers<T extends ElementType>(\n props: Partial<ElementProps<T>>,\n) {\n const wrappedProps = { ...props } as Record<string, unknown>\n\n for (const propName in wrappedProps) {\n const propValue = wrappedProps[propName]\n if (isEventHandler(propName, propValue)) {\n wrappedProps[propName] = (\n event: React.SyntheticEvent,\n ...args: unknown[]\n ) => {\n makeEventPreventable(\n event as Parameters<typeof makeEventPreventable>[0],\n )\n return propValue(event, ...args)\n }\n }\n }\n\n return wrappedProps as Partial<ElementProps<T>>\n}\n\nfunction isEventHandler(\n key: string,\n value: unknown,\n): value is (event: React.SyntheticEvent, ...args: unknown[]) => unknown {\n return (\n key.charCodeAt(0) === 111 &&\n key.charCodeAt(1) === 110 &&\n key.charCodeAt(2) >= 65 &&\n key.charCodeAt(2) <= 90 &&\n typeof value === 'function'\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/merge-element-props.ts"],"names":["mergeElementProps","internalProps","externalProps","mergeProps","wrapEventHandlers","props","wrappedProps","propName","propValue","isEventHandler","event","args","makeEventPreventable","key","value"],"mappings":"AAAA,iIAAiD,SAMjCA,CAAAA,CAIdC,CAAAA,CAA8BC,CAAAA,CAA8B,CAC5D,OAAOC,oCAAAA,CACLF,CACAG,CAAAA,CAAqBF,CAAa,CACpC,CACF,CAEA,SAASE,CAAAA,CACPC,CAAAA,CACA,CACA,IAAMC,CAAAA,CAAe,CAAE,GAAGD,CAAM,CAAA,CAEhC,GAAA,CAAA,IAAWE,EAAAA,GAAYD,CAAAA,CAAc,CACnC,IAAME,CAAAA,CAAYF,CAAAA,CAAaC,CAAQ,CAAA,CACnCE,CAAAA,CAAeF,CAAAA,CAAUC,CAAS,CAAA,EAAA,CACpCF,CAAAA,CAAaC,CAAQ,CAAA,CAAI,CACvBG,CAAAA,CAAAA,GACGC,CAAAA,CAAAA,EAAAA,CAEHC,8CAAAA,CAEA,CAAA,CACOJ,CAAAA,CAAUE,CAAAA,CAAO,GAAGC,CAAI,CAAA,CAAA,CAGrC,CAEA,OAAOL,CACT,CAEA,SAASG,CAAAA,CACPI,CAAAA,CACAC,CAAAA,CACuE,CACvE,OACED,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,GAAM,GAAA,EACtBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,GAAM,GAAA,EACtBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,EAAK,EAAA,EACrBA,CAAAA,CAAI,UAAA,CAAW,CAAC,CAAA,EAAK,EAAA,EACrB,OAAOC,CAAAA,EAAU,UAErB,CAAA,cAAA","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-SCDHQZFI.cjs","sourcesContent":["import { makeEventPreventable, mergeProps } from '@base-ui/react/merge-props'\nimport type * as React from 'react'\n\ntype ElementType = React.ElementType\ntype ElementProps<T extends ElementType> = React.ComponentPropsWithRef<T>\n\nexport function mergeElementProps<\n T extends ElementType,\n InternalProps extends Record<string, unknown> = ElementProps<T>,\n ExternalProps extends Partial<ElementProps<T>> = Partial<ElementProps<T>>,\n>(internalProps: InternalProps, externalProps: ExternalProps) {\n return mergeProps<T>(\n internalProps as ElementProps<T>,\n wrapEventHandlers<T>(externalProps) as ElementProps<T>,\n ) as InternalProps & ExternalProps\n}\n\nfunction wrapEventHandlers<T extends ElementType>(\n props: Partial<ElementProps<T>>,\n) {\n const wrappedProps = { ...props } as Record<string, unknown>\n\n for (const propName in wrappedProps) {\n const propValue = wrappedProps[propName]\n if (isEventHandler(propName, propValue)) {\n wrappedProps[propName] = (\n event: React.SyntheticEvent,\n ...args: unknown[]\n ) => {\n makeEventPreventable(\n event as Parameters<typeof makeEventPreventable>[0],\n )\n return propValue(event, ...args)\n }\n }\n }\n\n return wrappedProps as Partial<ElementProps<T>>\n}\n\nfunction isEventHandler(\n key: string,\n value: unknown,\n): value is (event: React.SyntheticEvent, ...args: unknown[]) => unknown {\n return (\n key.charCodeAt(0) === 111 &&\n key.charCodeAt(1) === 110 &&\n key.charCodeAt(2) >= 65 &&\n key.charCodeAt(2) <= 90 &&\n typeof value === 'function'\n )\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-W4ACKMIZ.cjs","../src/internal/popup-menu/contexts/focus-owner-context.ts","../src/internal/popup-menu/contexts/open-chain-context.ts","../src/internal/popup-menu/contexts/popup-menu-context.ts","../src/internal/popup-menu/contexts/popup-surface-id-context.ts","../src/internal/popup-menu/contexts/submenu-context.ts","../src/internal/popup-menu/contexts/subpage-context.ts","../src/internal/popup-menu/contexts/subpage-stack-context.ts","../src/internal/popup-menu/store/FocusOwnerStore.ts","../src/internal/popup-menu/hooks/use-popup-menu-root.ts","../src/internal/popup-menu/menu-tree/resolve.ts"],"names":["FocusOwnerContext","useFocusOwner","context","OpenChainContext","useOpenChain","PopupMenuContext","usePopupMenuContext","useMaybePopupMenuContext","PopupSurfaceIdContext","usePopupSurfaceId","SubmenuContext","useSubmenuContext","useMaybeSubmenuContext","SubpageContext","useSubpageContext","useMaybeSubpageContext","SubpageStackContext","useSubpageStack","useMaybeSubpageStack","selectors","createSelector","state","surfaceId","FocusOwnerStore","ReactStore","id","isPopupMenuNode","value","encodeDefinitionPathEntry","entry","encoded","index","codeUnit","isSafe"],"mappings":"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","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-W4ACKMIZ.cjs","sourcesContent":[null,"'use client'\n\nimport * as React from 'react'\nimport type { FocusOwnerStore } from '../store/FocusOwnerStore.js'\n\n// ============================================================================\n// Focus Owner Context\n// ============================================================================\n\nconst FocusOwnerContext = React.createContext<FocusOwnerStore | null>(null)\n\nexport function useFocusOwner(): FocusOwnerStore {\n const context = React.useContext(FocusOwnerContext)\n if (!context) {\n throw new Error(\n 'FocusOwner components must be used within a FocusOwnerProvider',\n )\n }\n return context\n}\n\nexport function useMaybeFocusOwner(): FocusOwnerStore | null {\n return React.useContext(FocusOwnerContext)\n}\n\nexport { FocusOwnerContext }\n","'use client'\n\nimport * as React from 'react'\nimport type { OpenChainStore } from '../store/OpenChainStore.js'\n\n// ============================================================================\n// Open Chain Context\n// ============================================================================\n\nconst OpenChainContext = React.createContext<OpenChainStore | null>(null)\n\nexport function useOpenChain(): OpenChainStore {\n const context = React.useContext(OpenChainContext)\n if (!context) {\n throw new Error(\n 'OpenChain components must be used within an OpenChainProvider',\n )\n }\n return context\n}\n\nexport function useMaybeOpenChain(): OpenChainStore | null {\n return React.useContext(OpenChainContext)\n}\n\nexport { OpenChainContext }\n","'use client'\n\nimport * as React from 'react'\nimport type {\n ListboxStore,\n VirtualItem,\n} from '../../listbox/store/ListboxStore.js'\nimport type {\n HighlightChangeEventDetails,\n PopupMenuOpenChangeReason,\n} from '../events.js'\n\n// ============================================================================\n// Popup Menu Context\n// ============================================================================\n// Shared root-level context for popup menus (DropdownMenu, ContextMenu).\n// Provides core menu functionality to all child components.\n\n/**\n * Virtual anchor for positioning the menu at a specific point.\n * Used by ContextMenu to position at cursor location.\n */\nexport interface VirtualAnchor {\n getBoundingClientRect(): DOMRect\n}\n\n/**\n * Virtualization configuration passed from Root/Submenu to Surface.\n */\nexport interface VirtualizationConfig {\n /** Whether virtualization mode is enabled */\n virtualized: boolean\n /** Pre-registered items for virtualization */\n items: VirtualItem[]\n /**\n * Callback when highlighted item changes (for scroll sync).\n * The third parameter contains event details including the reason for the change.\n */\n onHighlightChange?: (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => void\n}\n\n/**\n * Shared context value for popup menus.\n * Both DropdownMenu.Root and ContextMenu.Root provide this context.\n */\nexport interface PopupMenuContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Whether this menu tree currently ignores user interaction. */\n disabled: boolean\n /** Nesting depth: 0 = root menu, 1+ = submenu */\n depth: number\n /** Close the entire menu tree (deepest submenu to root, sequentially) */\n closeAll: (reason?: PopupMenuOpenChangeReason, event?: Event) => void\n /**\n * Internal: when true, Surface handles Tab explicitly (close the tree, or\n * cycle through focus zones). Enabled only by DropdownMenu.Root and\n * ContextMenu.Root — never Select or Combobox.\n */\n explicitTabBehavior: boolean\n /**\n * Internal: what Tab does under `explicitTabBehavior` when the surface (and\n * its ancestors) have no focus-zone tabbables. `'close'` closes the whole\n * tree (dropdown/context-menu). `'inert'` swallows the event, keeping focus\n * where it is (command palette).\n */\n tabWithoutZones: 'close' | 'inert'\n /** Register a surface (submenu) for closeAll tracking. Returns unregister function. */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Virtualization configuration (if enabled) */\n virtualization?: VirtualizationConfig\n /**\n * Virtual anchor for positioning.\n * Used by ContextMenu to position at cursor location.\n * DropdownMenu uses the Popover's anchor (trigger button) instead.\n */\n virtualAnchor?: VirtualAnchor\n /**\n * Type of menu for positioning logic.\n * - 'dropdown': positions relative to trigger button\n * - 'context': positions at cursor with fixed positioning\n */\n menuType: 'dropdown' | 'context'\n /**\n * When to close the menu on outside interactions.\n * - 'pointerdown': Close immediately when pointer is pressed outside (default)\n * - 'click': Close when a full click (pointerdown + pointerup) occurs outside\n * @default 'pointerdown'\n */\n closeOnOutsidePress: 'click' | 'pointerdown'\n}\n\nconst PopupMenuContext = React.createContext<PopupMenuContextValue | null>(null)\n\n/**\n * Hook to access the popup menu context.\n * Throws if used outside a popup menu.\n */\nexport function usePopupMenuContext(): PopupMenuContextValue {\n const context = React.useContext(PopupMenuContext)\n if (!context) {\n throw new Error(\n 'PopupMenu components must be used within a PopupMenu.Root or ContextMenu.Root',\n )\n }\n return context\n}\n\n/**\n * Hook to optionally access the popup menu context.\n * Returns null if used outside a popup menu.\n */\nexport function useMaybePopupMenuContext(): PopupMenuContextValue | null {\n return React.useContext(PopupMenuContext)\n}\n\n// Re-export for convenience\nexport type { VirtualItem }\nexport { PopupMenuContext }\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Popup Surface ID Context\n// ============================================================================\n\n/**\n * Context for passing surfaceId from Popup to Surface.\n * This ensures Popup and Surface share the same ID for data attribute tracking.\n *\n * For root menus, Popup generates the ID and provides it via this context.\n * For submenus, the ID comes from SubmenuContext.childSurfaceId instead.\n */\nconst PopupSurfaceIdContext = React.createContext<string | null>(null)\n\nexport function usePopupSurfaceId(): string | null {\n return React.useContext(PopupSurfaceIdContext)\n}\n\nexport { PopupSurfaceIdContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubmenuContextValue {\n /** Whether the submenu is open */\n open: boolean\n /** Set the submenu open state */\n setOpen: (open: boolean) => void\n /**\n * Latch set by explicit close actions (keyboard ArrowLeft/Ctrl+H/Escape-in-submenu,\n * or clicking the open trigger). While set and the trigger remains highlighted,\n * pointer/keyboard auto-open is suppressed. Reset when highlight leaves the trigger.\n */\n suppressAutoOpenRef: React.MutableRefObject<boolean>\n /** Reference to the trigger element */\n triggerRef: React.RefObject<HTMLElement | null>\n /** Reference to the submenu content element (for aim guard rect calculations) */\n contentRef: React.RefObject<HTMLElement | null>\n /** Surface ID of the parent menu (for keyboard navigation back) */\n parentSurfaceId: string\n /** Surface ID of this submenu (for keyboard navigation into) */\n childSurfaceId: string\n /**\n * Whether pressing Escape in this submenu closes the entire menu from the root.\n * When true, Escape closes the entire menu tree.\n * When false, Escape only closes this submenu and moves focus to the parent.\n * @default true\n */\n closeRootOnEsc: boolean\n}\n\nconst SubmenuContext = React.createContext<SubmenuContextValue | null>(null)\n\nexport function useSubmenuContext(): SubmenuContextValue {\n const context = React.useContext(SubmenuContext)\n if (!context) {\n throw new Error('SubmenuTrigger must be used within a Submenu')\n }\n return context\n}\n\nexport function useMaybeSubmenuContext(): SubmenuContextValue | null {\n return React.useContext(SubmenuContext)\n}\n\nexport { SubmenuContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubpageContextValue {\n /** Current page ID. */\n pageId: string\n /** Surface ID for this page. */\n surfaceId: string\n /** Surface ID for the previous page, if available. */\n parentSurfaceId: string | null\n /** Whether this page is currently active. */\n isActive: boolean\n /** Whether Escape should close the entire menu tree from this page. */\n closeRootOnEsc: boolean\n /** Navigate back one page. Returns true when navigation happened. */\n goBack: () => boolean\n}\n\nconst SubpageContext = React.createContext<SubpageContextValue | null>(null)\n\nexport function useSubpageContext(): SubpageContextValue {\n const context = React.useContext(SubpageContext)\n if (!context) {\n throw new Error(\n 'Subpage components must be used within a PopupMenu.Subpage',\n )\n }\n return context\n}\n\nexport function useMaybeSubpageContext(): SubpageContextValue | null {\n return React.useContext(SubpageContext)\n}\n\nexport { SubpageContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubpageRegistration {\n pageId: string\n surfaceId: string\n closeRootOnEsc: boolean\n}\n\nexport interface SubpageStackContextValue {\n /** Active page ID; `null` when the root surface is active. */\n activePageId: string | null\n /** Surface ID of the root surface. */\n rootSurfaceId: string\n /** Surface ID for the currently active page. */\n activeSurfaceId: string\n /** Whether there is a previous page to navigate back to. */\n canGoBack: boolean\n /** Whether Escape in the active page should close the entire menu tree. */\n shouldCloseRootOnEsc: boolean\n /** Open page IDs, bottom to top; empty at root. */\n stack: readonly string[]\n /** Register a page and return an unregister cleanup. */\n registerPage: (registration: SubpageRegistration) => () => void\n /** Push a page onto the stack. Returns true when navigation happened. */\n openPage: (pageId: string) => boolean\n /** Pop one page from the stack. Returns true when navigation happened. */\n goBack: () => boolean\n /** Resolve a surface ID for a page ID. */\n getSurfaceId: (pageId: string) => string | null\n}\n\nconst SubpageStackContext =\n React.createContext<SubpageStackContextValue | null>(null)\n\nexport function useSubpageStack(): SubpageStackContextValue {\n const context = React.useContext(SubpageStackContext)\n if (!context) {\n throw new Error('Subpage components must be used within a PopupMenu.Popup')\n }\n return context\n}\n\nexport function useMaybeSubpageStack(): SubpageStackContextValue | null {\n return React.useContext(SubpageStackContext)\n}\n\nexport { SubpageStackContext }\n","import { createSelector, ReactStore } from '@base-ui/utils/store'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface FocusOwnerState {\n /** Which surface currently owns focus (surfaceId or null) */\n ownerId: string | null\n}\n\n// ============================================================================\n// Selectors\n// ============================================================================\n\nconst selectors = {\n ownerId: createSelector((state: FocusOwnerState) => state.ownerId),\n isOwner: createSelector(\n (state: FocusOwnerState, surfaceId: string) => state.ownerId === surfaceId,\n ),\n}\n\n// ============================================================================\n// Store\n// ============================================================================\n\n/**\n * Tracks which menu surface owns DOM focus.\n * Single instance per menu tree (created at root, shared via context).\n *\n * Used by: DropdownMenu, ContextMenu\n * Not used by: Select, CommandMenu (single surface)\n */\nexport class FocusOwnerStore extends ReactStore<\n FocusOwnerState,\n Record<string, never>,\n typeof selectors\n> {\n constructor() {\n super({ ownerId: null }, {}, selectors)\n }\n\n /**\n * Set the owner surface ID.\n * Call this when focus should transfer to a new surface.\n */\n setOwnerId(id: string | null) {\n this.set('ownerId', id)\n }\n\n /**\n * Clear the owner (set to null).\n * Call this when the menu tree closes.\n */\n clearOwner() {\n this.set('ownerId', null)\n }\n}\n\nexport type { FocusOwnerState as State }\n","'use client'\n\nimport * as React from 'react'\nimport type { ChangeEventDetails } from '../../../utils/events/index.js'\nimport {\n createChangeEventDetails,\n REASONS,\n} from '../../../utils/events/index.js'\nimport { ensureInputModalityTracking } from '../../../utils/input-modality.js'\nimport { ListboxStore, type VirtualItem } from '../../listbox/index.js'\nimport type { VirtualizationConfig } from '../contexts/popup-menu-context.js'\nimport type {\n HighlightChangeEventDetails,\n PopupMenuHighlightChangeHandler,\n PopupMenuOpenChangeReason,\n} from '../events.js'\nimport type { MenuTreeResolver } from '../menu-tree/resolver.js'\nimport { createMenuTreeResolver } from '../menu-tree/resolver.js'\nimport type { GetResolvedIdFn, PopupMenuIdScope } from '../menu-tree/types.js'\nimport { FocusOwnerStore } from '../store/FocusOwnerStore.js'\nimport { OpenChainStore } from '../store/OpenChainStore.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UsePopupMenuRootParams {\n /**\n * Computes canonical Resolved IDs for data-first content from the Unresolved Menu Node (definitional facts only).\n * @default explicit `def.id` verbatim, else the joined definition path\n * Read once when the menu root mounts — later changes have no effect.\n */\n getResolvedId?: GetResolvedIdFn\n /** Definition Key uniqueness scope. Read once when the menu root mounts. */\n idScope?: PopupMenuIdScope\n /**\n * Callback when the open state changes.\n * The second parameter contains event details including the reason for the change.\n */\n onOpenChange?: (\n open: boolean,\n eventDetails: ChangeEventDetails<string>,\n ) => void\n\n /**\n * Whether the menu is initially open.\n * @default false\n */\n defaultOpen?: boolean\n\n /**\n * Whether virtualization mode is enabled.\n * @default false\n */\n virtualized?: boolean\n\n /**\n * Pre-registered items for virtualization.\n */\n items?: VirtualItem[]\n\n /**\n * Callback when the highlighted item changes. `id` is first; `node` is the\n * resolved menu node enrichment and may be null.\n * The fourth parameter contains event details including the reason for the change.\n */\n onHighlightChange?: PopupMenuHighlightChangeHandler<HighlightChangeEventDetails>\n\n /**\n * When to close the menu on outside interactions.\n * - 'pointerdown': Close immediately when pointer is pressed outside (default)\n * - 'click': Close when a full click (pointerdown + pointerup) occurs outside\n * @default 'pointerdown'\n */\n closeOnOutsidePress?: 'click' | 'pointerdown'\n\n /**\n * Whether the menu should ignore user interaction.\n * Can be controlled declaratively via this prop, or imperatively via actionsRef.setDisabled().\n * @default false\n */\n disabled?: boolean\n\n /**\n * Initial disabled state for imperative usage.\n * Ignored when `disabled` prop is true.\n * @default false\n */\n defaultDisabled?: boolean\n}\n\nexport interface PopupMenuRootActions {\n /** Close the menu tree imperatively. */\n close: () => void\n /** Unmount the popup imperatively (when keep-mounted mode is enabled). */\n unmount: () => void\n /** Enable/disable the menu tree imperatively. */\n setDisabled: (disabled: boolean) => void\n}\n\nexport interface UsePopupMenuRootReturn {\n /** The menu-tree resolver for this menu root. */\n menuTreeResolver: MenuTreeResolver\n /** The Listbox store instance */\n store: ListboxStore\n /** The FocusOwner store instance */\n focusOwnerStore: FocusOwnerStore\n /** The OpenChain store instance */\n openChainStore: OpenChainStore\n /** Register a surface (submenu) for closeAll tracking */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Close the entire menu tree */\n closeAll: (reason?: PopupMenuOpenChangeReason, event?: Event) => void\n /** Virtualization configuration (if enabled) */\n virtualization: VirtualizationConfig | undefined\n /** Handle open state change (updates store and clears stores on close) */\n handleOpenChange: (\n open: boolean,\n reason?: PopupMenuOpenChangeReason,\n event?: Event,\n ) => void\n /** Whether the menu currently ignores user interaction. */\n disabled: boolean\n /** Update imperative disabled state. */\n setDisabled: (disabled: boolean) => void\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook that creates and manages the core stores and utilities for popup menus.\n * Used by both DropdownMenu.Root and ContextMenu.Root.\n *\n * Provides:\n * - ListboxStore for item management\n * - FocusOwnerStore for focus tracking across submenus\n * - OpenChainStore for tracking open submenu chain\n * - Surface registry for closeAll functionality\n */\nexport function usePopupMenuRoot(\n params: UsePopupMenuRootParams = {},\n): UsePopupMenuRootReturn {\n const {\n onOpenChange,\n defaultOpen = false,\n virtualized = false,\n items: itemsProp,\n onHighlightChange,\n closeOnOutsidePress = 'pointerdown',\n disabled: disabledProp = false,\n defaultDisabled = false,\n getResolvedId,\n idScope = 'surface',\n } = params\n\n const menuTreeResolverRef = React.useRef<MenuTreeResolver | null>(null)\n if (menuTreeResolverRef.current === null) {\n menuTreeResolverRef.current = createMenuTreeResolver({\n getResolvedId,\n idScope,\n })\n }\n const menuTreeResolver = menuTreeResolverRef.current\n\n const handleHighlightChange = React.useCallback(\n (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => {\n onHighlightChange?.(\n id,\n id === null ? null : (menuTreeResolver.getNodeById(id) ?? null),\n index,\n eventDetails,\n )\n },\n [menuTreeResolver, onHighlightChange],\n )\n\n const [imperativeDisabled, setImperativeDisabled] =\n React.useState(defaultDisabled)\n const disabled = disabledProp || imperativeDisabled\n\n const setDisabled = React.useCallback((nextDisabled: boolean) => {\n setImperativeDisabled(nextDisabled)\n }, [])\n\n // Begin tracking global input modality so the store can attribute opens to\n // mouse/touch/pen/keyboard. Idempotent; installed once for the whole app.\n React.useEffect(() => {\n ensureInputModalityTracking()\n }, [])\n\n // Track outside pointer events to distinguish outside-press from focus-out\n // When a pointerdown happens outside the menu, we store it so that if a\n // focus-out close happens immediately after, we can treat it as outside-press\n const outsidePointerEventRef = React.useRef<PointerEvent | null>(null)\n\n // Create stable callback wrapper for onOpenChange that converts focus-out to outside-press\n // when the close was triggered by a pointer event outside the menu\n const stableOnOpenChange = React.useCallback(\n (open: boolean, eventDetails: ChangeEventDetails<string>) => {\n // If closing due to focus-out but we have a stored outside pointer event,\n // convert the reason to outside-press for better cancel() support\n if (\n !open &&\n eventDetails.reason === REASONS.focusOut &&\n outsidePointerEventRef.current\n ) {\n const pointerEvent = outsidePointerEventRef.current\n outsidePointerEventRef.current = null\n\n // Create new event details with outside-press reason and the pointer event\n const convertedDetails = createChangeEventDetails(\n REASONS.outsidePress,\n pointerEvent,\n )\n\n onOpenChange?.(open, convertedDetails)\n\n // If the converted callback canceled, also cancel the original\n if (convertedDetails.isCanceled) {\n eventDetails.cancel()\n }\n return\n }\n\n // Clear the pointer event ref if we're not using it\n outsidePointerEventRef.current = null\n\n onOpenChange?.(open, eventDetails)\n },\n [onOpenChange],\n )\n\n // Create the store instance\n const store = ListboxStore.useStore(\n undefined,\n { open: defaultOpen },\n {\n onOpenChange: stableOnOpenChange,\n },\n )\n\n // Get current open state for the pointer event listener\n const isOpen = store.useState('open')\n\n // Create focus owner store (single instance for entire menu tree)\n const focusOwnerStoreRef = React.useRef<FocusOwnerStore | null>(null)\n if (!focusOwnerStoreRef.current) {\n focusOwnerStoreRef.current = new FocusOwnerStore()\n }\n const focusOwnerStore = focusOwnerStoreRef.current\n\n // Create open chain store (single instance for entire menu tree)\n const openChainStoreRef = React.useRef<OpenChainStore | null>(null)\n if (!openChainStoreRef.current) {\n openChainStoreRef.current = new OpenChainStore()\n }\n const openChainStore = openChainStoreRef.current\n\n // Registry for tracking open submenus (for closeAll)\n type SurfaceEntry = { depth: number; setOpen: (open: boolean) => void }\n const surfaceRegistryRef = React.useRef<Map<string, SurfaceEntry>>(new Map())\n\n // Register a surface (submenu) for closeAll tracking\n const registerSurface = React.useCallback(\n (depth: number, setOpen: (open: boolean) => void) => {\n const id = Math.random().toString(36).slice(2)\n surfaceRegistryRef.current.set(id, { depth, setOpen })\n return () => {\n surfaceRegistryRef.current.delete(id)\n }\n },\n [],\n )\n\n // Close the entire menu tree from deepest submenu to root\n const closeAll = React.useCallback(\n (reason: PopupMenuOpenChangeReason = REASONS.itemPress, event?: Event) => {\n // Sort surfaces by depth (deepest first)\n const surfaces = [...surfaceRegistryRef.current.values()].sort(\n (a, b) => b.depth - a.depth,\n )\n\n // Close each submenu from deepest to shallowest\n for (const surface of surfaces) {\n surface.setOpen(false)\n }\n\n // Finally close the root\n store.setOpen(false, reason, event)\n\n // Clear focus ownership and open chain\n focusOwnerStore.clearOwner()\n openChainStore.clear()\n },\n [store, focusOwnerStore, openChainStore],\n )\n\n // Ref to hold closeAll for use in the pointerdown effect\n const closeAllRef = React.useRef(closeAll)\n closeAllRef.current = closeAll\n\n // Listen for pointerdown events on document to detect outside clicks\n // This is a single listener at the root level that handles the entire menu tree.\n // Behavior depends on closeOnOutsidePress:\n // - 'pointerdown': Close immediately when pointer is pressed outside\n // - 'click': Store event and convert focus-out to outside-press reason\n React.useEffect(() => {\n if (!isOpen || disabled) {\n outsidePointerEventRef.current = null\n return\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target as Element | null\n if (!target) return\n\n // Check if the pointerdown is inside any part of the menu tree or its triggers\n // base-ui sets data-open on popups and data-popup-open on triggers\n const isInsidePopup = target.closest('[data-open]') !== null\n const isInsideTrigger = target.closest('[data-popup-open]') !== null\n const isInside = isInsidePopup || isInsideTrigger\n\n if (closeOnOutsidePress === 'pointerdown' && !isInside) {\n // Close entire menu tree immediately on pointerdown outside\n closeAllRef.current(REASONS.outsidePress, event)\n } else {\n // Store the event for focus-out-to-outside-press conversion\n outsidePointerEventRef.current = event\n }\n }\n\n // Use capture phase to see the event before any stopPropagation\n document.addEventListener('pointerdown', handlePointerDown, true)\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown, true)\n outsidePointerEventRef.current = null\n }\n }, [isOpen, closeOnOutsidePress, disabled])\n\n // Handle open state change\n const handleOpenChange = React.useCallback(\n (\n newOpen: boolean,\n reason: PopupMenuOpenChangeReason = REASONS.none,\n event?: Event,\n ) => {\n const isImperativeAction = reason === REASONS.imperativeAction\n\n // Ignore user-driven open/close interactions while disabled.\n if (disabled && !isImperativeAction) {\n return\n }\n\n store.setOpen(newOpen, reason, event)\n // Clear focus ownership and open chain when menu closes\n if (!newOpen) {\n focusOwnerStore.clearOwner()\n openChainStore.clear()\n }\n },\n [store, focusOwnerStore, openChainStore, disabled],\n )\n\n // Memoize listbox wiring config\n const virtualization = React.useMemo(() => {\n if (!virtualized && !onHighlightChange) {\n return undefined\n }\n\n return {\n virtualized,\n items: itemsProp ?? [],\n onHighlightChange: handleHighlightChange,\n }\n }, [virtualized, itemsProp, handleHighlightChange, onHighlightChange])\n\n return {\n menuTreeResolver,\n store,\n focusOwnerStore,\n openChainStore,\n registerSurface,\n closeAll,\n virtualization,\n handleOpenChange,\n disabled,\n setDisabled,\n }\n}\n","import { slugify } from '../../listbox/utils/normalize.js'\nimport type { NodeDef } from '../data-first/types.js'\nimport type {\n GetResolvedIdFn,\n PopupMenuIdScope,\n PopupMenuNode,\n UnresolvedMenuNode,\n} from './types.js'\n\nexport function isPopupMenuNode(value: unknown): value is PopupMenuNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'def' in value &&\n typeof (value as PopupMenuNode).id === 'string' &&\n typeof (value as PopupMenuNode).definitionKey === 'string' &&\n Array.isArray((value as PopupMenuNode).definitionPath) &&\n Array.isArray((value as PopupMenuNode).children) &&\n typeof (value as PopupMenuNode).depth === 'number' &&\n 'parent' in value\n )\n}\n\nfunction encodeDefinitionPathEntry(entry: string): string {\n let encoded = ''\n for (let index = 0; index < entry.length; index += 1) {\n const codeUnit = entry.charCodeAt(index)\n const isSafe =\n (codeUnit >= 0x41 && codeUnit <= 0x5a) ||\n (codeUnit >= 0x61 && codeUnit <= 0x7a) ||\n (codeUnit >= 0x30 && codeUnit <= 0x39) ||\n codeUnit === 0x2e ||\n codeUnit === 0x5f ||\n codeUnit === 0x7e ||\n codeUnit === 0x2d\n encoded += isSafe\n ? String.fromCharCode(codeUnit)\n : `%${codeUnit.toString(16).padStart(4, '0')}`\n }\n return encoded\n}\n\n/** Default Resolved ID, using surface-scoped encoded paths unless menu scope is selected. */\nexport function defaultGetResolvedId(\n node: UnresolvedMenuNode,\n idScope: PopupMenuIdScope = 'surface',\n): string {\n if (idScope === 'menu') return node.definitionKey\n return node.definitionPath.map(encodeDefinitionPathEntry).join('/')\n}\n\n/** Definition Key for a def: explicit `id` verbatim, else slugified `value`. */\nexport function definitionKeyForDef(def: NodeDef): string {\n switch (def.kind) {\n case 'group':\n case 'radio-group':\n return def.id\n case 'separator':\n return def.id\n default:\n return def.id ?? slugify(def.value)\n }\n}\n\n/** Child defs of a def, in def order; empty for leaf kinds. */\nexport function childDefsOf(def: NodeDef): readonly NodeDef[] {\n switch (def.kind) {\n case 'group':\n case 'radio-group':\n return def.nodes\n case 'submenu':\n case 'subpage':\n case 'tree-item':\n return def.nodes ?? []\n default:\n return []\n }\n}\n\n/** Kinds whose Definition Key is part of their descendants' definition paths. */\nexport function contributesDefinitionPath(def: NodeDef): boolean {\n return def.kind === 'submenu' || def.kind === 'subpage'\n}\n\n/**\n * Resolve a def list into node instances under `parent`.\n * `basePath` is the path segments contributed by ancestors (the parent's\n * `definitionPath` when the parent contributes a segment, otherwise the parent's\n * own base path); pass `[]` for roots.\n */\nexport function resolveNodeDefs(\n defs: readonly NodeDef[],\n parent: PopupMenuNode | null,\n basePath: readonly string[],\n getResolvedId: GetResolvedIdFn,\n): PopupMenuNode[] {\n return defs.map((def, index) => {\n const definitionKey = definitionKeyForDef(def)\n const definitionPath = [...basePath, definitionKey]\n const unresolved: UnresolvedMenuNode = {\n def,\n kind: def.kind,\n definitionKey,\n definitionPath,\n parent,\n children: [],\n depth: parent ? parent.depth + 1 : 0,\n index,\n }\n // Call the seam before spreading so the node reflects any reads the seam\n // performs on the final definitional facts (spread-then-call would copy\n // the fields before the seam runs).\n const id = getResolvedId(unresolved)\n const node: PopupMenuNode = { ...unresolved, id }\n node.children = resolveNodeDefs(\n childDefsOf(def),\n node,\n contributesDefinitionPath(def) ? node.definitionPath : basePath,\n getResolvedId,\n )\n return node\n })\n}\n\n/**\n * The branch's resolved static children: the Menu Nodes whose def is one of\n * the branch def's authored `nodes`, in `children` order. Loader results are\n * grafted as children too but are never in `def.nodes`, so they are excluded\n * whether the graft appended to or replaced the static children.\n */\nexport function staticChildrenOf(branch: PopupMenuNode): PopupMenuNode[] {\n const authored = (branch.def as { nodes?: readonly NodeDef[] }).nodes\n if (!authored || authored.length === 0) return []\n const authoredSet = new Set<NodeDef>(authored)\n return branch.children.filter((child) => authoredSet.has(child.def))\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/ui/ui/packages/react/dist/chunk-W4ACKMIZ.cjs","../src/internal/popup-menu/contexts/focus-owner-context.ts","../src/internal/popup-menu/contexts/open-chain-context.ts","../src/internal/popup-menu/contexts/popup-menu-context.ts","../src/internal/popup-menu/contexts/popup-surface-id-context.ts","../src/internal/popup-menu/contexts/submenu-context.ts","../src/internal/popup-menu/contexts/subpage-context.ts","../src/internal/popup-menu/contexts/subpage-stack-context.ts","../src/internal/popup-menu/store/FocusOwnerStore.ts","../src/internal/popup-menu/hooks/use-popup-menu-root.ts","../src/internal/popup-menu/menu-tree/resolve.ts"],"names":["FocusOwnerContext","useFocusOwner","context","OpenChainContext","useOpenChain","PopupMenuContext","usePopupMenuContext","useMaybePopupMenuContext","PopupSurfaceIdContext","usePopupSurfaceId","SubmenuContext","useSubmenuContext","useMaybeSubmenuContext","SubpageContext","useSubpageContext","useMaybeSubpageContext","SubpageStackContext","useSubpageStack","useMaybeSubpageStack","selectors","createSelector","state","surfaceId","FocusOwnerStore","ReactStore","id","isPopupMenuNode","value","encodeDefinitionPathEntry","entry","encoded","index","codeUnit","isSafe"],"mappings":"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","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-W4ACKMIZ.cjs","sourcesContent":[null,"'use client'\n\nimport * as React from 'react'\nimport type { FocusOwnerStore } from '../store/FocusOwnerStore.js'\n\n// ============================================================================\n// Focus Owner Context\n// ============================================================================\n\nconst FocusOwnerContext = React.createContext<FocusOwnerStore | null>(null)\n\nexport function useFocusOwner(): FocusOwnerStore {\n const context = React.useContext(FocusOwnerContext)\n if (!context) {\n throw new Error(\n 'FocusOwner components must be used within a FocusOwnerProvider',\n )\n }\n return context\n}\n\nexport function useMaybeFocusOwner(): FocusOwnerStore | null {\n return React.useContext(FocusOwnerContext)\n}\n\nexport { FocusOwnerContext }\n","'use client'\n\nimport * as React from 'react'\nimport type { OpenChainStore } from '../store/OpenChainStore.js'\n\n// ============================================================================\n// Open Chain Context\n// ============================================================================\n\nconst OpenChainContext = React.createContext<OpenChainStore | null>(null)\n\nexport function useOpenChain(): OpenChainStore {\n const context = React.useContext(OpenChainContext)\n if (!context) {\n throw new Error(\n 'OpenChain components must be used within an OpenChainProvider',\n )\n }\n return context\n}\n\nexport function useMaybeOpenChain(): OpenChainStore | null {\n return React.useContext(OpenChainContext)\n}\n\nexport { OpenChainContext }\n","'use client'\n\nimport * as React from 'react'\nimport type {\n ListboxStore,\n VirtualItem,\n} from '../../listbox/store/ListboxStore.js'\nimport type {\n HighlightChangeEventDetails,\n PopupMenuOpenChangeReason,\n} from '../events.js'\n\n// ============================================================================\n// Popup Menu Context\n// ============================================================================\n// Shared root-level context for popup menus (DropdownMenu, ContextMenu).\n// Provides core menu functionality to all child components.\n\n/**\n * Virtual anchor for positioning the menu at a specific point.\n * Used by ContextMenu to position at cursor location.\n */\nexport interface VirtualAnchor {\n getBoundingClientRect(): DOMRect\n}\n\n/**\n * Virtualization configuration passed from Root/Submenu to Surface.\n */\nexport interface VirtualizationConfig {\n /** Whether virtualization mode is enabled */\n virtualized: boolean\n /** Pre-registered items for virtualization */\n items: VirtualItem[]\n /**\n * Callback when highlighted item changes (for scroll sync).\n * The third parameter contains event details including the reason for the change.\n */\n onHighlightChange?: (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => void\n}\n\n/**\n * Shared context value for popup menus.\n * Both DropdownMenu.Root and ContextMenu.Root provide this context.\n */\nexport interface PopupMenuContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Whether this menu tree currently ignores user interaction. */\n disabled: boolean\n /** Nesting depth: 0 = root menu, 1+ = submenu */\n depth: number\n /** Close the entire menu tree (deepest submenu to root, sequentially) */\n closeAll: (reason?: PopupMenuOpenChangeReason, event?: Event) => void\n /**\n * Internal: when true, Surface handles Tab explicitly (close the tree, or\n * cycle through focus zones). Enabled only by DropdownMenu.Root and\n * ContextMenu.Root — never Select or Combobox.\n */\n explicitTabBehavior: boolean\n /**\n * Internal: what Tab does under `explicitTabBehavior` when the surface (and\n * its ancestors) have no focus-zone tabbables. `'close'` closes the whole\n * tree (dropdown/context-menu). `'inert'` swallows the event, keeping focus\n * where it is (command palette).\n */\n tabWithoutZones: 'close' | 'inert'\n /** Register a surface (submenu) for closeAll tracking. Returns unregister function. */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Virtualization configuration (if enabled) */\n virtualization?: VirtualizationConfig\n /**\n * Virtual anchor for positioning.\n * Used by ContextMenu to position at cursor location.\n * DropdownMenu uses the Popover's anchor (trigger button) instead.\n */\n virtualAnchor?: VirtualAnchor\n /**\n * Type of menu for positioning logic.\n * - 'dropdown': positions relative to trigger button\n * - 'context': positions at cursor with fixed positioning\n */\n menuType: 'dropdown' | 'context'\n /**\n * When to close the menu on outside interactions.\n * - 'pointerdown': Close immediately when pointer is pressed outside (default)\n * - 'click': Close when a full click (pointerdown + pointerup) occurs outside\n * @default 'pointerdown'\n */\n closeOnOutsidePress: 'click' | 'pointerdown'\n}\n\nconst PopupMenuContext = React.createContext<PopupMenuContextValue | null>(null)\n\n/**\n * Hook to access the popup menu context.\n * Throws if used outside a popup menu.\n */\nexport function usePopupMenuContext(): PopupMenuContextValue {\n const context = React.useContext(PopupMenuContext)\n if (!context) {\n throw new Error(\n 'PopupMenu components must be used within a PopupMenu.Root or ContextMenu.Root',\n )\n }\n return context\n}\n\n/**\n * Hook to optionally access the popup menu context.\n * Returns null if used outside a popup menu.\n */\nexport function useMaybePopupMenuContext(): PopupMenuContextValue | null {\n return React.useContext(PopupMenuContext)\n}\n\n// Re-export for convenience\nexport type { VirtualItem }\nexport { PopupMenuContext }\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Popup Surface ID Context\n// ============================================================================\n\n/**\n * Context for passing surfaceId from Popup to Surface.\n * This ensures Popup and Surface share the same ID for data attribute tracking.\n *\n * For root menus, Popup generates the ID and provides it via this context.\n * For submenus, the ID comes from SubmenuContext.childSurfaceId instead.\n */\nconst PopupSurfaceIdContext = React.createContext<string | null>(null)\n\nexport function usePopupSurfaceId(): string | null {\n return React.useContext(PopupSurfaceIdContext)\n}\n\nexport { PopupSurfaceIdContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubmenuContextValue {\n /** Whether the submenu is open */\n open: boolean\n /** Set the submenu open state */\n setOpen: (open: boolean) => void\n /**\n * Latch set by explicit close actions (keyboard ArrowLeft/Ctrl+H/Escape-in-submenu,\n * or clicking the open trigger). While set and the trigger remains highlighted,\n * pointer/keyboard auto-open is suppressed. Reset when highlight leaves the trigger.\n */\n suppressAutoOpenRef: React.MutableRefObject<boolean>\n /** Reference to the trigger element */\n triggerRef: React.RefObject<HTMLElement | null>\n /** Reference to the submenu content element (for aim guard rect calculations) */\n contentRef: React.RefObject<HTMLElement | null>\n /** Surface ID of the parent menu (for keyboard navigation back) */\n parentSurfaceId: string\n /** Surface ID of this submenu (for keyboard navigation into) */\n childSurfaceId: string\n /**\n * Whether pressing Escape in this submenu closes the entire menu from the root.\n * When true, Escape closes the entire menu tree.\n * When false, Escape only closes this submenu and moves focus to the parent.\n * @default true\n */\n closeRootOnEsc: boolean\n}\n\nconst SubmenuContext = React.createContext<SubmenuContextValue | null>(null)\n\nexport function useSubmenuContext(): SubmenuContextValue {\n const context = React.useContext(SubmenuContext)\n if (!context) {\n throw new Error('SubmenuTrigger must be used within a Submenu')\n }\n return context\n}\n\nexport function useMaybeSubmenuContext(): SubmenuContextValue | null {\n return React.useContext(SubmenuContext)\n}\n\nexport { SubmenuContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubpageContextValue {\n /** Current page ID. */\n pageId: string\n /** Surface ID for this page. */\n surfaceId: string\n /** Surface ID for the previous page, if available. */\n parentSurfaceId: string | null\n /** Whether this page is currently active. */\n isActive: boolean\n /** Whether Escape should close the entire menu tree from this page. */\n closeRootOnEsc: boolean\n /** Navigate back one page. Returns true when navigation happened. */\n goBack: () => boolean\n}\n\nconst SubpageContext = React.createContext<SubpageContextValue | null>(null)\n\nexport function useSubpageContext(): SubpageContextValue {\n const context = React.useContext(SubpageContext)\n if (!context) {\n throw new Error(\n 'Subpage components must be used within a PopupMenu.Subpage',\n )\n }\n return context\n}\n\nexport function useMaybeSubpageContext(): SubpageContextValue | null {\n return React.useContext(SubpageContext)\n}\n\nexport { SubpageContext }\n","'use client'\n\nimport * as React from 'react'\n\nexport interface SubpageRegistration {\n pageId: string\n surfaceId: string\n closeRootOnEsc: boolean\n}\n\nexport interface SubpageStackContextValue {\n /** Active page ID; `null` when the root surface is active. */\n activePageId: string | null\n /** Surface ID of the root surface. */\n rootSurfaceId: string\n /** Surface ID for the currently active page. */\n activeSurfaceId: string\n /** Whether there is a previous page to navigate back to. */\n canGoBack: boolean\n /** Whether Escape in the active page should close the entire menu tree. */\n shouldCloseRootOnEsc: boolean\n /** Open page IDs, bottom to top; empty at root. */\n stack: readonly string[]\n /** Register a page and return an unregister cleanup. */\n registerPage: (registration: SubpageRegistration) => () => void\n /** Push a page onto the stack. Returns true when navigation happened. */\n openPage: (pageId: string) => boolean\n /** Pop one page from the stack. Returns true when navigation happened. */\n goBack: () => boolean\n /** Resolve a surface ID for a page ID. */\n getSurfaceId: (pageId: string) => string | null\n}\n\nconst SubpageStackContext =\n React.createContext<SubpageStackContextValue | null>(null)\n\nexport function useSubpageStack(): SubpageStackContextValue {\n const context = React.useContext(SubpageStackContext)\n if (!context) {\n throw new Error('Subpage components must be used within a PopupMenu.Popup')\n }\n return context\n}\n\nexport function useMaybeSubpageStack(): SubpageStackContextValue | null {\n return React.useContext(SubpageStackContext)\n}\n\nexport { SubpageStackContext }\n","import { createSelector, ReactStore } from '@base-ui/utils/store'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface FocusOwnerState {\n /** Which surface currently owns focus (surfaceId or null) */\n ownerId: string | null\n}\n\n// ============================================================================\n// Selectors\n// ============================================================================\n\nconst selectors = {\n ownerId: createSelector((state: FocusOwnerState) => state.ownerId),\n isOwner: createSelector(\n (state: FocusOwnerState, surfaceId: string) => state.ownerId === surfaceId,\n ),\n}\n\n// ============================================================================\n// Store\n// ============================================================================\n\n/**\n * Tracks which menu surface owns DOM focus.\n * Single instance per menu tree (created at root, shared via context).\n *\n * Used by: DropdownMenu, ContextMenu\n * Not used by: Select, CommandMenu (single surface)\n */\nexport class FocusOwnerStore extends ReactStore<\n FocusOwnerState,\n Record<string, never>,\n typeof selectors\n> {\n constructor() {\n super({ ownerId: null }, {}, selectors)\n }\n\n /**\n * Set the owner surface ID.\n * Call this when focus should transfer to a new surface.\n */\n setOwnerId(id: string | null) {\n this.set('ownerId', id)\n }\n\n /**\n * Clear the owner (set to null).\n * Call this when the menu tree closes.\n */\n clearOwner() {\n this.set('ownerId', null)\n }\n}\n\nexport type { FocusOwnerState as State }\n","'use client'\n\nimport * as React from 'react'\nimport type { ChangeEventDetails } from '../../../utils/events/index.js'\nimport {\n createChangeEventDetails,\n REASONS,\n} from '../../../utils/events/index.js'\nimport { ensureInputModalityTracking } from '../../../utils/input-modality.js'\nimport { ListboxStore, type VirtualItem } from '../../listbox/index.js'\nimport type { VirtualizationConfig } from '../contexts/popup-menu-context.js'\nimport type {\n HighlightChangeEventDetails,\n PopupMenuHighlightChangeHandler,\n PopupMenuOpenChangeReason,\n} from '../events.js'\nimport type { MenuTreeResolver } from '../menu-tree/resolver.js'\nimport { createMenuTreeResolver } from '../menu-tree/resolver.js'\nimport type { GetResolvedIdFn, PopupMenuIdScope } from '../menu-tree/types.js'\nimport { FocusOwnerStore } from '../store/FocusOwnerStore.js'\nimport { OpenChainStore } from '../store/OpenChainStore.js'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface UsePopupMenuRootParams {\n /**\n * Computes canonical Resolved IDs for data-first content from the Unresolved Menu Node (definitional facts only).\n * @default explicit `def.id` verbatim, else the joined definition path\n * Read once when the menu root mounts — later changes have no effect.\n */\n getResolvedId?: GetResolvedIdFn\n /** Definition Key uniqueness scope. Read once when the menu root mounts. */\n idScope?: PopupMenuIdScope\n /**\n * Callback when the open state changes.\n * The second parameter contains event details including the reason for the change.\n */\n onOpenChange?: (\n open: boolean,\n eventDetails: ChangeEventDetails<string>,\n ) => void\n\n /**\n * Whether the menu is initially open.\n * @default false\n */\n defaultOpen?: boolean\n\n /**\n * Whether virtualization mode is enabled.\n * @default false\n */\n virtualized?: boolean\n\n /**\n * Pre-registered items for virtualization.\n */\n items?: VirtualItem[]\n\n /**\n * Callback when the highlighted item changes. `id` is first; `node` is the\n * resolved menu node enrichment and may be null.\n * The fourth parameter contains event details including the reason for the change.\n */\n onHighlightChange?: PopupMenuHighlightChangeHandler<HighlightChangeEventDetails>\n\n /**\n * When to close the menu on outside interactions.\n * - 'pointerdown': Close immediately when pointer is pressed outside (default)\n * - 'click': Close when a full click (pointerdown + pointerup) occurs outside\n * @default 'pointerdown'\n */\n closeOnOutsidePress?: 'click' | 'pointerdown'\n\n /**\n * Whether the menu should ignore user interaction.\n * Can be controlled declaratively via this prop, or imperatively via actionsRef.setDisabled().\n * @default false\n */\n disabled?: boolean\n\n /**\n * Initial disabled state for imperative usage.\n * Ignored when `disabled` prop is true.\n * @default false\n */\n defaultDisabled?: boolean\n}\n\nexport interface PopupMenuRootActions {\n /** Close the menu tree imperatively. */\n close: () => void\n /** Unmount the popup imperatively (when keep-mounted mode is enabled). */\n unmount: () => void\n /** Enable/disable the menu tree imperatively. */\n setDisabled: (disabled: boolean) => void\n}\n\nexport interface UsePopupMenuRootReturn {\n /** The menu-tree resolver for this menu root. */\n menuTreeResolver: MenuTreeResolver\n /** The Listbox store instance */\n store: ListboxStore\n /** The FocusOwner store instance */\n focusOwnerStore: FocusOwnerStore\n /** The OpenChain store instance */\n openChainStore: OpenChainStore\n /** Register a surface (submenu) for closeAll tracking */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Close the entire menu tree */\n closeAll: (reason?: PopupMenuOpenChangeReason, event?: Event) => void\n /** Virtualization configuration (if enabled) */\n virtualization: VirtualizationConfig | undefined\n /** Handle open state change (updates store and clears stores on close) */\n handleOpenChange: (\n open: boolean,\n reason?: PopupMenuOpenChangeReason,\n event?: Event,\n ) => void\n /** Whether the menu currently ignores user interaction. */\n disabled: boolean\n /** Update imperative disabled state. */\n setDisabled: (disabled: boolean) => void\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook that creates and manages the core stores and utilities for popup menus.\n * Used by both DropdownMenu.Root and ContextMenu.Root.\n *\n * Provides:\n * - ListboxStore for item management\n * - FocusOwnerStore for focus tracking across submenus\n * - OpenChainStore for tracking open submenu chain\n * - Surface registry for closeAll functionality\n */\nexport function usePopupMenuRoot(\n params: UsePopupMenuRootParams = {},\n): UsePopupMenuRootReturn {\n const {\n onOpenChange,\n defaultOpen = false,\n virtualized = false,\n items: itemsProp,\n onHighlightChange,\n closeOnOutsidePress = 'pointerdown',\n disabled: disabledProp = false,\n defaultDisabled = false,\n getResolvedId,\n idScope = 'surface',\n } = params\n\n const menuTreeResolverRef = React.useRef<MenuTreeResolver | null>(null)\n if (menuTreeResolverRef.current === null) {\n menuTreeResolverRef.current = createMenuTreeResolver({\n getResolvedId,\n idScope,\n })\n }\n const menuTreeResolver = menuTreeResolverRef.current\n\n const handleHighlightChange = React.useCallback(\n (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => {\n onHighlightChange?.(\n id,\n id === null ? null : (menuTreeResolver.getNodeById(id) ?? null),\n index,\n eventDetails,\n )\n },\n [menuTreeResolver, onHighlightChange],\n )\n\n const [imperativeDisabled, setImperativeDisabled] =\n React.useState(defaultDisabled)\n const disabled = disabledProp || imperativeDisabled\n\n const setDisabled = React.useCallback((nextDisabled: boolean) => {\n setImperativeDisabled(nextDisabled)\n }, [])\n\n // Begin tracking global input modality so the store can attribute opens to\n // mouse/touch/pen/keyboard. Idempotent; installed once for the whole app.\n React.useEffect(() => {\n ensureInputModalityTracking()\n }, [])\n\n // Track outside pointer events to distinguish outside-press from focus-out\n // When a pointerdown happens outside the menu, we store it so that if a\n // focus-out close happens immediately after, we can treat it as outside-press\n const outsidePointerEventRef = React.useRef<PointerEvent | null>(null)\n\n // Create stable callback wrapper for onOpenChange that converts focus-out to outside-press\n // when the close was triggered by a pointer event outside the menu\n const stableOnOpenChange = React.useCallback(\n (open: boolean, eventDetails: ChangeEventDetails<string>) => {\n // If closing due to focus-out but we have a stored outside pointer event,\n // convert the reason to outside-press for better cancel() support\n if (\n !open &&\n eventDetails.reason === REASONS.focusOut &&\n outsidePointerEventRef.current\n ) {\n const pointerEvent = outsidePointerEventRef.current\n outsidePointerEventRef.current = null\n\n // Create new event details with outside-press reason and the pointer event\n const convertedDetails = createChangeEventDetails(\n REASONS.outsidePress,\n pointerEvent,\n )\n\n onOpenChange?.(open, convertedDetails)\n\n // If the converted callback canceled, also cancel the original\n if (convertedDetails.isCanceled) {\n eventDetails.cancel()\n }\n return\n }\n\n // Clear the pointer event ref if we're not using it\n outsidePointerEventRef.current = null\n\n onOpenChange?.(open, eventDetails)\n },\n [onOpenChange],\n )\n\n // Create the store instance\n const store = ListboxStore.useStore(\n undefined,\n { open: defaultOpen },\n {\n onOpenChange: stableOnOpenChange,\n },\n )\n\n // Get current open state for the pointer event listener\n const isOpen = store.useState('open')\n\n // Create focus owner store (single instance for entire menu tree)\n const focusOwnerStoreRef = React.useRef<FocusOwnerStore | null>(null)\n if (!focusOwnerStoreRef.current) {\n focusOwnerStoreRef.current = new FocusOwnerStore()\n }\n const focusOwnerStore = focusOwnerStoreRef.current\n\n // Create open chain store (single instance for entire menu tree)\n const openChainStoreRef = React.useRef<OpenChainStore | null>(null)\n if (!openChainStoreRef.current) {\n openChainStoreRef.current = new OpenChainStore()\n }\n const openChainStore = openChainStoreRef.current\n\n // Registry for tracking open submenus (for closeAll)\n type SurfaceEntry = { depth: number; setOpen: (open: boolean) => void }\n const surfaceRegistryRef = React.useRef<Map<string, SurfaceEntry>>(new Map())\n\n // Register a surface (submenu) for closeAll tracking\n const registerSurface = React.useCallback(\n (depth: number, setOpen: (open: boolean) => void) => {\n const id = Math.random().toString(36).slice(2)\n surfaceRegistryRef.current.set(id, { depth, setOpen })\n return () => {\n surfaceRegistryRef.current.delete(id)\n }\n },\n [],\n )\n\n // Close the entire menu tree from deepest submenu to root\n const closeAll = React.useCallback(\n (reason: PopupMenuOpenChangeReason = REASONS.itemPress, event?: Event) => {\n // Sort surfaces by depth (deepest first)\n const surfaces = [...surfaceRegistryRef.current.values()].sort(\n (a, b) => b.depth - a.depth,\n )\n\n // Close each submenu from deepest to shallowest\n for (const surface of surfaces) {\n surface.setOpen(false)\n }\n\n // Finally close the root\n store.setOpen(false, reason, event)\n\n // Clear focus ownership and open chain\n focusOwnerStore.clearOwner()\n openChainStore.clear()\n },\n [store, focusOwnerStore, openChainStore],\n )\n\n // Ref to hold closeAll for use in the pointerdown effect\n const closeAllRef = React.useRef(closeAll)\n closeAllRef.current = closeAll\n\n // Listen for pointerdown events on document to detect outside clicks\n // This is a single listener at the root level that handles the entire menu tree.\n // Behavior depends on closeOnOutsidePress:\n // - 'pointerdown': Close immediately when pointer is pressed outside\n // - 'click': Store event and convert focus-out to outside-press reason\n React.useEffect(() => {\n if (!isOpen || disabled) {\n outsidePointerEventRef.current = null\n return\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target as Element | null\n if (!target) return\n\n // Check if the pointerdown is inside any part of the menu tree or its triggers\n // base-ui sets data-open on popups and data-popup-open on triggers\n const isInsidePopup = target.closest('[data-open]') !== null\n const isInsideTrigger = target.closest('[data-popup-open]') !== null\n const isInside = isInsidePopup || isInsideTrigger\n\n if (closeOnOutsidePress === 'pointerdown' && !isInside) {\n // Close entire menu tree immediately on pointerdown outside\n closeAllRef.current(REASONS.outsidePress, event)\n } else {\n // Store the event for focus-out-to-outside-press conversion\n outsidePointerEventRef.current = event\n }\n }\n\n // Use capture phase to see the event before any stopPropagation\n document.addEventListener('pointerdown', handlePointerDown, true)\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown, true)\n outsidePointerEventRef.current = null\n }\n }, [isOpen, closeOnOutsidePress, disabled])\n\n // Handle open state change\n const handleOpenChange = React.useCallback(\n (\n newOpen: boolean,\n reason: PopupMenuOpenChangeReason = REASONS.none,\n event?: Event,\n ) => {\n const isImperativeAction = reason === REASONS.imperativeAction\n\n // Ignore user-driven open/close interactions while disabled.\n if (disabled && !isImperativeAction) {\n return\n }\n\n store.setOpen(newOpen, reason, event)\n // Clear focus ownership and open chain when menu closes\n if (!newOpen) {\n focusOwnerStore.clearOwner()\n openChainStore.clear()\n }\n },\n [store, focusOwnerStore, openChainStore, disabled],\n )\n\n // Memoize listbox wiring config\n const virtualization = React.useMemo(() => {\n if (!virtualized && !onHighlightChange) {\n return undefined\n }\n\n return {\n virtualized,\n items: itemsProp ?? [],\n onHighlightChange: handleHighlightChange,\n }\n }, [virtualized, itemsProp, handleHighlightChange, onHighlightChange])\n\n return {\n menuTreeResolver,\n store,\n focusOwnerStore,\n openChainStore,\n registerSurface,\n closeAll,\n virtualization,\n handleOpenChange,\n disabled,\n setDisabled,\n }\n}\n","import { slugify } from '../../listbox/utils/normalize.js'\nimport type { NodeDef } from '../data-first/types.js'\nimport type {\n GetResolvedIdFn,\n PopupMenuIdScope,\n PopupMenuNode,\n UnresolvedMenuNode,\n} from './types.js'\n\nexport function isPopupMenuNode(value: unknown): value is PopupMenuNode {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'def' in value &&\n typeof (value as PopupMenuNode).id === 'string' &&\n typeof (value as PopupMenuNode).definitionKey === 'string' &&\n Array.isArray((value as PopupMenuNode).definitionPath) &&\n Array.isArray((value as PopupMenuNode).children) &&\n typeof (value as PopupMenuNode).depth === 'number' &&\n 'parent' in value\n )\n}\n\nfunction encodeDefinitionPathEntry(entry: string): string {\n let encoded = ''\n for (let index = 0; index < entry.length; index += 1) {\n const codeUnit = entry.charCodeAt(index)\n const isSafe =\n (codeUnit >= 0x41 && codeUnit <= 0x5a) ||\n (codeUnit >= 0x61 && codeUnit <= 0x7a) ||\n (codeUnit >= 0x30 && codeUnit <= 0x39) ||\n codeUnit === 0x2e ||\n codeUnit === 0x5f ||\n codeUnit === 0x7e ||\n codeUnit === 0x2d\n encoded += isSafe\n ? String.fromCharCode(codeUnit)\n : `%${codeUnit.toString(16).padStart(4, '0')}`\n }\n return encoded\n}\n\n/** Default Resolved ID, using surface-scoped encoded paths unless menu scope is selected. */\nexport function defaultGetResolvedId(\n node: UnresolvedMenuNode,\n idScope: PopupMenuIdScope = 'surface',\n): string {\n if (idScope === 'menu') return node.definitionKey\n return node.definitionPath.map(encodeDefinitionPathEntry).join('/')\n}\n\n/** Definition Key for a def: explicit `id` verbatim, else slugified `value`. */\nexport function definitionKeyForDef(def: NodeDef): string {\n switch (def.kind) {\n case 'group':\n case 'radio-group':\n return def.id\n case 'separator':\n return def.id\n default:\n return def.id ?? slugify(def.value)\n }\n}\n\n/** Child defs of a def, in def order; empty for leaf kinds. */\nexport function childDefsOf(def: NodeDef): readonly NodeDef[] {\n switch (def.kind) {\n case 'group':\n case 'radio-group':\n return def.nodes\n case 'submenu':\n case 'subpage':\n case 'tree-item':\n return def.nodes ?? []\n default:\n return []\n }\n}\n\n/** Kinds whose Definition Key is part of their descendants' definition paths. */\nexport function contributesDefinitionPath(def: NodeDef): boolean {\n return def.kind === 'submenu' || def.kind === 'subpage'\n}\n\n/**\n * Resolve a def list into node instances under `parent`.\n * `basePath` is the path segments contributed by ancestors (the parent's\n * `definitionPath` when the parent contributes a segment, otherwise the parent's\n * own base path); pass `[]` for roots.\n */\nexport function resolveNodeDefs(\n defs: readonly NodeDef[],\n parent: PopupMenuNode | null,\n basePath: readonly string[],\n getResolvedId: GetResolvedIdFn,\n): PopupMenuNode[] {\n return defs.map((def, index) => {\n const definitionKey = definitionKeyForDef(def)\n const definitionPath = [...basePath, definitionKey]\n const unresolved: UnresolvedMenuNode = {\n def,\n kind: def.kind,\n definitionKey,\n definitionPath,\n parent,\n children: [],\n depth: parent ? parent.depth + 1 : 0,\n index,\n }\n // Call the seam before spreading so the node reflects any reads the seam\n // performs on the final definitional facts (spread-then-call would copy\n // the fields before the seam runs).\n const id = getResolvedId(unresolved)\n const node: PopupMenuNode = { ...unresolved, id }\n node.children = resolveNodeDefs(\n childDefsOf(def),\n node,\n contributesDefinitionPath(def) ? node.definitionPath : basePath,\n getResolvedId,\n )\n return node\n })\n}\n\n/**\n * The branch's resolved static children: the Menu Nodes whose def is one of\n * the branch def's authored `nodes`, in `children` order. Loader results are\n * grafted as children too but are never in `def.nodes`, so they are excluded\n * whether the graft appended to or replaced the static children.\n */\nexport function staticChildrenOf(branch: PopupMenuNode): PopupMenuNode[] {\n const authored = (branch.def as { nodes?: readonly NodeDef[] }).nodes\n if (!authored || authored.length === 0) return []\n const authoredSet = new Set<NodeDef>(authored)\n return branch.children.filter((child) => authoredSet.has(child.def))\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-XMZZ62VJ.cjs","../src/internal/listbox/contexts/group-context.ts","../src/internal/listbox/contexts/item-context.ts","../src/internal/listbox/contexts/listbox-context.ts","../src/internal/listbox/contexts/row-width-context.ts","../src/internal/listbox/contexts/surface-context.ts","../src/internal/listbox/hooks/use-listbox-item.ts","../src/internal/listbox/utils/normalize.ts"],"names":["GroupContext","useGroupContext","ItemContext","useItemContext","context","useMaybeItemContext","ListboxContext","useListboxContext","useMaybeListboxContext","RowWidthContext","useRowWidthContext","useMaybeRowWidthContext","SurfaceContext","useSurfaceContext","useMaybeSurfaceContext","normalizeValue","value","deburr","slugify","useListboxItem","params","idProp","valueProp","keywords","disabled","activatable","forceMount","shortcut","forceOrder","forceScore","isSubmenuTrigger","onSelect","closeOnClick","onAfterSelect","children","aimGuard","store","groupContext","depth","ref","rowId","rowElement","setRowElement","inferredValue","setInferredValue","textContent","registrationId","generatedDomId","domId"],"mappings":"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","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/chunk-XMZZ62VJ.cjs","sourcesContent":[null,"'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Group Context (for items to know their parent group)\n// ============================================================================\n\nexport interface GroupPositional {\n first?: boolean\n last?: boolean\n firstInGroup?: boolean\n lastInGroup?: boolean\n firstGroup?: boolean\n lastGroup?: boolean\n}\n\nexport interface GroupContextValue {\n groupId?: string\n positional?: GroupPositional\n}\n\nconst GroupContext = React.createContext<GroupContextValue | null>(null)\n\nexport function useGroupContext(): GroupContextValue | null {\n return React.useContext(GroupContext)\n}\n\nexport { GroupContext }\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Item Context (for child components like indicators to access item state)\n// ============================================================================\n\nexport interface ItemContextValue {\n /** Unique ID for this item (for DOM id attribute) */\n id: string\n /** Whether the item is highlighted */\n highlighted: boolean\n /** Whether the item is disabled */\n disabled: boolean\n /** Keyboard shortcut for this item */\n shortcut?: string\n}\n\nconst ItemContext = React.createContext<ItemContextValue | null>(null)\n\nexport function useItemContext(): ItemContextValue {\n const context = React.useContext(ItemContext)\n if (!context) {\n throw new Error('Item child components must be used within an Item')\n }\n return context\n}\n\nexport function useMaybeItemContext(): ItemContextValue | null {\n return React.useContext(ItemContext)\n}\n\nexport { ItemContext }\n","'use client'\n\nimport * as React from 'react'\nimport type { HighlightChangeEventDetails } from '../../popup-menu/events.js'\nimport type { ListboxStore, VirtualItem } from '../store/ListboxStore.js'\n\n/**\n * Virtualization configuration passed from Root/Submenu to Surface.\n */\nexport interface VirtualizationConfig {\n /** Whether virtualization mode is enabled */\n virtualized: boolean\n /** Pre-registered items for virtualization */\n items: VirtualItem[]\n /**\n * Callback when highlighted item changes (for scroll sync).\n * The third parameter contains event details including the reason for the change.\n */\n onHighlightChange?: (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => void\n}\n\nexport interface ListboxContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Nesting depth: 0 = root menu, 1+ = submenu */\n depth: number\n /** Close the entire menu tree (deepest submenu to root, sequentially) */\n closeAll: () => void\n /** Register a surface (submenu) for closeAll tracking. Returns unregister function. */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Virtualization configuration (if enabled) */\n virtualization?: VirtualizationConfig\n}\n\nconst ListboxContext = React.createContext<ListboxContextValue | null>(null)\n\nexport function useListboxContext(): ListboxContextValue {\n const context = React.useContext(ListboxContext)\n if (!context) {\n throw new Error('Listbox components must be used within a Listbox provider')\n }\n return context\n}\n\nexport function useMaybeListboxContext(): ListboxContextValue | null {\n return React.useContext(ListboxContext)\n}\n\nexport { ListboxContext }\n","'use client'\n\nimport * as React from 'react'\n\n/**\n * Context value for row width measurement.\n * Provided by List when `measureRowWidth` is enabled.\n */\nexport interface RowWidthContextValue {\n /**\n * Queue a row element for width measurement.\n * Call this when a row mounts or becomes visible.\n *\n * @param element - The DOM element to measure\n * @param id - Unique identifier for this row (used to avoid re-measuring)\n */\n queueMeasurement: (element: HTMLElement, id: string) => void\n}\n\n/**\n * Context for row width measurement.\n * Items use this to self-register for measurement.\n */\nexport const RowWidthContext = React.createContext<RowWidthContextValue | null>(\n null,\n)\n\nif (process.env.NODE_ENV !== 'production') {\n RowWidthContext.displayName = 'RowWidthContext'\n}\n\n/**\n * Hook to get the row width context.\n * Throws an error if used outside of a List with `measureRowWidth` enabled.\n */\nexport function useRowWidthContext(): RowWidthContextValue {\n const context = React.useContext(RowWidthContext)\n if (!context) {\n throw new Error(\n 'useRowWidthContext must be used within a List with measureRowWidth enabled',\n )\n }\n return context\n}\n\n/**\n * Hook to optionally get the row width context.\n * Returns null if not within a List with `measureRowWidth` enabled.\n * This is the preferred hook for items that should work both with and without measurement.\n */\nexport function useMaybeRowWidthContext(): RowWidthContextValue | null {\n return React.useContext(RowWidthContext)\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { ListboxStore } from '../store/ListboxStore.js'\n\n// Re-export types from the store for convenience\nexport type {\n FilterFn,\n ItemRegistration,\n} from '../store/ListboxStore.js'\n\n// ============================================================================\n// Surface Context\n// ============================================================================\n\nexport interface SurfaceContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Unique identifier for this surface */\n surfaceId: string\n}\n\nconst SurfaceContext = React.createContext<SurfaceContextValue | null>(null)\n\nexport function useSurfaceContext(): SurfaceContextValue {\n const context = React.useContext(SurfaceContext)\n if (!context) {\n throw new Error('Listbox components must be used within a Surface provider')\n }\n return context\n}\n\nexport function useMaybeSurfaceContext(): SurfaceContextValue | null {\n return React.useContext(SurfaceContext)\n}\n\nexport { SurfaceContext }\n","'use client'\n\nimport * as React from 'react'\nimport { useGroupContext } from '../contexts/group-context.js'\nimport type { ItemContextValue } from '../contexts/item-context.js'\nimport { useListboxContext } from '../contexts/listbox-context.js'\nimport { useMaybeRowWidthContext } from '../contexts/row-width-context.js'\nimport { useSurfaceContext } from '../contexts/surface-context.js'\nimport { normalizeValue } from '../utils/normalize.js'\n\n/**\n * Aim guard refs for submenu navigation.\n * Optional - only needed for popup menus with submenus.\n */\nexport interface AimGuardRefs {\n /** Whether aim guard is currently active */\n aimGuardActiveRef: React.RefObject<boolean>\n /** The depth at which aim guard is active (null when not guarding) */\n guardedDepthRef: React.RefObject<number | null>\n}\n\n/**\n * Parameters for the useListboxItem hook.\n */\nexport interface UseListboxItemParams {\n /**\n * Explicit unique identifier for this item in the store.\n * Takes highest priority for item registration.\n * Used by data-first APIs to ensure consistent IDs.\n */\n id?: string\n\n /**\n * Unique value for this item used as identifier and for filtering.\n * If not provided, will be inferred from textContent.\n * Used for registration when `id` is not provided.\n */\n value?: string\n\n /**\n * Additional keywords to match against when filtering.\n * Useful for aliases or synonyms.\n */\n keywords?: string[]\n\n /**\n * Whether this item is disabled.\n * Disabled items are not selectable and are skipped during keyboard navigation.\n */\n disabled?: boolean\n\n /**\n * Whether this item can be activated via Enter or click.\n * Non-activatable items remain highlightable.\n * @default true\n */\n activatable?: boolean\n\n /**\n * Whether to force render this item regardless of filter results.\n * @default false\n */\n forceMount?: boolean\n\n /**\n * Keyboard shortcut to trigger this item.\n * When the menu is focused and the user presses this key, the item will be selected.\n * Should be a single character (e.g., \"1\", \"a\", etc.).\n */\n shortcut?: string\n\n /**\n * Forces this row's relative order during score-based sorting.\n * Lower values appear earlier.\n * @default 0\n */\n forceOrder?: number\n\n /**\n * Overrides this row's computed fuzzy-match score.\n * Useful for pinning or manually ranking rows in score-based views.\n */\n forceScore?: number\n\n /**\n * Whether this item is a submenu trigger (for store registration).\n * @default false\n */\n isSubmenuTrigger?: boolean\n\n /**\n * Callback when this item is selected (via click or Enter key).\n * For simple items, pass this directly. For checkbox/radio items,\n * use registerSelect() to register a dynamic handler.\n */\n onSelect?: () => void\n\n /**\n * Whether selecting this item should close the menu.\n * @default true\n */\n closeOnClick?: boolean\n\n /**\n * Callback invoked after selection occurs (via click).\n * Called with the item's ID. The consumer handles any\n * post-selection behavior like closing menus.\n */\n onAfterSelect?: (itemId: string) => void\n\n /**\n * Children (used for text content inference when value is not provided).\n */\n children?: React.ReactNode\n\n /**\n * Optional aim guard refs for popup menu navigation.\n * When provided, pointer move events will respect the aim guard.\n */\n aimGuard?: AimGuardRefs\n}\n\n/**\n * Return value from the useListboxItem hook.\n */\nexport interface UseListboxItemReturn {\n /** Unique ID for this item (DOM ID for aria-activedescendant) */\n id: string\n\n /**\n * Store identifier for this item.\n * Use this when calling store methods like setHighlightedId, registerSubmenuOpen, etc.\n * This is the `value` prop (or inferred from textContent).\n */\n storeId: string\n\n /** Ref to attach to the item element */\n ref: React.RefObject<HTMLDivElement | null>\n\n /** Callback ref that tracks the mounted row element for positional attributes. Merge into the rendered element's ref. */\n rowRef: (element: HTMLElement | null) => void\n\n /** Positional state among visible rows (all false in virtualized mode). */\n positional: {\n first: boolean\n last: boolean\n firstInGroup: boolean\n lastInGroup: boolean\n }\n\n /** Whether item is currently highlighted */\n isHighlighted: boolean\n\n /** Whether item should be rendered (passes filter) */\n isVisible: boolean\n\n /** Context value to provide to children via ItemContext.Provider */\n contextValue: ItemContextValue\n\n /**\n * Event handlers to spread on the element.\n * These handle click, pointer move, and pointer down events.\n */\n handlers: {\n onClick: React.MouseEventHandler<HTMLDivElement>\n onPointerMove: React.PointerEventHandler<HTMLDivElement>\n onPointerDown: React.PointerEventHandler<HTMLDivElement>\n }\n\n /**\n * Register a custom onSelect handler.\n * This is useful for checkbox/radio items where the select behavior\n * needs to be customized (e.g., toggle checked state).\n * Returns an unregister function.\n */\n registerSelect: (handler: (() => void) | undefined) => () => void\n}\n\n/**\n * Hook that provides all shared logic for navigatable/highlightable listbox items.\n *\n * This hook handles:\n * - Item registration with the listbox store\n * - Highlight state management (keyboard and pointer)\n * - Filter/search visibility\n * - Scroll into view on keyboard navigation\n * - Click, pointer move, and pointer down event handlers\n * - Optional aim guard integration (for submenu navigation)\n *\n * @example\n * ```tsx\n * function CustomItem(props) {\n * const item = useListboxItem({\n * value: props.value,\n * disabled: props.disabled,\n * onSelect: props.onSelect,\n * })\n *\n * if (!item.isVisible) return null\n *\n * return (\n * <ItemContext.Provider value={item.contextValue}>\n * <div\n * ref={item.ref}\n * {...item.handlers}\n * data-highlighted={item.isHighlighted || undefined}\n * >\n * {props.children}\n * </div>\n * </ItemContext.Provider>\n * )\n * }\n * ```\n */\nexport function useListboxItem(\n params: UseListboxItemParams,\n): UseListboxItemReturn {\n const {\n id: idProp,\n value: valueProp,\n keywords,\n disabled = false,\n activatable = true,\n forceMount = false,\n shortcut,\n forceOrder,\n forceScore,\n isSubmenuTrigger = false,\n onSelect,\n closeOnClick = true,\n onAfterSelect,\n children,\n aimGuard,\n } = params\n\n const { store } = useSurfaceContext()\n const groupContext = useGroupContext()\n const { depth } = useListboxContext()\n\n const ref = React.useRef<HTMLDivElement>(null)\n\n // Positional row registry: stable per-instance row id + mounted element\n const rowId = React.useId()\n const [rowElement, setRowElement] = React.useState<HTMLElement | null>(null)\n\n React.useLayoutEffect(() => {\n if (!rowElement) return undefined\n return store.registerRow(rowId, rowElement, {\n kind: 'item',\n groupId: groupContext?.groupId,\n })\n }, [rowElement, rowId, groupContext?.groupId, store])\n\n // Infer value from textContent if not provided\n const [inferredValue, setInferredValue] = React.useState<string>('')\n\n // biome-ignore lint/correctness/useExhaustiveDependencies(children): children is an intentional trigger dep — re-infer the value from textContent when content changes\n React.useLayoutEffect(() => {\n if (idProp === undefined && valueProp === undefined && ref.current) {\n const textContent = ref.current.textContent?.trim() ?? ''\n setInferredValue(textContent)\n }\n }, [idProp, valueProp, children])\n\n // Registration ID priority: id prop > value prop > textContent inference\n // This ensures data-first APIs can provide explicit IDs that match their internal tracking\n // Note: valueProp is normalized (trimmed) to match cmdk's behavior\n const registrationId = idProp ?? (normalizeValue(valueProp) || inferredValue)\n\n // Generate a stable ID for DOM id attribute (aria-activedescendant, etc.)\n // When id prop is provided (data-first APIs), use it directly for DOM ID\n // This ensures aria-activedescendant works correctly with composite IDs\n const generatedDomId = React.useId()\n const domId = idProp ?? `item-${generatedDomId}`\n\n // Stabilize keywords to prevent infinite loops when passed as inline arrays\n // We use JSON.stringify to compare by value rather than reference\n // Keywords are also normalized (trimmed) to match cmdk's behavior\n const normalizedKeywords = keywords\n ?.map((k) => normalizeValue(k))\n .filter(Boolean)\n const keywordsKey = normalizedKeywords\n ? JSON.stringify(normalizedKeywords)\n : undefined\n\n // Register item with store (using registrationId as the unique identifier)\n // biome-ignore lint/correctness/useExhaustiveDependencies: keywordsKey is a stable by-value stand-in for normalizedKeywords — depending on the array itself (new identity every render) causes an infinite register/recompute loop\n React.useEffect(() => {\n if (!registrationId && !forceMount) return\n\n const unregister = store.registerItem(registrationId, {\n value: registrationId,\n keywords: normalizedKeywords,\n groupId: groupContext?.groupId,\n disabled,\n activatable,\n isSubmenuTrigger,\n shortcut,\n forceOrder,\n forceScore,\n closeOnClick,\n })\n\n return unregister\n }, [\n registrationId,\n keywordsKey,\n groupContext?.groupId,\n disabled,\n activatable,\n isSubmenuTrigger,\n shortcut,\n forceOrder,\n forceScore,\n closeOnClick,\n store,\n forceMount,\n ])\n\n // Register DOM ref with store for scroll behavior\n React.useEffect(() => {\n if (!registrationId) return\n return store.registerItemRef(registrationId, ref)\n }, [registrationId, store])\n\n // Register for row width measurement if enabled\n const rowWidthContext = useMaybeRowWidthContext()\n\n React.useLayoutEffect(() => {\n if (rowWidthContext && ref.current && registrationId) {\n rowWidthContext.queueMeasurement(ref.current, registrationId)\n }\n }, [rowWidthContext, registrationId])\n\n // Register onSelect handler if provided directly\n React.useEffect(() => {\n if (!onSelect || !registrationId) return\n return store.registerItemSelect(registrationId, onSelect)\n }, [registrationId, onSelect, store])\n\n // Use selectors to get derived state (using registrationId as identifier)\n const normalizedSearch = store.useState('normalizedSearch')\n const isHighlighted = store.useState('isHighlighted', registrationId)\n const isFirstRow = store.useState('isFirstRow', rowId)\n const isLastRow = store.useState('isLastRow', rowId)\n const isFirstInGroup = store.useState('isFirstInGroup', rowId)\n const isLastInGroup = store.useState('isLastInGroup', rowId)\n const score = store.useState('getItemScore', registrationId)\n\n // Check if filtering is disabled (consumer handles filtering externally)\n const filterDisabled = store.isFilterDisabled()\n\n // Determine visibility based on filter score\n // When filterDisabled, consumer handles filtering so all items are visible\n const hasSearch = normalizedSearch.length > 0\n const isVisible = forceMount || filterDisabled || !hasSearch || score > 0\n\n // Note: Scroll behavior is now handled by the store's setHighlightedId method.\n // It uses the registered DOM refs to call scrollIntoView when the element exists,\n // or falls back to onHighlightChange for virtualizer sync.\n\n // Event handlers\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (event.defaultPrevented) return\n if (disabled) return\n if (activatable === false) return\n if (!registrationId) return\n\n event.preventDefault()\n\n // Call the registered onSelect handler via store\n const registeredHandler = store.context.itemSelects.get(registrationId)\n registeredHandler?.()\n\n // Notify consumer that selection occurred (for closing menus, etc.)\n onAfterSelect?.(registrationId)\n },\n [disabled, activatable, store, registrationId, onAfterSelect],\n )\n\n const handlePointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault()\n },\n [],\n )\n\n const handlePointerMove = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.defaultPrevented) return\n if (disabled) return\n if (!registrationId) return\n\n // Don't highlight if aim guard is active at this depth (user is moving toward submenu)\n // Only block highlighting in the same menu where the trigger is located\n if (aimGuard) {\n const { aimGuardActiveRef, guardedDepthRef } = aimGuard\n if (aimGuardActiveRef.current && guardedDepthRef.current === depth)\n return\n }\n\n // Check if pointer has actually moved - prevents phantom highlights when\n // content shifts under a stationary pointer (e.g., search results changing)\n if (!store.shouldAllowPointerHighlight(event.clientX, event.clientY)) {\n return\n }\n\n // Highlight on hover (using registrationId as identifier)\n store.setHighlightedId(registrationId)\n },\n [disabled, aimGuard, depth, store, registrationId],\n )\n\n // Context value for child components\n const contextValue: ItemContextValue = React.useMemo(\n () => ({\n id: domId,\n highlighted: isHighlighted,\n disabled,\n shortcut,\n }),\n [domId, isHighlighted, disabled, shortcut],\n )\n\n // Register a custom select handler (for checkbox/radio items)\n const registerSelect = React.useCallback(\n (handler: (() => void) | undefined) => {\n if (!registrationId) return () => {}\n return store.registerItemSelect(registrationId, handler)\n },\n [store, registrationId],\n )\n\n const handlers = React.useMemo(\n () => ({\n onClick: handleClick,\n onPointerMove: handlePointerMove,\n onPointerDown: handlePointerDown,\n }),\n [handleClick, handlePointerMove, handlePointerDown],\n )\n\n const contextPositional = groupContext?.positional\n const positional = React.useMemo(\n () => ({\n first: contextPositional?.first ?? isFirstRow,\n last: contextPositional?.last ?? isLastRow,\n firstInGroup: contextPositional?.firstInGroup ?? isFirstInGroup,\n lastInGroup: contextPositional?.lastInGroup ?? isLastInGroup,\n }),\n [contextPositional, isFirstRow, isLastRow, isFirstInGroup, isLastInGroup],\n )\n\n return {\n id: domId,\n storeId: registrationId,\n ref,\n rowRef: setRowElement,\n positional,\n isHighlighted,\n isVisible,\n contextValue,\n handlers,\n registerSelect,\n }\n}\n","/**\n * Normalizes a value string for use in filtering and identification.\n * Trims leading/trailing whitespace to match cmdk's behavior.\n *\n * @param value - The value to normalize\n * @returns The trimmed value, or empty string if value is nullish\n */\nexport function normalizeValue(value: string | undefined | null): string {\n return value?.trim() ?? ''\n}\n\n/**\n * Remove diacritics/accents from a string so unaccented queries match accented\n * content (e.g. \"cafe\" matches \"café\", \"municao\" matches \"munição\").\n *\n * Uses Unicode NFD decomposition and strips combining marks. Characters that\n * do not decompose into a base letter plus a combining mark (e.g. \"ø\", \"ł\")\n * are intentionally left unchanged.\n *\n * @param value - The value to fold\n * @returns The value with combining diacritical marks removed\n */\nexport function deburr(value: string): string {\n return value.normalize('NFD').replace(/\\p{Diacritic}/gu, '')\n}\n\n/**\n * Converts a value string to a URL-safe slug for use in IDs.\n * - Trims whitespace\n * - Converts to lowercase\n * - Replaces spaces with hyphens\n * - Removes non-alphanumeric characters (except hyphens)\n * - Collapses multiple hyphens into one\n * - Removes leading/trailing hyphens\n *\n * @example\n * slugify(\"User Settings\") // \"user-settings\"\n * slugify(\" Hello World! \") // \"hello-world\"\n * slugify(\"Café & Co.\") // \"caf-co\"\n *\n * @param value - The value to slugify\n * @returns The slugified value, or empty string if value is nullish\n */\nexport function slugify(value: string | undefined | null): string {\n if (!value) return ''\n\n return (\n value\n .trim()\n .toLowerCase()\n // Replace spaces with hyphens\n .replace(/\\s+/g, '-')\n // Remove non-alphanumeric characters (except hyphens)\n .replace(/[^a-z0-9-]/g, '')\n // Collapse multiple hyphens into one\n .replace(/-+/g, '-')\n // Remove leading/trailing hyphens\n .replace(/^-|-$/g, '')\n )\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/ui/ui/packages/react/dist/chunk-XMZZ62VJ.cjs","../src/internal/listbox/contexts/group-context.ts","../src/internal/listbox/contexts/item-context.ts","../src/internal/listbox/contexts/listbox-context.ts","../src/internal/listbox/contexts/row-width-context.ts","../src/internal/listbox/contexts/surface-context.ts","../src/internal/listbox/hooks/use-listbox-item.ts","../src/internal/listbox/utils/normalize.ts"],"names":["GroupContext","useGroupContext","ItemContext","useItemContext","context","useMaybeItemContext","ListboxContext","useListboxContext","useMaybeListboxContext","RowWidthContext","useRowWidthContext","useMaybeRowWidthContext","SurfaceContext","useSurfaceContext","useMaybeSurfaceContext","normalizeValue","value","deburr","slugify","useListboxItem","params","idProp","valueProp","keywords","disabled","activatable","forceMount","shortcut","forceOrder","forceScore","isSubmenuTrigger","onSelect","closeOnClick","onAfterSelect","children","aimGuard","store","groupContext","depth","ref","rowId","rowElement","setRowElement","inferredValue","setInferredValue","textContent","registrationId","generatedDomId","domId"],"mappings":"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","file":"/home/runner/work/ui/ui/packages/react/dist/chunk-XMZZ62VJ.cjs","sourcesContent":[null,"'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Group Context (for items to know their parent group)\n// ============================================================================\n\nexport interface GroupPositional {\n first?: boolean\n last?: boolean\n firstInGroup?: boolean\n lastInGroup?: boolean\n firstGroup?: boolean\n lastGroup?: boolean\n}\n\nexport interface GroupContextValue {\n groupId?: string\n positional?: GroupPositional\n}\n\nconst GroupContext = React.createContext<GroupContextValue | null>(null)\n\nexport function useGroupContext(): GroupContextValue | null {\n return React.useContext(GroupContext)\n}\n\nexport { GroupContext }\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Item Context (for child components like indicators to access item state)\n// ============================================================================\n\nexport interface ItemContextValue {\n /** Unique ID for this item (for DOM id attribute) */\n id: string\n /** Whether the item is highlighted */\n highlighted: boolean\n /** Whether the item is disabled */\n disabled: boolean\n /** Keyboard shortcut for this item */\n shortcut?: string\n}\n\nconst ItemContext = React.createContext<ItemContextValue | null>(null)\n\nexport function useItemContext(): ItemContextValue {\n const context = React.useContext(ItemContext)\n if (!context) {\n throw new Error('Item child components must be used within an Item')\n }\n return context\n}\n\nexport function useMaybeItemContext(): ItemContextValue | null {\n return React.useContext(ItemContext)\n}\n\nexport { ItemContext }\n","'use client'\n\nimport * as React from 'react'\nimport type { HighlightChangeEventDetails } from '../../popup-menu/events.js'\nimport type { ListboxStore, VirtualItem } from '../store/ListboxStore.js'\n\n/**\n * Virtualization configuration passed from Root/Submenu to Surface.\n */\nexport interface VirtualizationConfig {\n /** Whether virtualization mode is enabled */\n virtualized: boolean\n /** Pre-registered items for virtualization */\n items: VirtualItem[]\n /**\n * Callback when highlighted item changes (for scroll sync).\n * The third parameter contains event details including the reason for the change.\n */\n onHighlightChange?: (\n id: string | null,\n index: number,\n eventDetails: HighlightChangeEventDetails,\n ) => void\n}\n\nexport interface ListboxContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Nesting depth: 0 = root menu, 1+ = submenu */\n depth: number\n /** Close the entire menu tree (deepest submenu to root, sequentially) */\n closeAll: () => void\n /** Register a surface (submenu) for closeAll tracking. Returns unregister function. */\n registerSurface: (\n depth: number,\n setOpen: (open: boolean) => void,\n ) => () => void\n /** Virtualization configuration (if enabled) */\n virtualization?: VirtualizationConfig\n}\n\nconst ListboxContext = React.createContext<ListboxContextValue | null>(null)\n\nexport function useListboxContext(): ListboxContextValue {\n const context = React.useContext(ListboxContext)\n if (!context) {\n throw new Error('Listbox components must be used within a Listbox provider')\n }\n return context\n}\n\nexport function useMaybeListboxContext(): ListboxContextValue | null {\n return React.useContext(ListboxContext)\n}\n\nexport { ListboxContext }\n","'use client'\n\nimport * as React from 'react'\n\n/**\n * Context value for row width measurement.\n * Provided by List when `measureRowWidth` is enabled.\n */\nexport interface RowWidthContextValue {\n /**\n * Queue a row element for width measurement.\n * Call this when a row mounts or becomes visible.\n *\n * @param element - The DOM element to measure\n * @param id - Unique identifier for this row (used to avoid re-measuring)\n */\n queueMeasurement: (element: HTMLElement, id: string) => void\n}\n\n/**\n * Context for row width measurement.\n * Items use this to self-register for measurement.\n */\nexport const RowWidthContext = React.createContext<RowWidthContextValue | null>(\n null,\n)\n\nif (process.env.NODE_ENV !== 'production') {\n RowWidthContext.displayName = 'RowWidthContext'\n}\n\n/**\n * Hook to get the row width context.\n * Throws an error if used outside of a List with `measureRowWidth` enabled.\n */\nexport function useRowWidthContext(): RowWidthContextValue {\n const context = React.useContext(RowWidthContext)\n if (!context) {\n throw new Error(\n 'useRowWidthContext must be used within a List with measureRowWidth enabled',\n )\n }\n return context\n}\n\n/**\n * Hook to optionally get the row width context.\n * Returns null if not within a List with `measureRowWidth` enabled.\n * This is the preferred hook for items that should work both with and without measurement.\n */\nexport function useMaybeRowWidthContext(): RowWidthContextValue | null {\n return React.useContext(RowWidthContext)\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { ListboxStore } from '../store/ListboxStore.js'\n\n// Re-export types from the store for convenience\nexport type {\n FilterFn,\n ItemRegistration,\n} from '../store/ListboxStore.js'\n\n// ============================================================================\n// Surface Context\n// ============================================================================\n\nexport interface SurfaceContextValue {\n /** The Listbox store instance */\n store: ListboxStore\n /** Unique identifier for this surface */\n surfaceId: string\n}\n\nconst SurfaceContext = React.createContext<SurfaceContextValue | null>(null)\n\nexport function useSurfaceContext(): SurfaceContextValue {\n const context = React.useContext(SurfaceContext)\n if (!context) {\n throw new Error('Listbox components must be used within a Surface provider')\n }\n return context\n}\n\nexport function useMaybeSurfaceContext(): SurfaceContextValue | null {\n return React.useContext(SurfaceContext)\n}\n\nexport { SurfaceContext }\n","'use client'\n\nimport * as React from 'react'\nimport { useGroupContext } from '../contexts/group-context.js'\nimport type { ItemContextValue } from '../contexts/item-context.js'\nimport { useListboxContext } from '../contexts/listbox-context.js'\nimport { useMaybeRowWidthContext } from '../contexts/row-width-context.js'\nimport { useSurfaceContext } from '../contexts/surface-context.js'\nimport { normalizeValue } from '../utils/normalize.js'\n\n/**\n * Aim guard refs for submenu navigation.\n * Optional - only needed for popup menus with submenus.\n */\nexport interface AimGuardRefs {\n /** Whether aim guard is currently active */\n aimGuardActiveRef: React.RefObject<boolean>\n /** The depth at which aim guard is active (null when not guarding) */\n guardedDepthRef: React.RefObject<number | null>\n}\n\n/**\n * Parameters for the useListboxItem hook.\n */\nexport interface UseListboxItemParams {\n /**\n * Explicit unique identifier for this item in the store.\n * Takes highest priority for item registration.\n * Used by data-first APIs to ensure consistent IDs.\n */\n id?: string\n\n /**\n * Unique value for this item used as identifier and for filtering.\n * If not provided, will be inferred from textContent.\n * Used for registration when `id` is not provided.\n */\n value?: string\n\n /**\n * Additional keywords to match against when filtering.\n * Useful for aliases or synonyms.\n */\n keywords?: string[]\n\n /**\n * Whether this item is disabled.\n * Disabled items are not selectable and are skipped during keyboard navigation.\n */\n disabled?: boolean\n\n /**\n * Whether this item can be activated via Enter or click.\n * Non-activatable items remain highlightable.\n * @default true\n */\n activatable?: boolean\n\n /**\n * Whether to force render this item regardless of filter results.\n * @default false\n */\n forceMount?: boolean\n\n /**\n * Keyboard shortcut to trigger this item.\n * When the menu is focused and the user presses this key, the item will be selected.\n * Should be a single character (e.g., \"1\", \"a\", etc.).\n */\n shortcut?: string\n\n /**\n * Forces this row's relative order during score-based sorting.\n * Lower values appear earlier.\n * @default 0\n */\n forceOrder?: number\n\n /**\n * Overrides this row's computed fuzzy-match score.\n * Useful for pinning or manually ranking rows in score-based views.\n */\n forceScore?: number\n\n /**\n * Whether this item is a submenu trigger (for store registration).\n * @default false\n */\n isSubmenuTrigger?: boolean\n\n /**\n * Callback when this item is selected (via click or Enter key).\n * For simple items, pass this directly. For checkbox/radio items,\n * use registerSelect() to register a dynamic handler.\n */\n onSelect?: () => void\n\n /**\n * Whether selecting this item should close the menu.\n * @default true\n */\n closeOnClick?: boolean\n\n /**\n * Callback invoked after selection occurs (via click).\n * Called with the item's ID. The consumer handles any\n * post-selection behavior like closing menus.\n */\n onAfterSelect?: (itemId: string) => void\n\n /**\n * Children (used for text content inference when value is not provided).\n */\n children?: React.ReactNode\n\n /**\n * Optional aim guard refs for popup menu navigation.\n * When provided, pointer move events will respect the aim guard.\n */\n aimGuard?: AimGuardRefs\n}\n\n/**\n * Return value from the useListboxItem hook.\n */\nexport interface UseListboxItemReturn {\n /** Unique ID for this item (DOM ID for aria-activedescendant) */\n id: string\n\n /**\n * Store identifier for this item.\n * Use this when calling store methods like setHighlightedId, registerSubmenuOpen, etc.\n * This is the `value` prop (or inferred from textContent).\n */\n storeId: string\n\n /** Ref to attach to the item element */\n ref: React.RefObject<HTMLDivElement | null>\n\n /** Callback ref that tracks the mounted row element for positional attributes. Merge into the rendered element's ref. */\n rowRef: (element: HTMLElement | null) => void\n\n /** Positional state among visible rows (all false in virtualized mode). */\n positional: {\n first: boolean\n last: boolean\n firstInGroup: boolean\n lastInGroup: boolean\n }\n\n /** Whether item is currently highlighted */\n isHighlighted: boolean\n\n /** Whether item should be rendered (passes filter) */\n isVisible: boolean\n\n /** Context value to provide to children via ItemContext.Provider */\n contextValue: ItemContextValue\n\n /**\n * Event handlers to spread on the element.\n * These handle click, pointer move, and pointer down events.\n */\n handlers: {\n onClick: React.MouseEventHandler<HTMLDivElement>\n onPointerMove: React.PointerEventHandler<HTMLDivElement>\n onPointerDown: React.PointerEventHandler<HTMLDivElement>\n }\n\n /**\n * Register a custom onSelect handler.\n * This is useful for checkbox/radio items where the select behavior\n * needs to be customized (e.g., toggle checked state).\n * Returns an unregister function.\n */\n registerSelect: (handler: (() => void) | undefined) => () => void\n}\n\n/**\n * Hook that provides all shared logic for navigatable/highlightable listbox items.\n *\n * This hook handles:\n * - Item registration with the listbox store\n * - Highlight state management (keyboard and pointer)\n * - Filter/search visibility\n * - Scroll into view on keyboard navigation\n * - Click, pointer move, and pointer down event handlers\n * - Optional aim guard integration (for submenu navigation)\n *\n * @example\n * ```tsx\n * function CustomItem(props) {\n * const item = useListboxItem({\n * value: props.value,\n * disabled: props.disabled,\n * onSelect: props.onSelect,\n * })\n *\n * if (!item.isVisible) return null\n *\n * return (\n * <ItemContext.Provider value={item.contextValue}>\n * <div\n * ref={item.ref}\n * {...item.handlers}\n * data-highlighted={item.isHighlighted || undefined}\n * >\n * {props.children}\n * </div>\n * </ItemContext.Provider>\n * )\n * }\n * ```\n */\nexport function useListboxItem(\n params: UseListboxItemParams,\n): UseListboxItemReturn {\n const {\n id: idProp,\n value: valueProp,\n keywords,\n disabled = false,\n activatable = true,\n forceMount = false,\n shortcut,\n forceOrder,\n forceScore,\n isSubmenuTrigger = false,\n onSelect,\n closeOnClick = true,\n onAfterSelect,\n children,\n aimGuard,\n } = params\n\n const { store } = useSurfaceContext()\n const groupContext = useGroupContext()\n const { depth } = useListboxContext()\n\n const ref = React.useRef<HTMLDivElement>(null)\n\n // Positional row registry: stable per-instance row id + mounted element\n const rowId = React.useId()\n const [rowElement, setRowElement] = React.useState<HTMLElement | null>(null)\n\n React.useLayoutEffect(() => {\n if (!rowElement) return undefined\n return store.registerRow(rowId, rowElement, {\n kind: 'item',\n groupId: groupContext?.groupId,\n })\n }, [rowElement, rowId, groupContext?.groupId, store])\n\n // Infer value from textContent if not provided\n const [inferredValue, setInferredValue] = React.useState<string>('')\n\n // biome-ignore lint/correctness/useExhaustiveDependencies(children): children is an intentional trigger dep — re-infer the value from textContent when content changes\n React.useLayoutEffect(() => {\n if (idProp === undefined && valueProp === undefined && ref.current) {\n const textContent = ref.current.textContent?.trim() ?? ''\n setInferredValue(textContent)\n }\n }, [idProp, valueProp, children])\n\n // Registration ID priority: id prop > value prop > textContent inference\n // This ensures data-first APIs can provide explicit IDs that match their internal tracking\n // Note: valueProp is normalized (trimmed) to match cmdk's behavior\n const registrationId = idProp ?? (normalizeValue(valueProp) || inferredValue)\n\n // Generate a stable ID for DOM id attribute (aria-activedescendant, etc.)\n // When id prop is provided (data-first APIs), use it directly for DOM ID\n // This ensures aria-activedescendant works correctly with composite IDs\n const generatedDomId = React.useId()\n const domId = idProp ?? `item-${generatedDomId}`\n\n // Stabilize keywords to prevent infinite loops when passed as inline arrays\n // We use JSON.stringify to compare by value rather than reference\n // Keywords are also normalized (trimmed) to match cmdk's behavior\n const normalizedKeywords = keywords\n ?.map((k) => normalizeValue(k))\n .filter(Boolean)\n const keywordsKey = normalizedKeywords\n ? JSON.stringify(normalizedKeywords)\n : undefined\n\n // Register item with store (using registrationId as the unique identifier)\n // biome-ignore lint/correctness/useExhaustiveDependencies: keywordsKey is a stable by-value stand-in for normalizedKeywords — depending on the array itself (new identity every render) causes an infinite register/recompute loop\n React.useEffect(() => {\n if (!registrationId && !forceMount) return\n\n const unregister = store.registerItem(registrationId, {\n value: registrationId,\n keywords: normalizedKeywords,\n groupId: groupContext?.groupId,\n disabled,\n activatable,\n isSubmenuTrigger,\n shortcut,\n forceOrder,\n forceScore,\n closeOnClick,\n })\n\n return unregister\n }, [\n registrationId,\n keywordsKey,\n groupContext?.groupId,\n disabled,\n activatable,\n isSubmenuTrigger,\n shortcut,\n forceOrder,\n forceScore,\n closeOnClick,\n store,\n forceMount,\n ])\n\n // Register DOM ref with store for scroll behavior\n React.useEffect(() => {\n if (!registrationId) return\n return store.registerItemRef(registrationId, ref)\n }, [registrationId, store])\n\n // Register for row width measurement if enabled\n const rowWidthContext = useMaybeRowWidthContext()\n\n React.useLayoutEffect(() => {\n if (rowWidthContext && ref.current && registrationId) {\n rowWidthContext.queueMeasurement(ref.current, registrationId)\n }\n }, [rowWidthContext, registrationId])\n\n // Register onSelect handler if provided directly\n React.useEffect(() => {\n if (!onSelect || !registrationId) return\n return store.registerItemSelect(registrationId, onSelect)\n }, [registrationId, onSelect, store])\n\n // Use selectors to get derived state (using registrationId as identifier)\n const normalizedSearch = store.useState('normalizedSearch')\n const isHighlighted = store.useState('isHighlighted', registrationId)\n const isFirstRow = store.useState('isFirstRow', rowId)\n const isLastRow = store.useState('isLastRow', rowId)\n const isFirstInGroup = store.useState('isFirstInGroup', rowId)\n const isLastInGroup = store.useState('isLastInGroup', rowId)\n const score = store.useState('getItemScore', registrationId)\n\n // Check if filtering is disabled (consumer handles filtering externally)\n const filterDisabled = store.isFilterDisabled()\n\n // Determine visibility based on filter score\n // When filterDisabled, consumer handles filtering so all items are visible\n const hasSearch = normalizedSearch.length > 0\n const isVisible = forceMount || filterDisabled || !hasSearch || score > 0\n\n // Note: Scroll behavior is now handled by the store's setHighlightedId method.\n // It uses the registered DOM refs to call scrollIntoView when the element exists,\n // or falls back to onHighlightChange for virtualizer sync.\n\n // Event handlers\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (event.defaultPrevented) return\n if (disabled) return\n if (activatable === false) return\n if (!registrationId) return\n\n event.preventDefault()\n\n // Call the registered onSelect handler via store\n const registeredHandler = store.context.itemSelects.get(registrationId)\n registeredHandler?.()\n\n // Notify consumer that selection occurred (for closing menus, etc.)\n onAfterSelect?.(registrationId)\n },\n [disabled, activatable, store, registrationId, onAfterSelect],\n )\n\n const handlePointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault()\n },\n [],\n )\n\n const handlePointerMove = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.defaultPrevented) return\n if (disabled) return\n if (!registrationId) return\n\n // Don't highlight if aim guard is active at this depth (user is moving toward submenu)\n // Only block highlighting in the same menu where the trigger is located\n if (aimGuard) {\n const { aimGuardActiveRef, guardedDepthRef } = aimGuard\n if (aimGuardActiveRef.current && guardedDepthRef.current === depth)\n return\n }\n\n // Check if pointer has actually moved - prevents phantom highlights when\n // content shifts under a stationary pointer (e.g., search results changing)\n if (!store.shouldAllowPointerHighlight(event.clientX, event.clientY)) {\n return\n }\n\n // Highlight on hover (using registrationId as identifier)\n store.setHighlightedId(registrationId)\n },\n [disabled, aimGuard, depth, store, registrationId],\n )\n\n // Context value for child components\n const contextValue: ItemContextValue = React.useMemo(\n () => ({\n id: domId,\n highlighted: isHighlighted,\n disabled,\n shortcut,\n }),\n [domId, isHighlighted, disabled, shortcut],\n )\n\n // Register a custom select handler (for checkbox/radio items)\n const registerSelect = React.useCallback(\n (handler: (() => void) | undefined) => {\n if (!registrationId) return () => {}\n return store.registerItemSelect(registrationId, handler)\n },\n [store, registrationId],\n )\n\n const handlers = React.useMemo(\n () => ({\n onClick: handleClick,\n onPointerMove: handlePointerMove,\n onPointerDown: handlePointerDown,\n }),\n [handleClick, handlePointerMove, handlePointerDown],\n )\n\n const contextPositional = groupContext?.positional\n const positional = React.useMemo(\n () => ({\n first: contextPositional?.first ?? isFirstRow,\n last: contextPositional?.last ?? isLastRow,\n firstInGroup: contextPositional?.firstInGroup ?? isFirstInGroup,\n lastInGroup: contextPositional?.lastInGroup ?? isLastInGroup,\n }),\n [contextPositional, isFirstRow, isLastRow, isFirstInGroup, isLastInGroup],\n )\n\n return {\n id: domId,\n storeId: registrationId,\n ref,\n rowRef: setRowElement,\n positional,\n isHighlighted,\n isVisible,\n contextValue,\n handlers,\n registerSelect,\n }\n}\n","/**\n * Normalizes a value string for use in filtering and identification.\n * Trims leading/trailing whitespace to match cmdk's behavior.\n *\n * @param value - The value to normalize\n * @returns The trimmed value, or empty string if value is nullish\n */\nexport function normalizeValue(value: string | undefined | null): string {\n return value?.trim() ?? ''\n}\n\n/**\n * Remove diacritics/accents from a string so unaccented queries match accented\n * content (e.g. \"cafe\" matches \"café\", \"municao\" matches \"munição\").\n *\n * Uses Unicode NFD decomposition and strips combining marks. Characters that\n * do not decompose into a base letter plus a combining mark (e.g. \"ø\", \"ł\")\n * are intentionally left unchanged.\n *\n * @param value - The value to fold\n * @returns The value with combining diacritical marks removed\n */\nexport function deburr(value: string): string {\n return value.normalize('NFD').replace(/\\p{Diacritic}/gu, '')\n}\n\n/**\n * Converts a value string to a URL-safe slug for use in IDs.\n * - Trims whitespace\n * - Converts to lowercase\n * - Replaces spaces with hyphens\n * - Removes non-alphanumeric characters (except hyphens)\n * - Collapses multiple hyphens into one\n * - Removes leading/trailing hyphens\n *\n * @example\n * slugify(\"User Settings\") // \"user-settings\"\n * slugify(\" Hello World! \") // \"hello-world\"\n * slugify(\"Café & Co.\") // \"caf-co\"\n *\n * @param value - The value to slugify\n * @returns The slugified value, or empty string if value is nullish\n */\nexport function slugify(value: string | undefined | null): string {\n if (!value) return ''\n\n return (\n value\n .trim()\n .toLowerCase()\n // Replace spaces with hyphens\n .replace(/\\s+/g, '-')\n // Remove non-alphanumeric characters (except hyphens)\n .replace(/[^a-z0-9-]/g, '')\n // Collapse multiple hyphens into one\n .replace(/-+/g, '-')\n // Remove leading/trailing hyphens\n .replace(/^-|-$/g, '')\n )\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/combobox/index.cjs","../../src/combobox/index.parts.ts","../../src/combobox/clear/clear.tsx","../../src/combobox/clear/clear.data-attrs.ts","../../src/combobox/contexts/combobox-positioner-context.ts","../../src/combobox/input/input.tsx","../../src/combobox/input-wrapper/input-wrapper-context.ts","../../src/combobox/input/input.data-attrs.ts","../../src/combobox/input/use-combobox-display-value.ts"],"names":["index_parts_exports","__export","PopupMenuArrow","PopupMenuBackdrop","ComboboxClear","PopupMenuEmpty","PopupMenuGroup","PopupMenuGroupLabel","PopupMenuIcon","ComboboxInput","ComboboxInputWrapper","ComboboxItem","ComboboxItemIndicator","ComboboxItemLabel","PopupMenuList","PopupMenuPopup","PopupMenuPortal","ComboboxPositioner","ComboboxRoot","PopupMenuScrollDownArrow","PopupMenuScrollUpArrow","PopupMenuSeparator","ComboboxSurface","useComboboxPositionerContext","ComboboxClearDataAttributes","props","forwardedRef","keepMounted","disabledProp","render","className","style","onClick","onPointerDown","rest","comboboxContext","useComboboxContext","disabled","hasValue","handleClick","event","handlePointerDown","state","element","useRender","ComboboxPositionerContext","ComboboxInputWrapperContext","useIsInsideInputWrapper","ComboboxInputDataAttributes","useComboboxDisplayValue","params","open","isValueEmpty","getValueText","value","serializedValue","stringifyAsValue","registryText","itemsLabel","resolveLabelFromItems","resolvedLabel","resolveLabel","selectedLabel","texts","v","text"],"mappings":"AAAA,4/BAA0F,yDAA+P,yDAAmF,yDAA2C,ICAvdA,EAAAA,CAAA,CAAA,CAAA,CAAAC,iCAAAA,EAAAD,CAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAE,mBAAAA,CAAA,QAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAC,oBAAAA,CAAA,UAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,IAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,YAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,IAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,aAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,SAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,IAAA,CAAA,CAAA,CAAA,EAAAC,oBAAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,MAAA,CAAA,CAAA,CAAA,EAAAC,mBAAAA,CAAA,UAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,IAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,eAAA,CAAA,CAAA,CAAA,EAAAC,oBAAAA,CAAA,aAAA,CAAA,CAAA,CAAA,EAAAC,oBAAAA,CAAA,SAAA,CAAA,CAAA,CAAA,EAAAC,oBAAAA,CAAA,OAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAA,4BAAA,CAAA,CAAA,CAAA,EAAAC,EAAAA,CAAAA,CAAAA,CCEA,sDAA0B,mmBACH,ICAVC,EAAAA,CAA8B,CAKzC,IAAA,CAAM,wBACR,CAAA,CDyBO,IAAMpB,EAAAA,CAAsB,CAAA,CAAA,UAAA,CAGjC,QAAA,CAAuBqB,CAAAA,CAAOC,CAAAA,CAAc,CAC5C,GAAM,CACJ,WAAA,CAAAC,CAAAA,CAAc,CAAA,CAAA,CACd,QAAA,CAAUC,CAAAA,CACV,MAAA,CAAAC,CAAAA,CACA,SAAA,CAAAC,CAAAA,CACA,KAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,GAAGC,CACL,CAAA,CAAIT,CAAAA,CAEEU,CAAAA,CAAkBC,iCAAAA,CAAmB,CAErCC,CAAAA,kBAAWT,CAAAA,SAAgBO,CAAAA,CAAgB,UAAA,CAE3CG,CAAAA,CAAWH,CAAAA,CAAgB,QAAA,CAC7BA,CAAAA,CAAgB,MAAA,CAAO,MAAA,CAAS,CAAA,CAChCA,CAAAA,CAAgB,KAAA,GAAU,EAAA,CAExBI,CAAAA,CAAoB,CAAA,CAAA,WAAA,CACvBC,CAAAA,EAA+C,iBAC9CR,CAAAA,0BAAAA,CAAUQ,CAAK,GAAA,CACX,CAAAA,CAAAA,CAAM,gBAAA,EAAA,CAENL,CAAAA,CAAgB,QAAA,CAClBA,CAAAA,CAAgB,cAAA,CAAe,CAAC,CAAC,CAAA,CAEjCA,CAAAA,CAAgB,aAAA,CAAc,EAAE,CAAA,CAIlCA,CAAAA,CAAgB,kBAAA,CAAmB,EAAE,CAAA,CACvC,CAAA,CACA,CAACH,CAAAA,CAASG,CAAe,CAC3B,CAAA,CAGMM,CAAAA,CAA0B,CAAA,CAAA,WAAA,CAC7BD,CAAAA,EAAiD,CAChDA,CAAAA,CAAM,cAAA,CAAe,CAAA,iBACrBP,CAAAA,0BAAAA,CAAgBO,CAAK,GACvB,CAAA,CACA,CAACP,CAAa,CAChB,CAAA,CAEMS,CAAAA,CAAmC,CAAA,CAAA,OAAA,CACvC,CAAA,CAAA,EAAA,CAAO,CACL,QAAA,CAAAJ,CAAAA,CACA,QAAA,CAAAD,CACF,CAAA,CAAA,CACA,CAACC,CAAAA,CAAUD,CAAQ,CACrB,CAAA,CAEMM,CAAAA,CAAUC,kCAAAA,CACd,MAAA,CAAAf,CAAAA,CACA,GAAA,CAAKH,CAAAA,CACL,KAAA,CAAAgB,CAAAA,CACA,KAAA,CAAO,CACL,GAAGR,CAAAA,CACH,CAACV,EAAAA,CAA4B,IAAI,CAAA,CAAG,EAAA,CACpC,IAAA,CAAM,QAAA,CACN,QAAA,CAAU,CAAA,CAAA,CACV,YAAA,CAAc,iBAAA,CACd,QAAA,CAAUa,CAAAA,EAAY,CAACC,CAAAA,CACvB,SAAA,CAAAR,CAAAA,CACA,KAAA,CAAAC,CAAAA,CACA,OAAA,CAASQ,CAAAA,CACT,aAAA,CAAeE,CACjB,CAAA,CACA,OAAA,CAASd,CAAAA,EAAeW,CAAAA,CACxB,cAAA,CAAgB,QAClB,CAAC,CAAA,CAGD,MAAI,CAACX,CAAAA,EAAe,CAACW,CAAAA,CACZ,IAAA,CAGFK,CACT,CAAC,CAAA,CEnHD,IAkDME,EAAAA,CACE,EAAA,CAAA,aAAA,CAAqD,IAAI,CAAA,CAM1D,SAAStB,EAAAA,CAAAA,CAAsE,CACpF,OAAa,EAAA,CAAA,UAAA,CAAWsB,EAAyB,CACnD,CC3DA,ICIaC,EAAAA,CAAoC,EAAA,CAAA,aAAA,CAAuB,CAAA,CAAK,CAAA,CAKtE,SAASC,EAAAA,CAAAA,CAAmC,CACjD,OAAa,EAAA,CAAA,UAAA,CAAWD,EAA2B,CACrD,CCVO,IAAME,CAAAA,CAA8B,CAKzC,IAAA,CAAM,wBAAA,CAEN,IAAA,CAAM,WAAA,CAEN,MAAA,CAAQ,aAAA,CAER,QAAA,CAAU,eAAA,CAEV,WAAA,CAAa,kBACf,CAAA,CCfA,SAiCgBC,EAAAA,CACdC,CAAAA,CACsC,CACtC,GAAM,CAAE,eAAA,CAAAf,CAAAA,CAAiB,IAAA,CAAAgB,CAAK,CAAA,CAAID,CAAAA,CAG5BZ,CAAAA,CAAWH,CAAAA,CAAgB,QAAA,CAC7BA,CAAAA,CAAgB,MAAA,CAAO,MAAA,CAAS,CAAA,CAChC,CAACiB,iCAAAA,CAAajB,CAAgB,KAAK,CAAA,CAGjCkB,CAAAA,CAAqB,EAAA,CAAA,WAAA,CACxBC,CAAAA,EAAqC,CAEpC,IAAMC,CAAAA,CAAkBC,iCAAAA,CACtBF,CACAnB,CAAAA,CAAgB,iBAClB,CAAA,CAGMsB,CAAAA,CAAetB,CAAAA,CAAgB,gBAAA,CAAiB,GAAA,CAAIoB,CAAe,CAAA,CACzE,EAAA,CAAIE,CAAAA,GAAiB,KAAA,CAAA,CACnB,OAAOA,CAAAA,CAKT,IAAMC,CAAAA,CAAaC,iCAAAA,CACjBxB,CAAgB,KAAA,CAChBoB,CACF,CAAA,CACA,EAAA,CAAI,OAAOG,CAAAA,EAAe,QAAA,CACxB,OAAOA,CAAAA,CAIT,IAAME,CAAAA,CAAgBC,iCAAAA,CACpBP,CACAnB,CAAAA,CAAgB,iBAClB,CAAA,CAEA,EAAA,CAAIyB,CAAAA,EAAiBA,CAAAA,GAAkBL,CAAAA,CACrC,OAAOK,CAIX,CAAA,CACA,CACEzB,CAAAA,CAAgB,gBAAA,CAChBA,CAAAA,CAAgB,KAAA,CAChBA,CAAAA,CAAgB,iBAAA,CAChBA,CAAAA,CAAgB,iBAClB,CACF,CAAA,CAGM2B,CAAAA,CAAsB,EAAA,CAAA,OAAA,CAAQ,CAAA,CAAA,EAAM,CACxC,EAAA,CAAI,CAACxB,CAAAA,CACH,MAAO,EAAA,CAET,EAAA,CAAIH,CAAAA,CAAgB,QAAA,CAAU,CAE5B,IAAM4B,CAAAA,CAAQ5B,CAAAA,CAAgB,MAAA,CAC3B,GAAA,CAAK6B,CAAAA,EAAM,CACV,IAAMC,CAAAA,CAAOZ,CAAAA,CAAaW,CAAC,CAAA,CAC3B,OAAIC,CAAAA,GAAS,KAAA,CAAA,CAAkBA,CAAAA,CAG7BJ,iCAAAA,CAAaG,CAAG7B,CAAAA,CAAgB,iBAAiB,CAAA,EACjDqB,iCAAAA,CAAiBQ,CAAG7B,CAAAA,CAAgB,iBAAiB,CAEzD,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACjB,OAAI4B,CAAAA,CAAM,MAAA,EAAU,CAAA,CACXA,CAAAA,CAAM,IAAA,CAAK,IAAI,CAAA,CAEjB,CAAA,EAAA","file":"/Users/kianbazza/repos/bazzalabs/ui/packages/react/dist/combobox/index.cjs","sourcesContent":[null,"// ============================================================================\n// Combobox Parts\n// ============================================================================\n// Re-exports shared components from internal/popup-menu with Combobox-specific\n// Root, Input, Item, ItemLabel, and ItemIndicator components.\n\n// Re-export VirtualItem type from internal/listbox\nexport type { VirtualItem } from '../internal/listbox/index.js'\n\n// Re-export shared components from internal/popup-menu\nexport {\n PopupMenuArrow as Arrow,\n PopupMenuBackdrop as Backdrop,\n PopupMenuEmpty as Empty,\n // Structure\n PopupMenuGroup as Group,\n PopupMenuGroupLabel as GroupLabel,\n // Icon\n PopupMenuIcon as Icon,\n PopupMenuList as List,\n PopupMenuPopup as Popup,\n // Positioning & Container\n PopupMenuPortal as Portal,\n // Scroll indicators\n PopupMenuScrollDownArrow as ScrollDownArrow,\n PopupMenuScrollUpArrow as ScrollUpArrow,\n PopupMenuSeparator as Separator,\n} from '../internal/popup-menu/index.js'\nexport { ComboboxClear as Clear } from './clear/clear.js'\nexport { useComboboxPositionerContext } from './contexts/combobox-positioner-context.js'\nexport { ComboboxInput as Input } from './input/input.js'\nexport { ComboboxInputWrapper as InputWrapper } from './input-wrapper/input-wrapper.js'\nexport { ComboboxItem as Item } from './item/item.js'\nexport { ComboboxItemIndicator as ItemIndicator } from './item-indicator/item-indicator.js'\nexport { ComboboxItemLabel as ItemLabel } from './item-label/item-label.js'\nexport { ComboboxPositioner as Positioner } from './positioner/positioner.js'\n// Combobox-specific components\nexport { ComboboxRoot as Root } from './root/root.js'\nexport { ComboboxSurface as Surface } from './surface/surface.js'\n","'use client'\n\nimport { useRender } from '@base-ui/react/use-render'\nimport * as React from 'react'\nimport type { ComponentProps } from '../../utils/types.js'\nimport { useComboboxContext } from '../contexts/combobox-context.js'\nimport { ComboboxClearDataAttributes } from './clear.data-attrs.js'\n\nexport { ComboboxClearDataAttributes }\n\nexport interface ComboboxClearState extends Record<string, unknown> {\n /**\n * Whether the combobox has a value (clear button is actionable).\n */\n hasValue: boolean\n /**\n * Whether the combobox is disabled.\n */\n disabled: boolean\n}\n\nexport interface ComboboxClearProps\n extends ComponentProps<'button', ComboboxClear.State> {\n /**\n * Whether to render the button even when there's no value to clear.\n * @default false\n */\n keepMounted?: boolean\n}\n\n/**\n * A button that clears the selected value(s) when clicked.\n * Renders a `<button>` element.\n */\nexport const ComboboxClear = React.forwardRef<\n HTMLButtonElement,\n ComboboxClear.Props\n>(function ComboboxClear(props, forwardedRef) {\n const {\n keepMounted = false,\n disabled: disabledProp,\n render,\n className,\n style,\n onClick,\n onPointerDown,\n ...rest\n } = props\n\n const comboboxContext = useComboboxContext()\n\n const disabled = disabledProp ?? comboboxContext.disabled\n\n const hasValue = comboboxContext.multiple\n ? comboboxContext.values.length > 0\n : comboboxContext.value !== ''\n\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n if (event.defaultPrevented) return\n\n if (comboboxContext.multiple) {\n comboboxContext.onValuesChange([])\n } else {\n comboboxContext.onValueChange('')\n }\n\n // Also clear the input value\n comboboxContext.onInputValueChange('')\n },\n [onClick, comboboxContext],\n )\n\n // Prevent pointer down from stealing focus from the input\n const handlePointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n event.preventDefault()\n onPointerDown?.(event)\n },\n [onPointerDown],\n )\n\n const state: ComboboxClear.State = React.useMemo(\n () => ({\n hasValue,\n disabled,\n }),\n [hasValue, disabled],\n )\n\n const element = useRender({\n render,\n ref: forwardedRef,\n state,\n props: {\n ...rest,\n [ComboboxClearDataAttributes.slot]: '',\n type: 'button',\n tabIndex: -1, // Not tabbable - use keyboard shortcuts instead\n 'aria-label': 'Clear selection',\n disabled: disabled || !hasValue,\n className,\n style,\n onClick: handleClick,\n onPointerDown: handlePointerDown,\n },\n enabled: keepMounted || hasValue,\n defaultTagName: 'button',\n })\n\n // Don't render if no value and not keepMounted\n if (!keepMounted && !hasValue) {\n return null\n }\n\n return element\n})\n\nexport namespace ComboboxClear {\n export type State = ComboboxClearState\n export interface Props extends ComboboxClearProps {}\n}\n","/**\n * Data attributes for ComboboxClear component.\n */\nexport const ComboboxClearDataAttributes = {\n /**\n * Identifies the component part.\n * @type {'bazzaui-combobox-clear'}\n */\n slot: 'bazzaui-combobox-clear',\n} as const\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Types matching Base UI's positioning types\nexport type Side = 'top' | 'bottom' | 'left' | 'right'\nexport type Align = 'start' | 'center' | 'end'\n\n/**\n * Layout mode for the combobox popup.\n * - `'floating'` - Standard dropdown positioning below/above the input\n * - `'input-embedded'` - Popup wraps around the input (macOS-style)\n */\nexport type ComboboxLayout = 'floating' | 'input-embedded'\n\n/**\n * Context value for Combobox Positioner.\n * Provides alignment state for coordinating positioning behavior.\n */\nexport interface ComboboxPositionerContextValue {\n /**\n * The layout mode being used.\n * - `'floating'` - Standard dropdown positioning\n * - `'input-embedded'` - Popup wraps around the input\n */\n layout: ComboboxLayout\n\n /**\n * The side of the popup relative to the input.\n */\n side: Side\n\n /**\n * The alignment of the popup.\n */\n align: Align\n\n /**\n * Height of the input element in pixels.\n * Use this to add appropriate padding to the popup.\n */\n inputHeight: number\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComboboxPositionerContext =\n React.createContext<ComboboxPositionerContextValue | null>(null)\n\n/**\n * Hook to access the Combobox Positioner context.\n * Returns null if used outside a ComboboxPositioner.\n */\nexport function useComboboxPositionerContext(): ComboboxPositionerContextValue | null {\n return React.useContext(ComboboxPositionerContext)\n}\n\nexport { ComboboxPositionerContext }\n","'use client'\n\nimport { useRender } from '@base-ui/react/use-render'\nimport * as React from 'react'\nimport { useFocusOwner } from '../../internal/popup-menu/contexts/focus-owner-context.js'\nimport { usePopupMenuContext } from '../../internal/popup-menu/contexts/popup-menu-context.js'\nimport { resolveLabelFromItems } from '../../utils/items.js'\nimport type { ComponentProps } from '../../utils/types.js'\nimport { useComboboxContext } from '../contexts/combobox-context.js'\nimport { useIsInsideInputWrapper } from '../input-wrapper/input-wrapper-context.js'\nimport { ComboboxInputDataAttributes } from './input.data-attrs.js'\nimport { useComboboxDisplayValue } from './use-combobox-display-value.js'\nimport { useComboboxInputBehavior } from './use-combobox-input-behavior.js'\n\nexport { ComboboxInputDataAttributes }\n\nexport interface ComboboxInputState extends Record<string, unknown> {\n /**\n * Whether the combobox popup is open.\n */\n open: boolean\n /**\n * Whether the input is disabled.\n */\n disabled: boolean\n /**\n * Whether the input currently shows placeholder (no value selected).\n */\n placeholder: boolean\n}\n\n/**\n * Cursor behavior when the combobox popup opens.\n * - `'none'` - Don't move the cursor (cursor appears where clicked)\n * - `'end'` - Move cursor to the end of the input\n * - `'select-all'` - Move cursor to the end and select all text\n */\nexport type ComboboxInputCursorBehavior = 'none' | 'end' | 'select-all'\n\nexport interface ComboboxInputProps\n extends Omit<\n ComponentProps<'input', ComboboxInput.State>,\n 'value' | 'onChange' | 'type'\n > {\n /**\n * Placeholder text shown when no value is selected and input is empty.\n * Overrides the placeholder set on Combobox.Root.\n */\n placeholder?: string\n\n /**\n * Cursor behavior when the combobox popup opens.\n * - `'none'` - Don't move the cursor (cursor appears where clicked)\n * - `'end'` - Move cursor to the end of the input\n * - `'select-all'` - Move cursor to the end and select all text\n *\n * @default 'none'\n */\n cursorBehavior?: ComboboxInputCursorBehavior\n}\n\n/**\n * An input that acts as both the trigger and search field for the combobox.\n * Renders an `<input>` element with combobox ARIA semantics.\n */\nexport const ComboboxInput = React.forwardRef<\n HTMLInputElement,\n ComboboxInput.Props\n>(function ComboboxInput(props, forwardedRef) {\n const {\n placeholder: placeholderProp,\n disabled: disabledProp,\n cursorBehavior = 'none',\n render,\n className,\n style,\n onFocus,\n onBlur,\n onClick,\n onKeyDown,\n ...rest\n } = props\n\n const comboboxContext = useComboboxContext()\n const popupMenuContext = usePopupMenuContext()\n const focusOwnerStore = useFocusOwner()\n const isInsideInputWrapper = useIsInsideInputWrapper()\n\n const disabled =\n (disabledProp ?? comboboxContext.disabled) || popupMenuContext.disabled\n\n // A `null` item's label (looked up under the empty-string key) acts as the\n // placeholder, taking precedence over the Root placeholder but not an\n // explicit `placeholder` prop on the input.\n const nullItemLabel = resolveLabelFromItems(comboboxContext.items, '')\n const placeholder =\n placeholderProp ??\n (typeof nullItemLabel === 'string' ? nullItemLabel : undefined) ??\n comboboxContext.placeholder\n\n // Get open state\n const open = popupMenuContext.store.useState('open')\n\n // Use display value hook\n const { hasValue, displayValue, getValueText } = useComboboxDisplayValue({\n comboboxContext,\n open,\n })\n\n // Use input behavior hook\n const { handleChange, handleFocus, handleBlur, handleClick, handleKeyDown } =\n useComboboxInputBehavior({\n comboboxContext,\n store: popupMenuContext.store,\n focusOwnerStore,\n open,\n disabled,\n cursorBehavior,\n hasValue,\n getValueText,\n onFocus,\n onBlur,\n onClick,\n onKeyDown,\n })\n\n // Build data attributes\n const dataAttrs: Record<string, string> = {\n [ComboboxInputDataAttributes.slot]: '',\n }\n if (open) {\n dataAttrs[ComboboxInputDataAttributes.open] = ''\n } else {\n dataAttrs[ComboboxInputDataAttributes.closed] = ''\n }\n if (disabled) {\n dataAttrs[ComboboxInputDataAttributes.disabled] = ''\n }\n if (!hasValue) {\n dataAttrs[ComboboxInputDataAttributes.placeholder] = ''\n }\n // Add input-embedded data attribute when layout is input-embedded\n if (comboboxContext.layout === 'input-embedded') {\n dataAttrs['data-input-embedded'] = ''\n }\n\n // Register input element for positioning\n const mergedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n comboboxContext.setInputElement(node)\n if (typeof forwardedRef === 'function') {\n forwardedRef(node)\n } else if (forwardedRef) {\n forwardedRef.current = node\n }\n },\n [forwardedRef, comboboxContext],\n )\n\n const state: ComboboxInput.State = React.useMemo(\n () => ({\n open,\n disabled,\n placeholder: !hasValue,\n }),\n [open, disabled, hasValue],\n )\n\n // When input-embedded layout, apply styles to position input above the popup\n // Skip z-index if inside an InputWrapper (the wrapper handles z-index)\n const inputEmbeddedStyles: React.CSSProperties | undefined =\n comboboxContext.layout === 'input-embedded' && !isInsideInputWrapper\n ? { position: 'relative', zIndex: 1 }\n : undefined\n\n const element = useRender({\n render,\n ref: mergedRef,\n state,\n props: {\n ...rest,\n ...dataAttrs,\n type: 'text',\n role: 'combobox',\n 'aria-autocomplete': 'list',\n 'aria-expanded': open,\n 'aria-controls': comboboxContext.listId,\n 'aria-haspopup': 'listbox',\n autoComplete: 'off',\n autoCorrect: 'off',\n spellCheck: false,\n disabled,\n placeholder: !hasValue ? placeholder : undefined,\n className,\n style: { ...inputEmbeddedStyles, ...style },\n value: displayValue,\n onChange: handleChange,\n onFocus: handleFocus,\n onBlur: handleBlur,\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n },\n defaultTagName: 'input',\n })\n\n return element\n})\n\nexport namespace ComboboxInput {\n export interface Props extends ComboboxInputProps {}\n export type State = ComboboxInputState\n}\n","import * as React from 'react'\n\n/**\n * Context to indicate that children are inside an InputWrapper.\n * When true, Input should not apply its own z-index styles for input-embedded layout.\n */\nexport const ComboboxInputWrapperContext = React.createContext<boolean>(false)\n\n/**\n * Hook to check if component is inside a ComboboxInputWrapper.\n */\nexport function useIsInsideInputWrapper(): boolean {\n return React.useContext(ComboboxInputWrapperContext)\n}\n","/**\n * Data attributes for ComboboxInput component.\n */\nexport const ComboboxInputDataAttributes = {\n /**\n * Identifies the component part.\n * @type {'bazzaui-combobox-input'}\n */\n slot: 'bazzaui-combobox-input',\n /** Present when the combobox popup is open. */\n open: 'data-open',\n /** Present when the combobox popup is closed. */\n closed: 'data-closed',\n /** Present when the input is disabled. */\n disabled: 'data-disabled',\n /** Present when no value is selected (showing placeholder). */\n placeholder: 'data-placeholder',\n} as const\n","'use client'\n\nimport * as React from 'react'\nimport { resolveLabelFromItems } from '../../utils/items.js'\nimport {\n isValueEmpty,\n resolveLabel,\n stringifyAsValue,\n} from '../../utils/resolve-value-label.js'\nimport type { ComboboxContextValue } from '../contexts/combobox-context.js'\n\nexport interface UseComboboxDisplayValueParams<Value = unknown> {\n comboboxContext: ComboboxContextValue<Value>\n open: boolean\n}\n\nexport interface UseComboboxDisplayValueReturn<Value = unknown> {\n /** Whether a value is selected */\n hasValue: boolean\n /** The value to display in the input */\n displayValue: string\n /** The label of the selected value(s) */\n selectedLabel: string\n /** Get the display text for a value */\n getValueText: (value: Value) => string | undefined\n}\n\n/**\n * Hook to compute the display value for the combobox input.\n *\n * Handles:\n * - Determining if a value is selected (single or multi-select)\n * - Computing the display label for selected values\n * - Switching between selected label (closed) and input value (open)\n */\nexport function useComboboxDisplayValue<Value = unknown>(\n params: UseComboboxDisplayValueParams<Value>,\n): UseComboboxDisplayValueReturn<Value> {\n const { comboboxContext, open } = params\n\n // Determine if showing placeholder (no value selected)\n const hasValue = comboboxContext.multiple\n ? comboboxContext.values.length > 0\n : !isValueEmpty(comboboxContext.value)\n\n // Get the display text for selected value\n const getValueText = React.useCallback(\n (value: Value): string | undefined => {\n // Serialize for registry lookup\n const serializedValue = stringifyAsValue(\n value,\n comboboxContext.itemToStringValue,\n )\n\n // First try the registry (populated when items mount)\n const registryText = comboboxContext.itemTextRegistry.get(serializedValue)\n if (registryText !== undefined) {\n return registryText\n }\n\n // Fall back to the items prop (for initial render before popup opens).\n // The input can only display strings, so ignore non-string labels here.\n const itemsLabel = resolveLabelFromItems(\n comboboxContext.items,\n serializedValue,\n )\n if (typeof itemsLabel === 'string') {\n return itemsLabel\n }\n\n // Fall back to itemToStringLabel for object values\n const resolvedLabel = resolveLabel(\n value,\n comboboxContext.itemToStringLabel,\n )\n // Only return if it's different from the serialized value (meaning we got a real label)\n if (resolvedLabel && resolvedLabel !== serializedValue) {\n return resolvedLabel\n }\n\n return undefined\n },\n [\n comboboxContext.itemTextRegistry,\n comboboxContext.items,\n comboboxContext.itemToStringLabel,\n comboboxContext.itemToStringValue,\n ],\n )\n\n // Get the label for the selected value (used when closed or just opened)\n const selectedLabel = React.useMemo(() => {\n if (!hasValue) {\n return ''\n }\n if (comboboxContext.multiple) {\n // For multi-select, show comma-separated values or count\n const texts = comboboxContext.values\n .map((v) => {\n const text = getValueText(v)\n if (text !== undefined) return text\n // Fall back to resolved label or serialized value\n return (\n resolveLabel(v, comboboxContext.itemToStringLabel) ||\n stringifyAsValue(v, comboboxContext.itemToStringValue)\n )\n })\n .filter(Boolean)\n if (texts.length <= 2) {\n return texts.join(', ')\n }\n return `${texts.length} selected`\n }\n // Single-select: show the value's text.\n // Empty-string values are already handled by the `!hasValue` guard above;\n // this null check also narrows `Value | null` down to `Value`.\n const value = comboboxContext.value\n if (value == null) return ''\n\n const text = getValueText(value)\n if (text !== undefined) return text\n // Fall back to resolved label or serialized value\n return (\n resolveLabel(value, comboboxContext.itemToStringLabel) ||\n stringifyAsValue(value, comboboxContext.itemToStringValue)\n )\n }, [\n hasValue,\n comboboxContext.multiple,\n comboboxContext.value,\n comboboxContext.values,\n comboboxContext.itemToStringLabel,\n comboboxContext.itemToStringValue,\n getValueText,\n ])\n\n // Determine the display value for the input\n // When closed: show selected value's text\n // When open: show the search/filter text (inputValue)\n const displayValue = React.useMemo(() => {\n if (!open) {\n // When closed, show the selected value's label\n return selectedLabel\n }\n // When open, use the input value for filtering\n return comboboxContext.inputValue\n }, [open, selectedLabel, comboboxContext.inputValue])\n\n return {\n hasValue,\n displayValue,\n selectedLabel,\n getValueText,\n }\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/ui/ui/packages/react/dist/combobox/index.cjs","../../src/combobox/index.parts.ts","../../src/combobox/clear/clear.tsx","../../src/combobox/clear/clear.data-attrs.ts","../../src/combobox/contexts/combobox-positioner-context.ts","../../src/combobox/input/input.tsx","../../src/combobox/input-wrapper/input-wrapper-context.ts","../../src/combobox/input/input.data-attrs.ts","../../src/combobox/input/use-combobox-display-value.ts"],"names":["index_parts_exports","__export","PopupMenuArrow","PopupMenuBackdrop","ComboboxClear","PopupMenuEmpty","PopupMenuGroup","PopupMenuGroupLabel","PopupMenuIcon","ComboboxInput","ComboboxInputWrapper","ComboboxItem","ComboboxItemIndicator","ComboboxItemLabel","PopupMenuList","PopupMenuPopup","PopupMenuPortal","ComboboxPositioner","ComboboxRoot","PopupMenuScrollDownArrow","PopupMenuScrollUpArrow","PopupMenuSeparator","ComboboxSurface","useComboboxPositionerContext","ComboboxClearDataAttributes","props","forwardedRef","keepMounted","disabledProp","render","className","style","onClick","onPointerDown","rest","comboboxContext","useComboboxContext","disabled","hasValue","handleClick","event","handlePointerDown","state","element","useRender","ComboboxPositionerContext","ComboboxInputWrapperContext","useIsInsideInputWrapper","ComboboxInputDataAttributes","useComboboxDisplayValue","params","open","isValueEmpty","getValueText","value","serializedValue","stringifyAsValue","registryText","itemsLabel","resolveLabelFromItems","resolvedLabel","resolveLabel","selectedLabel","texts","v","text"],"mappings":"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","file":"/home/runner/work/ui/ui/packages/react/dist/combobox/index.cjs","sourcesContent":[null,"// ============================================================================\n// Combobox Parts\n// ============================================================================\n// Re-exports shared components from internal/popup-menu with Combobox-specific\n// Root, Input, Item, ItemLabel, and ItemIndicator components.\n\n// Re-export VirtualItem type from internal/listbox\nexport type { VirtualItem } from '../internal/listbox/index.js'\n\n// Re-export shared components from internal/popup-menu\nexport {\n PopupMenuArrow as Arrow,\n PopupMenuBackdrop as Backdrop,\n PopupMenuEmpty as Empty,\n // Structure\n PopupMenuGroup as Group,\n PopupMenuGroupLabel as GroupLabel,\n // Icon\n PopupMenuIcon as Icon,\n PopupMenuList as List,\n PopupMenuPopup as Popup,\n // Positioning & Container\n PopupMenuPortal as Portal,\n // Scroll indicators\n PopupMenuScrollDownArrow as ScrollDownArrow,\n PopupMenuScrollUpArrow as ScrollUpArrow,\n PopupMenuSeparator as Separator,\n} from '../internal/popup-menu/index.js'\nexport { ComboboxClear as Clear } from './clear/clear.js'\nexport { useComboboxPositionerContext } from './contexts/combobox-positioner-context.js'\nexport { ComboboxInput as Input } from './input/input.js'\nexport { ComboboxInputWrapper as InputWrapper } from './input-wrapper/input-wrapper.js'\nexport { ComboboxItem as Item } from './item/item.js'\nexport { ComboboxItemIndicator as ItemIndicator } from './item-indicator/item-indicator.js'\nexport { ComboboxItemLabel as ItemLabel } from './item-label/item-label.js'\nexport { ComboboxPositioner as Positioner } from './positioner/positioner.js'\n// Combobox-specific components\nexport { ComboboxRoot as Root } from './root/root.js'\nexport { ComboboxSurface as Surface } from './surface/surface.js'\n","'use client'\n\nimport { useRender } from '@base-ui/react/use-render'\nimport * as React from 'react'\nimport type { ComponentProps } from '../../utils/types.js'\nimport { useComboboxContext } from '../contexts/combobox-context.js'\nimport { ComboboxClearDataAttributes } from './clear.data-attrs.js'\n\nexport { ComboboxClearDataAttributes }\n\nexport interface ComboboxClearState extends Record<string, unknown> {\n /**\n * Whether the combobox has a value (clear button is actionable).\n */\n hasValue: boolean\n /**\n * Whether the combobox is disabled.\n */\n disabled: boolean\n}\n\nexport interface ComboboxClearProps\n extends ComponentProps<'button', ComboboxClear.State> {\n /**\n * Whether to render the button even when there's no value to clear.\n * @default false\n */\n keepMounted?: boolean\n}\n\n/**\n * A button that clears the selected value(s) when clicked.\n * Renders a `<button>` element.\n */\nexport const ComboboxClear = React.forwardRef<\n HTMLButtonElement,\n ComboboxClear.Props\n>(function ComboboxClear(props, forwardedRef) {\n const {\n keepMounted = false,\n disabled: disabledProp,\n render,\n className,\n style,\n onClick,\n onPointerDown,\n ...rest\n } = props\n\n const comboboxContext = useComboboxContext()\n\n const disabled = disabledProp ?? comboboxContext.disabled\n\n const hasValue = comboboxContext.multiple\n ? comboboxContext.values.length > 0\n : comboboxContext.value !== ''\n\n const handleClick = React.useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n if (event.defaultPrevented) return\n\n if (comboboxContext.multiple) {\n comboboxContext.onValuesChange([])\n } else {\n comboboxContext.onValueChange('')\n }\n\n // Also clear the input value\n comboboxContext.onInputValueChange('')\n },\n [onClick, comboboxContext],\n )\n\n // Prevent pointer down from stealing focus from the input\n const handlePointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n event.preventDefault()\n onPointerDown?.(event)\n },\n [onPointerDown],\n )\n\n const state: ComboboxClear.State = React.useMemo(\n () => ({\n hasValue,\n disabled,\n }),\n [hasValue, disabled],\n )\n\n const element = useRender({\n render,\n ref: forwardedRef,\n state,\n props: {\n ...rest,\n [ComboboxClearDataAttributes.slot]: '',\n type: 'button',\n tabIndex: -1, // Not tabbable - use keyboard shortcuts instead\n 'aria-label': 'Clear selection',\n disabled: disabled || !hasValue,\n className,\n style,\n onClick: handleClick,\n onPointerDown: handlePointerDown,\n },\n enabled: keepMounted || hasValue,\n defaultTagName: 'button',\n })\n\n // Don't render if no value and not keepMounted\n if (!keepMounted && !hasValue) {\n return null\n }\n\n return element\n})\n\nexport namespace ComboboxClear {\n export type State = ComboboxClearState\n export interface Props extends ComboboxClearProps {}\n}\n","/**\n * Data attributes for ComboboxClear component.\n */\nexport const ComboboxClearDataAttributes = {\n /**\n * Identifies the component part.\n * @type {'bazzaui-combobox-clear'}\n */\n slot: 'bazzaui-combobox-clear',\n} as const\n","'use client'\n\nimport * as React from 'react'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Types matching Base UI's positioning types\nexport type Side = 'top' | 'bottom' | 'left' | 'right'\nexport type Align = 'start' | 'center' | 'end'\n\n/**\n * Layout mode for the combobox popup.\n * - `'floating'` - Standard dropdown positioning below/above the input\n * - `'input-embedded'` - Popup wraps around the input (macOS-style)\n */\nexport type ComboboxLayout = 'floating' | 'input-embedded'\n\n/**\n * Context value for Combobox Positioner.\n * Provides alignment state for coordinating positioning behavior.\n */\nexport interface ComboboxPositionerContextValue {\n /**\n * The layout mode being used.\n * - `'floating'` - Standard dropdown positioning\n * - `'input-embedded'` - Popup wraps around the input\n */\n layout: ComboboxLayout\n\n /**\n * The side of the popup relative to the input.\n */\n side: Side\n\n /**\n * The alignment of the popup.\n */\n align: Align\n\n /**\n * Height of the input element in pixels.\n * Use this to add appropriate padding to the popup.\n */\n inputHeight: number\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ComboboxPositionerContext =\n React.createContext<ComboboxPositionerContextValue | null>(null)\n\n/**\n * Hook to access the Combobox Positioner context.\n * Returns null if used outside a ComboboxPositioner.\n */\nexport function useComboboxPositionerContext(): ComboboxPositionerContextValue | null {\n return React.useContext(ComboboxPositionerContext)\n}\n\nexport { ComboboxPositionerContext }\n","'use client'\n\nimport { useRender } from '@base-ui/react/use-render'\nimport * as React from 'react'\nimport { useFocusOwner } from '../../internal/popup-menu/contexts/focus-owner-context.js'\nimport { usePopupMenuContext } from '../../internal/popup-menu/contexts/popup-menu-context.js'\nimport { resolveLabelFromItems } from '../../utils/items.js'\nimport type { ComponentProps } from '../../utils/types.js'\nimport { useComboboxContext } from '../contexts/combobox-context.js'\nimport { useIsInsideInputWrapper } from '../input-wrapper/input-wrapper-context.js'\nimport { ComboboxInputDataAttributes } from './input.data-attrs.js'\nimport { useComboboxDisplayValue } from './use-combobox-display-value.js'\nimport { useComboboxInputBehavior } from './use-combobox-input-behavior.js'\n\nexport { ComboboxInputDataAttributes }\n\nexport interface ComboboxInputState extends Record<string, unknown> {\n /**\n * Whether the combobox popup is open.\n */\n open: boolean\n /**\n * Whether the input is disabled.\n */\n disabled: boolean\n /**\n * Whether the input currently shows placeholder (no value selected).\n */\n placeholder: boolean\n}\n\n/**\n * Cursor behavior when the combobox popup opens.\n * - `'none'` - Don't move the cursor (cursor appears where clicked)\n * - `'end'` - Move cursor to the end of the input\n * - `'select-all'` - Move cursor to the end and select all text\n */\nexport type ComboboxInputCursorBehavior = 'none' | 'end' | 'select-all'\n\nexport interface ComboboxInputProps\n extends Omit<\n ComponentProps<'input', ComboboxInput.State>,\n 'value' | 'onChange' | 'type'\n > {\n /**\n * Placeholder text shown when no value is selected and input is empty.\n * Overrides the placeholder set on Combobox.Root.\n */\n placeholder?: string\n\n /**\n * Cursor behavior when the combobox popup opens.\n * - `'none'` - Don't move the cursor (cursor appears where clicked)\n * - `'end'` - Move cursor to the end of the input\n * - `'select-all'` - Move cursor to the end and select all text\n *\n * @default 'none'\n */\n cursorBehavior?: ComboboxInputCursorBehavior\n}\n\n/**\n * An input that acts as both the trigger and search field for the combobox.\n * Renders an `<input>` element with combobox ARIA semantics.\n */\nexport const ComboboxInput = React.forwardRef<\n HTMLInputElement,\n ComboboxInput.Props\n>(function ComboboxInput(props, forwardedRef) {\n const {\n placeholder: placeholderProp,\n disabled: disabledProp,\n cursorBehavior = 'none',\n render,\n className,\n style,\n onFocus,\n onBlur,\n onClick,\n onKeyDown,\n ...rest\n } = props\n\n const comboboxContext = useComboboxContext()\n const popupMenuContext = usePopupMenuContext()\n const focusOwnerStore = useFocusOwner()\n const isInsideInputWrapper = useIsInsideInputWrapper()\n\n const disabled =\n (disabledProp ?? comboboxContext.disabled) || popupMenuContext.disabled\n\n // A `null` item's label (looked up under the empty-string key) acts as the\n // placeholder, taking precedence over the Root placeholder but not an\n // explicit `placeholder` prop on the input.\n const nullItemLabel = resolveLabelFromItems(comboboxContext.items, '')\n const placeholder =\n placeholderProp ??\n (typeof nullItemLabel === 'string' ? nullItemLabel : undefined) ??\n comboboxContext.placeholder\n\n // Get open state\n const open = popupMenuContext.store.useState('open')\n\n // Use display value hook\n const { hasValue, displayValue, getValueText } = useComboboxDisplayValue({\n comboboxContext,\n open,\n })\n\n // Use input behavior hook\n const { handleChange, handleFocus, handleBlur, handleClick, handleKeyDown } =\n useComboboxInputBehavior({\n comboboxContext,\n store: popupMenuContext.store,\n focusOwnerStore,\n open,\n disabled,\n cursorBehavior,\n hasValue,\n getValueText,\n onFocus,\n onBlur,\n onClick,\n onKeyDown,\n })\n\n // Build data attributes\n const dataAttrs: Record<string, string> = {\n [ComboboxInputDataAttributes.slot]: '',\n }\n if (open) {\n dataAttrs[ComboboxInputDataAttributes.open] = ''\n } else {\n dataAttrs[ComboboxInputDataAttributes.closed] = ''\n }\n if (disabled) {\n dataAttrs[ComboboxInputDataAttributes.disabled] = ''\n }\n if (!hasValue) {\n dataAttrs[ComboboxInputDataAttributes.placeholder] = ''\n }\n // Add input-embedded data attribute when layout is input-embedded\n if (comboboxContext.layout === 'input-embedded') {\n dataAttrs['data-input-embedded'] = ''\n }\n\n // Register input element for positioning\n const mergedRef = React.useCallback(\n (node: HTMLInputElement | null) => {\n comboboxContext.setInputElement(node)\n if (typeof forwardedRef === 'function') {\n forwardedRef(node)\n } else if (forwardedRef) {\n forwardedRef.current = node\n }\n },\n [forwardedRef, comboboxContext],\n )\n\n const state: ComboboxInput.State = React.useMemo(\n () => ({\n open,\n disabled,\n placeholder: !hasValue,\n }),\n [open, disabled, hasValue],\n )\n\n // When input-embedded layout, apply styles to position input above the popup\n // Skip z-index if inside an InputWrapper (the wrapper handles z-index)\n const inputEmbeddedStyles: React.CSSProperties | undefined =\n comboboxContext.layout === 'input-embedded' && !isInsideInputWrapper\n ? { position: 'relative', zIndex: 1 }\n : undefined\n\n const element = useRender({\n render,\n ref: mergedRef,\n state,\n props: {\n ...rest,\n ...dataAttrs,\n type: 'text',\n role: 'combobox',\n 'aria-autocomplete': 'list',\n 'aria-expanded': open,\n 'aria-controls': comboboxContext.listId,\n 'aria-haspopup': 'listbox',\n autoComplete: 'off',\n autoCorrect: 'off',\n spellCheck: false,\n disabled,\n placeholder: !hasValue ? placeholder : undefined,\n className,\n style: { ...inputEmbeddedStyles, ...style },\n value: displayValue,\n onChange: handleChange,\n onFocus: handleFocus,\n onBlur: handleBlur,\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n },\n defaultTagName: 'input',\n })\n\n return element\n})\n\nexport namespace ComboboxInput {\n export interface Props extends ComboboxInputProps {}\n export type State = ComboboxInputState\n}\n","import * as React from 'react'\n\n/**\n * Context to indicate that children are inside an InputWrapper.\n * When true, Input should not apply its own z-index styles for input-embedded layout.\n */\nexport const ComboboxInputWrapperContext = React.createContext<boolean>(false)\n\n/**\n * Hook to check if component is inside a ComboboxInputWrapper.\n */\nexport function useIsInsideInputWrapper(): boolean {\n return React.useContext(ComboboxInputWrapperContext)\n}\n","/**\n * Data attributes for ComboboxInput component.\n */\nexport const ComboboxInputDataAttributes = {\n /**\n * Identifies the component part.\n * @type {'bazzaui-combobox-input'}\n */\n slot: 'bazzaui-combobox-input',\n /** Present when the combobox popup is open. */\n open: 'data-open',\n /** Present when the combobox popup is closed. */\n closed: 'data-closed',\n /** Present when the input is disabled. */\n disabled: 'data-disabled',\n /** Present when no value is selected (showing placeholder). */\n placeholder: 'data-placeholder',\n} as const\n","'use client'\n\nimport * as React from 'react'\nimport { resolveLabelFromItems } from '../../utils/items.js'\nimport {\n isValueEmpty,\n resolveLabel,\n stringifyAsValue,\n} from '../../utils/resolve-value-label.js'\nimport type { ComboboxContextValue } from '../contexts/combobox-context.js'\n\nexport interface UseComboboxDisplayValueParams<Value = unknown> {\n comboboxContext: ComboboxContextValue<Value>\n open: boolean\n}\n\nexport interface UseComboboxDisplayValueReturn<Value = unknown> {\n /** Whether a value is selected */\n hasValue: boolean\n /** The value to display in the input */\n displayValue: string\n /** The label of the selected value(s) */\n selectedLabel: string\n /** Get the display text for a value */\n getValueText: (value: Value) => string | undefined\n}\n\n/**\n * Hook to compute the display value for the combobox input.\n *\n * Handles:\n * - Determining if a value is selected (single or multi-select)\n * - Computing the display label for selected values\n * - Switching between selected label (closed) and input value (open)\n */\nexport function useComboboxDisplayValue<Value = unknown>(\n params: UseComboboxDisplayValueParams<Value>,\n): UseComboboxDisplayValueReturn<Value> {\n const { comboboxContext, open } = params\n\n // Determine if showing placeholder (no value selected)\n const hasValue = comboboxContext.multiple\n ? comboboxContext.values.length > 0\n : !isValueEmpty(comboboxContext.value)\n\n // Get the display text for selected value\n const getValueText = React.useCallback(\n (value: Value): string | undefined => {\n // Serialize for registry lookup\n const serializedValue = stringifyAsValue(\n value,\n comboboxContext.itemToStringValue,\n )\n\n // First try the registry (populated when items mount)\n const registryText = comboboxContext.itemTextRegistry.get(serializedValue)\n if (registryText !== undefined) {\n return registryText\n }\n\n // Fall back to the items prop (for initial render before popup opens).\n // The input can only display strings, so ignore non-string labels here.\n const itemsLabel = resolveLabelFromItems(\n comboboxContext.items,\n serializedValue,\n )\n if (typeof itemsLabel === 'string') {\n return itemsLabel\n }\n\n // Fall back to itemToStringLabel for object values\n const resolvedLabel = resolveLabel(\n value,\n comboboxContext.itemToStringLabel,\n )\n // Only return if it's different from the serialized value (meaning we got a real label)\n if (resolvedLabel && resolvedLabel !== serializedValue) {\n return resolvedLabel\n }\n\n return undefined\n },\n [\n comboboxContext.itemTextRegistry,\n comboboxContext.items,\n comboboxContext.itemToStringLabel,\n comboboxContext.itemToStringValue,\n ],\n )\n\n // Get the label for the selected value (used when closed or just opened)\n const selectedLabel = React.useMemo(() => {\n if (!hasValue) {\n return ''\n }\n if (comboboxContext.multiple) {\n // For multi-select, show comma-separated values or count\n const texts = comboboxContext.values\n .map((v) => {\n const text = getValueText(v)\n if (text !== undefined) return text\n // Fall back to resolved label or serialized value\n return (\n resolveLabel(v, comboboxContext.itemToStringLabel) ||\n stringifyAsValue(v, comboboxContext.itemToStringValue)\n )\n })\n .filter(Boolean)\n if (texts.length <= 2) {\n return texts.join(', ')\n }\n return `${texts.length} selected`\n }\n // Single-select: show the value's text.\n // Empty-string values are already handled by the `!hasValue` guard above;\n // this null check also narrows `Value | null` down to `Value`.\n const value = comboboxContext.value\n if (value == null) return ''\n\n const text = getValueText(value)\n if (text !== undefined) return text\n // Fall back to resolved label or serialized value\n return (\n resolveLabel(value, comboboxContext.itemToStringLabel) ||\n stringifyAsValue(value, comboboxContext.itemToStringValue)\n )\n }, [\n hasValue,\n comboboxContext.multiple,\n comboboxContext.value,\n comboboxContext.values,\n comboboxContext.itemToStringLabel,\n comboboxContext.itemToStringValue,\n getValueText,\n ])\n\n // Determine the display value for the input\n // When closed: show selected value's text\n // When open: show the search/filter text (inputValue)\n const displayValue = React.useMemo(() => {\n if (!open) {\n // When closed, show the selected value's label\n return selectedLabel\n }\n // When open, use the input value for filtering\n return comboboxContext.inputValue\n }, [open, selectedLabel, comboboxContext.inputValue])\n\n return {\n hasValue,\n displayValue,\n selectedLabel,\n getValueText,\n }\n}\n"]}