@immediately-run/omnibox 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Omnibox.cjs CHANGED
@@ -53,8 +53,7 @@ function appScore(hit, q) {
53
53
  if (hit.category.toLowerCase().includes(q)) return 0;
54
54
  return -1;
55
55
  }
56
- const appRoute = (repo) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;
57
- function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
56
+ function Omnibox({ variant, heroShortcut = false, hits, renderChip, renderDoc }) {
58
57
  const isMobile = useMediaQuery("(max-width: 720px)");
59
58
  const [query, setQuery] = (0, import_react.useState)("");
60
59
  const [highlight, setHighlight] = (0, import_react.useState)(-1);
@@ -72,7 +71,7 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
72
71
  } catch (error) {
73
72
  if (!warnedSources.current.has(kind)) {
74
73
  warnedSources.current.add(kind);
75
- console.warn(`omnibox: the "${String(kind)}" hit source threw and is disabled for this mount`, error);
74
+ console.warn(`omnibox: the "${String(kind)}" hit source threw; its rows are empty for this query`, error);
76
75
  }
77
76
  return [];
78
77
  }
@@ -225,7 +224,7 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
225
224
  className: "omnibox-option",
226
225
  role: "option",
227
226
  "aria-selected": highlight === idx,
228
- path: appRoute(hit.repo),
227
+ path: hit.path,
229
228
  children: [
230
229
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "omnibox-option-name", children: hit.name }),
231
230
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "omnibox-option-cat", children: hit.category }),
@@ -238,6 +237,15 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
238
237
  }) }),
239
238
  docHits.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "omnibox-group", role: "group", "aria-label": "Docs and tutorials", children: docHits.map((hit) => {
240
239
  const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);
240
+ const anchorProps = {
241
+ id: `${listId}-opt-doc-${hit.key}`,
242
+ className: "omnibox-option",
243
+ role: "option",
244
+ "aria-selected": highlight === idx
245
+ };
246
+ if (renderDoc) {
247
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Fragment, { children: renderDoc(hit, anchorProps) }, hit.key);
248
+ }
241
249
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
242
250
  "a",
243
251
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Omnibox.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react';\nimport './omnibox.css';\nimport { parseLaunch, PROVIDERS, type Launch } from './launch';\nimport { PlatformLink } from '@immediately-run/sdk/platformLink';\nimport { focusHeroOmnibox, registerOmniboxFocus } from './omniboxFocus';\nimport type { OmniboxVariant } from './omniboxFocus';\n\n// The omnibox (R3-512; FRONT_DOOR_IA §5) — the front door's primary control. It\n// does W1 (run a repo by URL or tuple) and W2 (find an app) in one place, as a\n// WAI-ARIA list-autocomplete combobox with three result groups of ONE action per\n// row. Run and Open rows render through `PlatformLink`, which resolves the\n// host-space href and escapes the frame: a platform route navigates the HOST\n// document, and a root-relative href inside the sandboxed frame would resolve\n// against the sandbox origin and land nowhere.\n//\n// The package owns the component and the launch grammar; it owns NO data. The\n// app-directory and docs hit sources are injected per app (`hits`), because the\n// package cannot depend on a consumer's records (R3-530).\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia(query).matches\n : false,\n );\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(query);\n const onChange = () => setMatches(mq.matches);\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [query]);\n return matches;\n}\n\n/* ── the hit vocabulary a consumer's sources speak ──────────────────────── */\n\nexport interface AppHit {\n key: string;\n name: string;\n category: string;\n blurb: string;\n /** The repository the row opens — an org repo under immediately-run. */\n repo: string;\n /** Opaque to the package: a consumer's `renderChip` reads it back. */\n provenance?: unknown;\n}\n\nexport interface DocHit {\n key: string;\n title: string;\n lead: string;\n /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */\n href: string;\n}\n\n/** The data seams. Absent sources simply yield no rows of their kind; an omnibox\n * with no `hits` at all is the launch grammar only (what the Home app renders). */\nexport interface OmniboxHitSources {\n /** Candidate app hits for a query; the package ranks, filters and orders them. */\n apps?: (query: string) => AppHit[];\n /** Matched doc hits for a query, best-first, capped by the source. */\n docs?: (query: string) => DocHit[];\n}\n\n/* ── ranking ────────────────────────────────────────────────────────────── */\n\n/** name-prefix > name-substring > repo > blurb > category (FRONT_DOOR_IA §5.3).\n * Internal: the ranking is the package's policy, not part of the surface. */\nfunction appScore(hit: AppHit, q: string): number {\n if (hit.name.toLowerCase().startsWith(q)) return 4;\n if (hit.name.toLowerCase().includes(q)) return 3;\n if (hit.repo.toLowerCase().includes(q)) return 2;\n if (hit.blurb.toLowerCase().includes(q)) return 1;\n if (hit.category.toLowerCase().includes(q)) return 0;\n return -1;\n}\n\n/** The platform path an app row opens. The directory's apps are org repos that\n * open at their entry — the one shape an injected `apps` source feeds. */\nconst appRoute = (repo: string) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;\n\n/* ── the component ──────────────────────────────────────────────────────── */\n\nexport interface OmniboxProps {\n variant: OmniboxVariant;\n /** Nav variant only: true while the hero omnibox is mounted (`/`), so the\n * nav field renders as the shortcut that focuses it. Derived by the caller\n * from the route — render-time data, not an effect. */\n heroShortcut?: boolean;\n /** App-directory and docs hit sources. Absent → the launch grammar only. */\n hits?: OmniboxHitSources;\n /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a\n * site component with site data types, so the package renders what it is given. */\n renderChip?: (hit: AppHit) => ReactNode;\n}\n\nfunction Omnibox({ variant, heroShortcut = false, hits, renderChip }: OmniboxProps) {\n const isMobile = useMediaQuery('(max-width: 720px)');\n const [query, setQuery] = useState('');\n const [highlight, setHighlight] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const outerRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n const inputId = `${listId}-input`;\n const helperId = useId();\n const noticeId = useId();\n // A source that throws is degraded, not fatal: logged ONCE per source, then\n // that group stays empty — the location row still renders.\n const warnedSources = useRef<Set<keyof OmniboxHitSources>>(new Set());\n const callSource = useCallback(\n function callSource<K extends keyof OmniboxHitSources>(\n kind: K,\n source: OmniboxHitSources[K],\n q: string,\n ): ReturnType<NonNullable<OmniboxHitSources[K]>> | [] {\n try {\n return source!(q) as ReturnType<NonNullable<OmniboxHitSources[K]>>;\n } catch (error) {\n if (!warnedSources.current.has(kind)) {\n warnedSources.current.add(kind);\n console.warn(`omnibox: the \"${String(kind)}\" hit source threw and is disabled for this mount`, error);\n }\n return [];\n }\n },\n [],\n );\n\n const parsed: Launch = useMemo(() => parseLaunch(query), [query]);\n const runnable = parsed.kind === 'location' || parsed.kind === 'platform-url';\n const runPath =\n parsed.kind === 'location'\n ? parsed.presentPath\n : parsed.kind === 'platform-url'\n ? parsed.path\n : undefined;\n\n const panelOpen = query.trim() !== '';\n\n // Adjusting state during render (the sanctioned pattern): the highlight must\n // not survive the option set changing under it, and an effect would cascade.\n const [prevQuery, setPrevQuery] = useState(query);\n if (prevQuery !== query) {\n setPrevQuery(query);\n setHighlight(-1);\n }\n\n // Unknown provider → the notice replaces the helper line's text and is\n // announced through the live region.\n const notice =\n parsed.kind === 'unknown-provider'\n ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.`\n : '';\n\n const helper =\n variant === 'new' ? 'the repo you just created' : 'Accepts provider:namespace/repository@ref · GitHub is the first provider';\n\n const appHits = useMemo(() => {\n if (!panelOpen || !hits?.apps) return [];\n const q = query.trim().toLowerCase();\n return callSource('apps', hits.apps, q)\n .map((hit) => ({ hit, score: appScore(hit, q) }))\n .filter(({ score }) => score >= 0)\n .sort((a, b) => b.score - a.score)\n .map(({ hit }) => hit);\n }, [panelOpen, query, hits, callSource]);\n\n const docHits = useMemo(() => {\n if (!panelOpen || !hits?.docs) return [];\n return callSource('docs', hits.docs, query.trim().toLowerCase());\n }, [panelOpen, query, hits, callSource]);\n\n const locationRow = parsed.kind === 'location' ? parsed : undefined;\n const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;\n\n // Flattened options, in group order — the arrow-key walk and the highlight id\n // both read this list.\n const options = useMemo(() => {\n const list: { id: string; label: string }[] = [];\n if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });\n for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });\n for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });\n return list;\n }, [locationRow, appHits, docHits, listId]);\n\n // Register with the focus registry (⌘K, the nav shortcut and the \"paste a repo\"\n // CTAs all land here). `reveal` is what lets those CTAs scroll this field into\n // view without any component querying for its CSS class.\n useEffect(\n () =>\n registerOmniboxFocus(variant, {\n focus: () => inputRef.current?.focus(),\n reveal: () => outerRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }),\n }),\n [variant],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n if (!panelOpen || options.length === 0) return;\n e.preventDefault();\n setHighlight((h) => {\n if (h === -1) return e.key === 'ArrowDown' ? 0 : options.length - 1;\n return (h + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length;\n });\n return;\n }\n if (e.key === 'Enter') {\n if (highlight >= 0 && highlight < options.length) {\n e.preventDefault();\n document.getElementById(options[highlight].id)?.click();\n return;\n }\n if (runnable) {\n e.preventDefault();\n document.getElementById(`${listId}-run`)?.click();\n }\n return;\n }\n if (e.key === 'Escape') {\n // Close the panel, then clear the highlight, then blur — in that order.\n setQuery('');\n setHighlight(-1);\n inputRef.current?.blur();\n }\n },\n [panelOpen, options, highlight, runnable, listId],\n );\n\n const chip = (\n <span className=\"omnibox-chip\" aria-hidden={Object.keys(PROVIDERS).length === 1 || undefined}>\n {Object.keys(PROVIDERS).length === 1 ? (\n // One provider: a static label with no caret — NOT a dropdown of\n // providers that do not exist.\n <span className=\"omnibox-chip-label\">github</span>\n ) : (\n <select className=\"omnibox-chip-select\" aria-label=\"Provider\">\n {Object.keys(PROVIDERS).map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n )}\n </span>\n );\n\n const run = runPath !== undefined ? (\n <PlatformLink\n id={`${listId}-run`}\n className=\"omnibox-run\"\n path={runPath}\n aria-label=\"Run\"\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </PlatformLink>\n ) : (\n <button\n id={`${listId}-run`}\n type=\"button\"\n className=\"omnibox-run\"\n aria-disabled=\"true\"\n aria-describedby={`${helperId} ${noticeId}`}\n onClick={(e) => e.preventDefault()}\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </button>\n );\n\n const field = (\n <div className={`omnibox omnibox--${variant}`}>\n <div className=\"omnibox-row\">\n {chip}\n <input\n ref={inputRef}\n id={inputId}\n className=\"omnibox-input\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? listId : undefined}\n aria-activedescendant={highlight >= 0 ? options[highlight]?.id : undefined}\n aria-describedby={`${helperId} ${noticeId}`}\n aria-invalid={notice ? true : undefined}\n placeholder={isMobile ? 'Paste a repo or an app name' : 'owner/repo@branch, a GitHub URL, or an app name'}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {run}\n </div>\n <p className=\"omnibox-helper\" id={helperId}>\n {notice || helper}\n </p>\n {/* The live region announces the notice; empty in the common case. */}\n <p className=\"omnibox-visually-hidden\" id={noticeId} aria-live=\"polite\">\n {notice}\n </p>\n {panelOpen && (\n <div className=\"omnibox-panel\" id={listId} role=\"listbox\" aria-label=\"Results\">\n {hasResults ? (\n <>\n {locationRow && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Run from source\">\n <PlatformLink\n id={`${listId}-opt-location`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === 0}\n path={locationRow.presentPath}\n >\n <span className=\"omnibox-option-name\">{locationRow.display}</span>\n <span className=\"omnibox-option-action\">Run</span>\n </PlatformLink>\n </div>\n )}\n {appHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Apps in the directory\">\n {appHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);\n return (\n <PlatformLink\n key={hit.key}\n id={`${listId}-opt-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n path={appRoute(hit.repo)}\n >\n <span className=\"omnibox-option-name\">{hit.name}</span>\n <span className=\"omnibox-option-cat\">{hit.category}</span>\n <span className=\"omnibox-option-blurb\">{hit.blurb}</span>\n {renderChip?.(hit)}\n </PlatformLink>\n );\n })}\n </div>\n )}\n {docHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Docs and tutorials\">\n {docHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);\n return (\n <a\n key={hit.key}\n id={`${listId}-opt-doc-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n href={hit.href}\n >\n <span className=\"omnibox-option-name\">{hit.title}</span>\n <span className=\"omnibox-option-blurb\">{hit.lead}</span>\n </a>\n );\n })}\n </div>\n )}\n </>\n ) : (\n <div className=\"omnibox-empty\">Nothing matched. Try an app name, or paste a repo.</div>\n )}\n </div>\n )}\n </div>\n );\n\n // The nav variant collapses to a shortcut button while the hero omnibox is\n // mounted (on `/`): activating it focuses the hero field. On every other\n // route the field expands in place.\n if (variant === 'nav' && heroShortcut) {\n return (\n <button\n type=\"button\"\n className=\"omnibox-nav-button\"\n onClick={() => focusHeroOmnibox()}\n aria-label=\"Search apps and docs, or paste a repo\"\n >\n <span className=\"omnibox-nav-button-label\">Search</span>\n <span className=\"kbd\">⌘K</span>\n </button>\n );\n }\n\n return (\n <div className={`omnibox-outer omnibox-outer--${variant}`} ref={outerRef}>\n <label className=\"omnibox-visually-hidden\" htmlFor={inputId}>\n Paste a repo, or search apps and docs\n </label>\n {field}\n </div>\n );\n}\n\nexport default Omnibox;\n"],"mappings":"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","names":["callSource"]}
1
+ {"version":3,"sources":["../src/Omnibox.tsx"],"sourcesContent":["import { Fragment, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react';\nimport './omnibox.css';\nimport { parseLaunch, PROVIDERS, type Launch } from './launch';\nimport { PlatformLink } from '@immediately-run/sdk/platformLink';\nimport { focusHeroOmnibox, registerOmniboxFocus } from './omniboxFocus';\nimport type { OmniboxVariant } from './omniboxFocus';\n\n// The omnibox (R3-512; FRONT_DOOR_IA §5) — the front door's primary control. It\n// does W1 (run a repo by URL or tuple) and W2 (find an app) in one place, as a\n// WAI-ARIA list-autocomplete combobox with three result groups of ONE action per\n// row. Run and Open rows render through `PlatformLink`, which resolves the\n// host-space href and escapes the frame: a platform route navigates the HOST\n// document, and a root-relative href inside the sandboxed frame would resolve\n// against the sandbox origin and land nowhere.\n//\n// The package owns the component and the launch grammar; it owns NO data. The\n// app-directory and docs hit sources are injected per app (`hits`), because the\n// package cannot depend on a consumer's records (R3-530).\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia(query).matches\n : false,\n );\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(query);\n const onChange = () => setMatches(mq.matches);\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [query]);\n return matches;\n}\n\n/* ── the hit vocabulary a consumer's sources speak ──────────────────────── */\n\nexport interface AppHit {\n key: string;\n name: string;\n category: string;\n blurb: string;\n /** The repository the row opens — an org repo under immediately-run. */\n repo: string;\n /** The PLATFORM path the row opens, e.g. `/present/github/immediately-run/todo/main/files/src/App.tsx`.\n * Supplied by the consumer's `apps` source beside its own route builder, so the\n * package carries no second spelling of any route family. Rendered through\n * `PlatformLink` (host-space href, frame-escaping). */\n path: string;\n /** Opaque to the package: a consumer's `renderChip` reads it back. */\n provenance?: unknown;\n}\n\nexport interface DocHit {\n key: string;\n title: string;\n lead: string;\n /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */\n href: string;\n /** The app-space route behind `href`, when the consumer renders the row through\n * its own in-app link (`renderDoc`). Opaque to the package. */\n to?: string;\n}\n\n/** The data seams. Absent sources simply yield no rows of their kind; an omnibox\n * with no `hits` at all is the launch grammar only (what the Home app renders). */\nexport interface OmniboxHitSources {\n /** Candidate app hits for a query; the package ranks, filters and orders them. */\n apps?: (query: string) => AppHit[];\n /** Matched doc hits for a query, best-first, capped by the source. */\n docs?: (query: string) => DocHit[];\n}\n\n/* ── ranking ────────────────────────────────────────────────────────────── */\n\n/** name-prefix > name-substring > repo > blurb > category (FRONT_DOOR_IA §5.3).\n * Internal: the ranking is the package's policy, not part of the surface. */\nfunction appScore(hit: AppHit, q: string): number {\n if (hit.name.toLowerCase().startsWith(q)) return 4;\n if (hit.name.toLowerCase().includes(q)) return 3;\n if (hit.repo.toLowerCase().includes(q)) return 2;\n if (hit.blurb.toLowerCase().includes(q)) return 1;\n if (hit.category.toLowerCase().includes(q)) return 0;\n return -1;\n}\n\n/* ── the component ──────────────────────────────────────────────────────── */\n\n/** What a `renderDoc` anchor must spread: the combobox's option identity and state. */\nexport interface DocAnchorProps {\n id: string;\n className: string;\n role: 'option';\n 'aria-selected': boolean;\n}\n\nexport interface OmniboxProps {\n variant: OmniboxVariant;\n /** Nav variant only: true while the hero omnibox is mounted (`/`), so the\n * nav field renders as the shortcut that focuses it. Derived by the caller\n * from the route — render-time data, not an effect. */\n heroShortcut?: boolean;\n /** App-directory and docs hit sources. Absent → the launch grammar only. */\n hits?: OmniboxHitSources;\n /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a\n * site component with site data types, so the package renders what it is given. */\n renderChip?: (hit: AppHit) => ReactNode;\n /** Renders a doc ROW. `anchorProps` carries the combobox contract (the option's\n * id, class, role and aria-selected) — spread them onto the anchor you render so\n * the arrow-key highlight and the Enter walk keep working. The fallback is a\n * plain `<a href>` — its href is real and resolvable, but on-host a plain click\n * navigates the sandboxed FRAME to the target instead of routing the app, so a\n * consumer with an in-app link (the landing page's SiteLink) should supply this. */\n renderDoc?: (hit: DocHit, anchorProps: DocAnchorProps) => ReactNode;\n}\n\nfunction Omnibox({ variant, heroShortcut = false, hits, renderChip, renderDoc }: OmniboxProps) {\n const isMobile = useMediaQuery('(max-width: 720px)');\n const [query, setQuery] = useState('');\n const [highlight, setHighlight] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const outerRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n const inputId = `${listId}-input`;\n const helperId = useId();\n const noticeId = useId();\n // A source that throws is degraded, not fatal: that query's group stays empty\n // and the location row still renders. The source is called again on the next\n // keystroke — a transient throw recovers silently; only the LOG is once.\n const warnedSources = useRef<Set<keyof OmniboxHitSources>>(new Set());\n const callSource = useCallback(\n function callSource<K extends keyof OmniboxHitSources>(\n kind: K,\n source: OmniboxHitSources[K],\n q: string,\n ): ReturnType<NonNullable<OmniboxHitSources[K]>> | [] {\n try {\n return source!(q) as ReturnType<NonNullable<OmniboxHitSources[K]>>;\n } catch (error) {\n if (!warnedSources.current.has(kind)) {\n warnedSources.current.add(kind);\n console.warn(`omnibox: the \"${String(kind)}\" hit source threw; its rows are empty for this query`, error);\n }\n return [];\n }\n },\n [],\n );\n\n const parsed: Launch = useMemo(() => parseLaunch(query), [query]);\n const runnable = parsed.kind === 'location' || parsed.kind === 'platform-url';\n const runPath =\n parsed.kind === 'location'\n ? parsed.presentPath\n : parsed.kind === 'platform-url'\n ? parsed.path\n : undefined;\n\n const panelOpen = query.trim() !== '';\n\n // Adjusting state during render (the sanctioned pattern): the highlight must\n // not survive the option set changing under it, and an effect would cascade.\n const [prevQuery, setPrevQuery] = useState(query);\n if (prevQuery !== query) {\n setPrevQuery(query);\n setHighlight(-1);\n }\n\n // Unknown provider → the notice replaces the helper line's text and is\n // announced through the live region.\n const notice =\n parsed.kind === 'unknown-provider'\n ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.`\n : '';\n\n const helper =\n variant === 'new' ? 'the repo you just created' : 'Accepts provider:namespace/repository@ref · GitHub is the first provider';\n\n const appHits = useMemo(() => {\n if (!panelOpen || !hits?.apps) return [];\n const q = query.trim().toLowerCase();\n return callSource('apps', hits.apps, q)\n .map((hit) => ({ hit, score: appScore(hit, q) }))\n .filter(({ score }) => score >= 0)\n .sort((a, b) => b.score - a.score)\n .map(({ hit }) => hit);\n }, [panelOpen, query, hits, callSource]);\n\n const docHits = useMemo(() => {\n if (!panelOpen || !hits?.docs) return [];\n return callSource('docs', hits.docs, query.trim().toLowerCase());\n }, [panelOpen, query, hits, callSource]);\n\n const locationRow = parsed.kind === 'location' ? parsed : undefined;\n const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;\n\n // Flattened options, in group order — the arrow-key walk and the highlight id\n // both read this list.\n const options = useMemo(() => {\n const list: { id: string; label: string }[] = [];\n if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });\n for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });\n for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });\n return list;\n }, [locationRow, appHits, docHits, listId]);\n\n // Register with the focus registry (⌘K, the nav shortcut and the \"paste a repo\"\n // CTAs all land here). `reveal` is what lets those CTAs scroll this field into\n // view without any component querying for its CSS class.\n useEffect(\n () =>\n registerOmniboxFocus(variant, {\n focus: () => inputRef.current?.focus(),\n reveal: () => outerRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }),\n }),\n [variant],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n if (!panelOpen || options.length === 0) return;\n e.preventDefault();\n setHighlight((h) => {\n if (h === -1) return e.key === 'ArrowDown' ? 0 : options.length - 1;\n return (h + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length;\n });\n return;\n }\n if (e.key === 'Enter') {\n if (highlight >= 0 && highlight < options.length) {\n e.preventDefault();\n document.getElementById(options[highlight].id)?.click();\n return;\n }\n if (runnable) {\n e.preventDefault();\n document.getElementById(`${listId}-run`)?.click();\n }\n return;\n }\n if (e.key === 'Escape') {\n // Close the panel, then clear the highlight, then blur — in that order.\n setQuery('');\n setHighlight(-1);\n inputRef.current?.blur();\n }\n },\n [panelOpen, options, highlight, runnable, listId],\n );\n\n const chip = (\n <span className=\"omnibox-chip\" aria-hidden={Object.keys(PROVIDERS).length === 1 || undefined}>\n {Object.keys(PROVIDERS).length === 1 ? (\n // One provider: a static label with no caret — NOT a dropdown of\n // providers that do not exist.\n <span className=\"omnibox-chip-label\">github</span>\n ) : (\n <select className=\"omnibox-chip-select\" aria-label=\"Provider\">\n {Object.keys(PROVIDERS).map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n )}\n </span>\n );\n\n const run = runPath !== undefined ? (\n <PlatformLink\n id={`${listId}-run`}\n className=\"omnibox-run\"\n path={runPath}\n aria-label=\"Run\"\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </PlatformLink>\n ) : (\n <button\n id={`${listId}-run`}\n type=\"button\"\n className=\"omnibox-run\"\n aria-disabled=\"true\"\n aria-describedby={`${helperId} ${noticeId}`}\n onClick={(e) => e.preventDefault()}\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </button>\n );\n\n const field = (\n <div className={`omnibox omnibox--${variant}`}>\n <div className=\"omnibox-row\">\n {chip}\n <input\n ref={inputRef}\n id={inputId}\n className=\"omnibox-input\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? listId : undefined}\n aria-activedescendant={highlight >= 0 ? options[highlight]?.id : undefined}\n aria-describedby={`${helperId} ${noticeId}`}\n aria-invalid={notice ? true : undefined}\n placeholder={isMobile ? 'Paste a repo or an app name' : 'owner/repo@branch, a GitHub URL, or an app name'}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {run}\n </div>\n <p className=\"omnibox-helper\" id={helperId}>\n {notice || helper}\n </p>\n {/* The live region announces the notice; empty in the common case. */}\n <p className=\"omnibox-visually-hidden\" id={noticeId} aria-live=\"polite\">\n {notice}\n </p>\n {panelOpen && (\n <div className=\"omnibox-panel\" id={listId} role=\"listbox\" aria-label=\"Results\">\n {hasResults ? (\n <>\n {locationRow && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Run from source\">\n <PlatformLink\n id={`${listId}-opt-location`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === 0}\n path={locationRow.presentPath}\n >\n <span className=\"omnibox-option-name\">{locationRow.display}</span>\n <span className=\"omnibox-option-action\">Run</span>\n </PlatformLink>\n </div>\n )}\n {appHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Apps in the directory\">\n {appHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);\n return (\n <PlatformLink\n key={hit.key}\n id={`${listId}-opt-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n path={hit.path}\n >\n <span className=\"omnibox-option-name\">{hit.name}</span>\n <span className=\"omnibox-option-cat\">{hit.category}</span>\n <span className=\"omnibox-option-blurb\">{hit.blurb}</span>\n {renderChip?.(hit)}\n </PlatformLink>\n );\n })}\n </div>\n )}\n {docHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Docs and tutorials\">\n {docHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);\n const anchorProps: DocAnchorProps = {\n id: `${listId}-opt-doc-${hit.key}`,\n className: 'omnibox-option',\n role: 'option',\n 'aria-selected': highlight === idx,\n };\n if (renderDoc) {\n return <Fragment key={hit.key}>{renderDoc(hit, anchorProps)}</Fragment>;\n }\n return (\n <a\n key={hit.key}\n id={`${listId}-opt-doc-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n href={hit.href}\n >\n <span className=\"omnibox-option-name\">{hit.title}</span>\n <span className=\"omnibox-option-blurb\">{hit.lead}</span>\n </a>\n );\n })}\n </div>\n )}\n </>\n ) : (\n <div className=\"omnibox-empty\">Nothing matched. Try an app name, or paste a repo.</div>\n )}\n </div>\n )}\n </div>\n );\n\n // The nav variant collapses to a shortcut button while the hero omnibox is\n // mounted (on `/`): activating it focuses the hero field. On every other\n // route the field expands in place.\n if (variant === 'nav' && heroShortcut) {\n return (\n <button\n type=\"button\"\n className=\"omnibox-nav-button\"\n onClick={() => focusHeroOmnibox()}\n aria-label=\"Search apps and docs, or paste a repo\"\n >\n <span className=\"omnibox-nav-button-label\">Search</span>\n <span className=\"kbd\">⌘K</span>\n </button>\n );\n }\n\n return (\n <div className={`omnibox-outer omnibox-outer--${variant}`} ref={outerRef}>\n <label className=\"omnibox-visually-hidden\" htmlFor={inputId}>\n Paste a repo, or search apps and docs\n </label>\n {field}\n </div>\n );\n}\n\nexport default Omnibox;\n"],"mappings":"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","names":["callSource"]}
@@ -9,6 +9,11 @@ interface AppHit {
9
9
  blurb: string;
10
10
  /** The repository the row opens — an org repo under immediately-run. */
11
11
  repo: string;
12
+ /** The PLATFORM path the row opens, e.g. `/present/github/immediately-run/todo/main/files/src/App.tsx`.
13
+ * Supplied by the consumer's `apps` source beside its own route builder, so the
14
+ * package carries no second spelling of any route family. Rendered through
15
+ * `PlatformLink` (host-space href, frame-escaping). */
16
+ path: string;
12
17
  /** Opaque to the package: a consumer's `renderChip` reads it back. */
13
18
  provenance?: unknown;
14
19
  }
@@ -18,6 +23,9 @@ interface DocHit {
18
23
  lead: string;
19
24
  /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */
20
25
  href: string;
26
+ /** The app-space route behind `href`, when the consumer renders the row through
27
+ * its own in-app link (`renderDoc`). Opaque to the package. */
28
+ to?: string;
21
29
  }
22
30
  /** The data seams. Absent sources simply yield no rows of their kind; an omnibox
23
31
  * with no `hits` at all is the launch grammar only (what the Home app renders). */
@@ -27,6 +35,13 @@ interface OmniboxHitSources {
27
35
  /** Matched doc hits for a query, best-first, capped by the source. */
28
36
  docs?: (query: string) => DocHit[];
29
37
  }
38
+ /** What a `renderDoc` anchor must spread: the combobox's option identity and state. */
39
+ interface DocAnchorProps {
40
+ id: string;
41
+ className: string;
42
+ role: 'option';
43
+ 'aria-selected': boolean;
44
+ }
30
45
  interface OmniboxProps {
31
46
  variant: OmniboxVariant;
32
47
  /** Nav variant only: true while the hero omnibox is mounted (`/`), so the
@@ -38,7 +53,14 @@ interface OmniboxProps {
38
53
  /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a
39
54
  * site component with site data types, so the package renders what it is given. */
40
55
  renderChip?: (hit: AppHit) => ReactNode;
56
+ /** Renders a doc ROW. `anchorProps` carries the combobox contract (the option's
57
+ * id, class, role and aria-selected) — spread them onto the anchor you render so
58
+ * the arrow-key highlight and the Enter walk keep working. The fallback is a
59
+ * plain `<a href>` — its href is real and resolvable, but on-host a plain click
60
+ * navigates the sandboxed FRAME to the target instead of routing the app, so a
61
+ * consumer with an in-app link (the landing page's SiteLink) should supply this. */
62
+ renderDoc?: (hit: DocHit, anchorProps: DocAnchorProps) => ReactNode;
41
63
  }
42
- declare function Omnibox({ variant, heroShortcut, hits, renderChip }: OmniboxProps): react.JSX.Element;
64
+ declare function Omnibox({ variant, heroShortcut, hits, renderChip, renderDoc }: OmniboxProps): react.JSX.Element;
43
65
 
44
- export { type AppHit, type DocHit, type OmniboxHitSources, type OmniboxProps, Omnibox as default };
66
+ export { type AppHit, type DocAnchorProps, type DocHit, type OmniboxHitSources, type OmniboxProps, Omnibox as default };
package/dist/Omnibox.d.ts CHANGED
@@ -9,6 +9,11 @@ interface AppHit {
9
9
  blurb: string;
10
10
  /** The repository the row opens — an org repo under immediately-run. */
11
11
  repo: string;
12
+ /** The PLATFORM path the row opens, e.g. `/present/github/immediately-run/todo/main/files/src/App.tsx`.
13
+ * Supplied by the consumer's `apps` source beside its own route builder, so the
14
+ * package carries no second spelling of any route family. Rendered through
15
+ * `PlatformLink` (host-space href, frame-escaping). */
16
+ path: string;
12
17
  /** Opaque to the package: a consumer's `renderChip` reads it back. */
13
18
  provenance?: unknown;
14
19
  }
@@ -18,6 +23,9 @@ interface DocHit {
18
23
  lead: string;
19
24
  /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */
20
25
  href: string;
26
+ /** The app-space route behind `href`, when the consumer renders the row through
27
+ * its own in-app link (`renderDoc`). Opaque to the package. */
28
+ to?: string;
21
29
  }
22
30
  /** The data seams. Absent sources simply yield no rows of their kind; an omnibox
23
31
  * with no `hits` at all is the launch grammar only (what the Home app renders). */
@@ -27,6 +35,13 @@ interface OmniboxHitSources {
27
35
  /** Matched doc hits for a query, best-first, capped by the source. */
28
36
  docs?: (query: string) => DocHit[];
29
37
  }
38
+ /** What a `renderDoc` anchor must spread: the combobox's option identity and state. */
39
+ interface DocAnchorProps {
40
+ id: string;
41
+ className: string;
42
+ role: 'option';
43
+ 'aria-selected': boolean;
44
+ }
30
45
  interface OmniboxProps {
31
46
  variant: OmniboxVariant;
32
47
  /** Nav variant only: true while the hero omnibox is mounted (`/`), so the
@@ -38,7 +53,14 @@ interface OmniboxProps {
38
53
  /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a
39
54
  * site component with site data types, so the package renders what it is given. */
40
55
  renderChip?: (hit: AppHit) => ReactNode;
56
+ /** Renders a doc ROW. `anchorProps` carries the combobox contract (the option's
57
+ * id, class, role and aria-selected) — spread them onto the anchor you render so
58
+ * the arrow-key highlight and the Enter walk keep working. The fallback is a
59
+ * plain `<a href>` — its href is real and resolvable, but on-host a plain click
60
+ * navigates the sandboxed FRAME to the target instead of routing the app, so a
61
+ * consumer with an in-app link (the landing page's SiteLink) should supply this. */
62
+ renderDoc?: (hit: DocHit, anchorProps: DocAnchorProps) => ReactNode;
41
63
  }
42
- declare function Omnibox({ variant, heroShortcut, hits, renderChip }: OmniboxProps): react.JSX.Element;
64
+ declare function Omnibox({ variant, heroShortcut, hits, renderChip, renderDoc }: OmniboxProps): react.JSX.Element;
43
65
 
44
- export { type AppHit, type DocHit, type OmniboxHitSources, type OmniboxProps, Omnibox as default };
66
+ export { type AppHit, type DocAnchorProps, type DocHit, type OmniboxHitSources, type OmniboxProps, Omnibox as default };
package/dist/Omnibox.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
2
+ import { Fragment as Fragment2, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
3
  import "./omnibox.css";
4
4
  import { parseLaunch, PROVIDERS } from "./launch";
5
5
  import { PlatformLink } from "@immediately-run/sdk/platformLink";
@@ -26,8 +26,7 @@ function appScore(hit, q) {
26
26
  if (hit.category.toLowerCase().includes(q)) return 0;
27
27
  return -1;
28
28
  }
29
- const appRoute = (repo) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;
30
- function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
29
+ function Omnibox({ variant, heroShortcut = false, hits, renderChip, renderDoc }) {
31
30
  const isMobile = useMediaQuery("(max-width: 720px)");
32
31
  const [query, setQuery] = useState("");
33
32
  const [highlight, setHighlight] = useState(-1);
@@ -45,7 +44,7 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
45
44
  } catch (error) {
46
45
  if (!warnedSources.current.has(kind)) {
47
46
  warnedSources.current.add(kind);
48
- console.warn(`omnibox: the "${String(kind)}" hit source threw and is disabled for this mount`, error);
47
+ console.warn(`omnibox: the "${String(kind)}" hit source threw; its rows are empty for this query`, error);
49
48
  }
50
49
  return [];
51
50
  }
@@ -202,7 +201,7 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
202
201
  className: "omnibox-option",
203
202
  role: "option",
204
203
  "aria-selected": highlight === idx,
205
- path: appRoute(hit.repo),
204
+ path: hit.path,
206
205
  children: [
207
206
  /* @__PURE__ */ jsx("span", { className: "omnibox-option-name", children: hit.name }),
208
207
  /* @__PURE__ */ jsx("span", { className: "omnibox-option-cat", children: hit.category }),
@@ -215,6 +214,15 @@ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
215
214
  }) }),
216
215
  docHits.length > 0 && /* @__PURE__ */ jsx("div", { className: "omnibox-group", role: "group", "aria-label": "Docs and tutorials", children: docHits.map((hit) => {
217
216
  const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);
217
+ const anchorProps = {
218
+ id: `${listId}-opt-doc-${hit.key}`,
219
+ className: "omnibox-option",
220
+ role: "option",
221
+ "aria-selected": highlight === idx
222
+ };
223
+ if (renderDoc) {
224
+ return /* @__PURE__ */ jsx(Fragment2, { children: renderDoc(hit, anchorProps) }, hit.key);
225
+ }
218
226
  return /* @__PURE__ */ jsxs(
219
227
  "a",
220
228
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Omnibox.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react';\nimport './omnibox.css';\nimport { parseLaunch, PROVIDERS, type Launch } from './launch';\nimport { PlatformLink } from '@immediately-run/sdk/platformLink';\nimport { focusHeroOmnibox, registerOmniboxFocus } from './omniboxFocus';\nimport type { OmniboxVariant } from './omniboxFocus';\n\n// The omnibox (R3-512; FRONT_DOOR_IA §5) — the front door's primary control. It\n// does W1 (run a repo by URL or tuple) and W2 (find an app) in one place, as a\n// WAI-ARIA list-autocomplete combobox with three result groups of ONE action per\n// row. Run and Open rows render through `PlatformLink`, which resolves the\n// host-space href and escapes the frame: a platform route navigates the HOST\n// document, and a root-relative href inside the sandboxed frame would resolve\n// against the sandbox origin and land nowhere.\n//\n// The package owns the component and the launch grammar; it owns NO data. The\n// app-directory and docs hit sources are injected per app (`hits`), because the\n// package cannot depend on a consumer's records (R3-530).\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia(query).matches\n : false,\n );\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(query);\n const onChange = () => setMatches(mq.matches);\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [query]);\n return matches;\n}\n\n/* ── the hit vocabulary a consumer's sources speak ──────────────────────── */\n\nexport interface AppHit {\n key: string;\n name: string;\n category: string;\n blurb: string;\n /** The repository the row opens — an org repo under immediately-run. */\n repo: string;\n /** Opaque to the package: a consumer's `renderChip` reads it back. */\n provenance?: unknown;\n}\n\nexport interface DocHit {\n key: string;\n title: string;\n lead: string;\n /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */\n href: string;\n}\n\n/** The data seams. Absent sources simply yield no rows of their kind; an omnibox\n * with no `hits` at all is the launch grammar only (what the Home app renders). */\nexport interface OmniboxHitSources {\n /** Candidate app hits for a query; the package ranks, filters and orders them. */\n apps?: (query: string) => AppHit[];\n /** Matched doc hits for a query, best-first, capped by the source. */\n docs?: (query: string) => DocHit[];\n}\n\n/* ── ranking ────────────────────────────────────────────────────────────── */\n\n/** name-prefix > name-substring > repo > blurb > category (FRONT_DOOR_IA §5.3).\n * Internal: the ranking is the package's policy, not part of the surface. */\nfunction appScore(hit: AppHit, q: string): number {\n if (hit.name.toLowerCase().startsWith(q)) return 4;\n if (hit.name.toLowerCase().includes(q)) return 3;\n if (hit.repo.toLowerCase().includes(q)) return 2;\n if (hit.blurb.toLowerCase().includes(q)) return 1;\n if (hit.category.toLowerCase().includes(q)) return 0;\n return -1;\n}\n\n/** The platform path an app row opens. The directory's apps are org repos that\n * open at their entry — the one shape an injected `apps` source feeds. */\nconst appRoute = (repo: string) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;\n\n/* ── the component ──────────────────────────────────────────────────────── */\n\nexport interface OmniboxProps {\n variant: OmniboxVariant;\n /** Nav variant only: true while the hero omnibox is mounted (`/`), so the\n * nav field renders as the shortcut that focuses it. Derived by the caller\n * from the route — render-time data, not an effect. */\n heroShortcut?: boolean;\n /** App-directory and docs hit sources. Absent → the launch grammar only. */\n hits?: OmniboxHitSources;\n /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a\n * site component with site data types, so the package renders what it is given. */\n renderChip?: (hit: AppHit) => ReactNode;\n}\n\nfunction Omnibox({ variant, heroShortcut = false, hits, renderChip }: OmniboxProps) {\n const isMobile = useMediaQuery('(max-width: 720px)');\n const [query, setQuery] = useState('');\n const [highlight, setHighlight] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const outerRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n const inputId = `${listId}-input`;\n const helperId = useId();\n const noticeId = useId();\n // A source that throws is degraded, not fatal: logged ONCE per source, then\n // that group stays empty — the location row still renders.\n const warnedSources = useRef<Set<keyof OmniboxHitSources>>(new Set());\n const callSource = useCallback(\n function callSource<K extends keyof OmniboxHitSources>(\n kind: K,\n source: OmniboxHitSources[K],\n q: string,\n ): ReturnType<NonNullable<OmniboxHitSources[K]>> | [] {\n try {\n return source!(q) as ReturnType<NonNullable<OmniboxHitSources[K]>>;\n } catch (error) {\n if (!warnedSources.current.has(kind)) {\n warnedSources.current.add(kind);\n console.warn(`omnibox: the \"${String(kind)}\" hit source threw and is disabled for this mount`, error);\n }\n return [];\n }\n },\n [],\n );\n\n const parsed: Launch = useMemo(() => parseLaunch(query), [query]);\n const runnable = parsed.kind === 'location' || parsed.kind === 'platform-url';\n const runPath =\n parsed.kind === 'location'\n ? parsed.presentPath\n : parsed.kind === 'platform-url'\n ? parsed.path\n : undefined;\n\n const panelOpen = query.trim() !== '';\n\n // Adjusting state during render (the sanctioned pattern): the highlight must\n // not survive the option set changing under it, and an effect would cascade.\n const [prevQuery, setPrevQuery] = useState(query);\n if (prevQuery !== query) {\n setPrevQuery(query);\n setHighlight(-1);\n }\n\n // Unknown provider → the notice replaces the helper line's text and is\n // announced through the live region.\n const notice =\n parsed.kind === 'unknown-provider'\n ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.`\n : '';\n\n const helper =\n variant === 'new' ? 'the repo you just created' : 'Accepts provider:namespace/repository@ref · GitHub is the first provider';\n\n const appHits = useMemo(() => {\n if (!panelOpen || !hits?.apps) return [];\n const q = query.trim().toLowerCase();\n return callSource('apps', hits.apps, q)\n .map((hit) => ({ hit, score: appScore(hit, q) }))\n .filter(({ score }) => score >= 0)\n .sort((a, b) => b.score - a.score)\n .map(({ hit }) => hit);\n }, [panelOpen, query, hits, callSource]);\n\n const docHits = useMemo(() => {\n if (!panelOpen || !hits?.docs) return [];\n return callSource('docs', hits.docs, query.trim().toLowerCase());\n }, [panelOpen, query, hits, callSource]);\n\n const locationRow = parsed.kind === 'location' ? parsed : undefined;\n const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;\n\n // Flattened options, in group order — the arrow-key walk and the highlight id\n // both read this list.\n const options = useMemo(() => {\n const list: { id: string; label: string }[] = [];\n if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });\n for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });\n for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });\n return list;\n }, [locationRow, appHits, docHits, listId]);\n\n // Register with the focus registry (⌘K, the nav shortcut and the \"paste a repo\"\n // CTAs all land here). `reveal` is what lets those CTAs scroll this field into\n // view without any component querying for its CSS class.\n useEffect(\n () =>\n registerOmniboxFocus(variant, {\n focus: () => inputRef.current?.focus(),\n reveal: () => outerRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }),\n }),\n [variant],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n if (!panelOpen || options.length === 0) return;\n e.preventDefault();\n setHighlight((h) => {\n if (h === -1) return e.key === 'ArrowDown' ? 0 : options.length - 1;\n return (h + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length;\n });\n return;\n }\n if (e.key === 'Enter') {\n if (highlight >= 0 && highlight < options.length) {\n e.preventDefault();\n document.getElementById(options[highlight].id)?.click();\n return;\n }\n if (runnable) {\n e.preventDefault();\n document.getElementById(`${listId}-run`)?.click();\n }\n return;\n }\n if (e.key === 'Escape') {\n // Close the panel, then clear the highlight, then blur — in that order.\n setQuery('');\n setHighlight(-1);\n inputRef.current?.blur();\n }\n },\n [panelOpen, options, highlight, runnable, listId],\n );\n\n const chip = (\n <span className=\"omnibox-chip\" aria-hidden={Object.keys(PROVIDERS).length === 1 || undefined}>\n {Object.keys(PROVIDERS).length === 1 ? (\n // One provider: a static label with no caret — NOT a dropdown of\n // providers that do not exist.\n <span className=\"omnibox-chip-label\">github</span>\n ) : (\n <select className=\"omnibox-chip-select\" aria-label=\"Provider\">\n {Object.keys(PROVIDERS).map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n )}\n </span>\n );\n\n const run = runPath !== undefined ? (\n <PlatformLink\n id={`${listId}-run`}\n className=\"omnibox-run\"\n path={runPath}\n aria-label=\"Run\"\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </PlatformLink>\n ) : (\n <button\n id={`${listId}-run`}\n type=\"button\"\n className=\"omnibox-run\"\n aria-disabled=\"true\"\n aria-describedby={`${helperId} ${noticeId}`}\n onClick={(e) => e.preventDefault()}\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </button>\n );\n\n const field = (\n <div className={`omnibox omnibox--${variant}`}>\n <div className=\"omnibox-row\">\n {chip}\n <input\n ref={inputRef}\n id={inputId}\n className=\"omnibox-input\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? listId : undefined}\n aria-activedescendant={highlight >= 0 ? options[highlight]?.id : undefined}\n aria-describedby={`${helperId} ${noticeId}`}\n aria-invalid={notice ? true : undefined}\n placeholder={isMobile ? 'Paste a repo or an app name' : 'owner/repo@branch, a GitHub URL, or an app name'}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {run}\n </div>\n <p className=\"omnibox-helper\" id={helperId}>\n {notice || helper}\n </p>\n {/* The live region announces the notice; empty in the common case. */}\n <p className=\"omnibox-visually-hidden\" id={noticeId} aria-live=\"polite\">\n {notice}\n </p>\n {panelOpen && (\n <div className=\"omnibox-panel\" id={listId} role=\"listbox\" aria-label=\"Results\">\n {hasResults ? (\n <>\n {locationRow && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Run from source\">\n <PlatformLink\n id={`${listId}-opt-location`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === 0}\n path={locationRow.presentPath}\n >\n <span className=\"omnibox-option-name\">{locationRow.display}</span>\n <span className=\"omnibox-option-action\">Run</span>\n </PlatformLink>\n </div>\n )}\n {appHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Apps in the directory\">\n {appHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);\n return (\n <PlatformLink\n key={hit.key}\n id={`${listId}-opt-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n path={appRoute(hit.repo)}\n >\n <span className=\"omnibox-option-name\">{hit.name}</span>\n <span className=\"omnibox-option-cat\">{hit.category}</span>\n <span className=\"omnibox-option-blurb\">{hit.blurb}</span>\n {renderChip?.(hit)}\n </PlatformLink>\n );\n })}\n </div>\n )}\n {docHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Docs and tutorials\">\n {docHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);\n return (\n <a\n key={hit.key}\n id={`${listId}-opt-doc-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n href={hit.href}\n >\n <span className=\"omnibox-option-name\">{hit.title}</span>\n <span className=\"omnibox-option-blurb\">{hit.lead}</span>\n </a>\n );\n })}\n </div>\n )}\n </>\n ) : (\n <div className=\"omnibox-empty\">Nothing matched. Try an app name, or paste a repo.</div>\n )}\n </div>\n )}\n </div>\n );\n\n // The nav variant collapses to a shortcut button while the hero omnibox is\n // mounted (on `/`): activating it focuses the hero field. On every other\n // route the field expands in place.\n if (variant === 'nav' && heroShortcut) {\n return (\n <button\n type=\"button\"\n className=\"omnibox-nav-button\"\n onClick={() => focusHeroOmnibox()}\n aria-label=\"Search apps and docs, or paste a repo\"\n >\n <span className=\"omnibox-nav-button-label\">Search</span>\n <span className=\"kbd\">⌘K</span>\n </button>\n );\n }\n\n return (\n <div className={`omnibox-outer omnibox-outer--${variant}`} ref={outerRef}>\n <label className=\"omnibox-visually-hidden\" htmlFor={inputId}>\n Paste a repo, or search apps and docs\n </label>\n {field}\n </div>\n );\n}\n\nexport default Omnibox;\n"],"mappings":"AA8OQ,SA0EI,UA1EJ,KAcJ,YAdI;AA9OR,SAAS,aAAa,WAAW,OAAO,SAAS,QAAQ,gBAAgB;AAEzE,OAAO;AACP,SAAS,aAAa,iBAA8B;AACpD,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB,4BAA4B;AAevD,SAAS,cAAc,OAAwB;AAC7C,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAS,MACrC,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,aAC1D,OAAO,WAAW,KAAK,EAAE,UACzB;AAAA,EACN;AACA,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY;AAC9E,UAAM,KAAK,OAAO,WAAW,KAAK;AAClC,UAAM,WAAW,MAAM,WAAW,GAAG,OAAO;AAC5C,aAAS;AACT,OAAG,iBAAiB,UAAU,QAAQ;AACtC,WAAO,MAAM,GAAG,oBAAoB,UAAU,QAAQ;AAAA,EACxD,GAAG,CAAC,KAAK,CAAC;AACV,SAAO;AACT;AAoCA,SAAS,SAAS,KAAa,GAAmB;AAChD,MAAI,IAAI,KAAK,YAAY,EAAE,WAAW,CAAC,EAAG,QAAO;AACjD,MAAI,IAAI,KAAK,YAAY,EAAE,SAAS,CAAC,EAAG,QAAO;AAC/C,MAAI,IAAI,KAAK,YAAY,EAAE,SAAS,CAAC,EAAG,QAAO;AAC/C,MAAI,IAAI,MAAM,YAAY,EAAE,SAAS,CAAC,EAAG,QAAO;AAChD,MAAI,IAAI,SAAS,YAAY,EAAE,SAAS,CAAC,EAAG,QAAO;AACnD,SAAO;AACT;AAIA,MAAM,WAAW,CAAC,SAAiB,mCAAmC,IAAI;AAiB1E,SAAS,QAAQ,EAAE,SAAS,eAAe,OAAO,MAAM,WAAW,GAAiB;AAClF,QAAM,WAAW,cAAc,oBAAoB;AACnD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,EAAE;AAC7C,QAAM,WAAW,OAAyB,IAAI;AAC9C,QAAM,WAAW,OAAuB,IAAI;AAC5C,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,GAAG,MAAM;AACzB,QAAM,WAAW,MAAM;AACvB,QAAM,WAAW,MAAM;AAGvB,QAAM,gBAAgB,OAAqC,oBAAI,IAAI,CAAC;AACpE,QAAM,aAAa;AAAA,IACjB,SAASA,YACP,MACA,QACA,GACoD;AACpD,UAAI;AACF,eAAO,OAAQ,CAAC;AAAA,MAClB,SAAS,OAAO;AACd,YAAI,CAAC,cAAc,QAAQ,IAAI,IAAI,GAAG;AACpC,wBAAc,QAAQ,IAAI,IAAI;AAC9B,kBAAQ,KAAK,iBAAiB,OAAO,IAAI,CAAC,qDAAqD,KAAK;AAAA,QACtG;AACA,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,SAAiB,QAAQ,MAAM,YAAY,KAAK,GAAG,CAAC,KAAK,CAAC;AAChE,QAAM,WAAW,OAAO,SAAS,cAAc,OAAO,SAAS;AAC/D,QAAM,UACJ,OAAO,SAAS,aACZ,OAAO,cACP,OAAO,SAAS,iBACd,OAAO,OACP;AAER,QAAM,YAAY,MAAM,KAAK,MAAM;AAInC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,MAAI,cAAc,OAAO;AACvB,iBAAa,KAAK;AAClB,iBAAa,EAAE;AAAA,EACjB;AAIA,QAAM,SACJ,OAAO,SAAS,qBACZ,GAAG,OAAO,SAAS,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG,OAAO,SAAS,MAAM,CAAC,CAAC,+CACrE;AAEN,QAAM,SACJ,YAAY,QAAQ,8BAA8B;AAEpD,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,CAAC,aAAa,CAAC,MAAM,KAAM,QAAO,CAAC;AACvC,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,WAAO,WAAW,QAAQ,KAAK,MAAM,CAAC,EACnC,IAAI,CAAC,SAAS,EAAE,KAAK,OAAO,SAAS,KAAK,CAAC,EAAE,EAAE,EAC/C,OAAO,CAAC,EAAE,MAAM,MAAM,SAAS,CAAC,EAChC,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AAAA,EACzB,GAAG,CAAC,WAAW,OAAO,MAAM,UAAU,CAAC;AAEvC,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,CAAC,aAAa,CAAC,MAAM,KAAM,QAAO,CAAC;AACvC,WAAO,WAAW,QAAQ,KAAK,MAAM,MAAM,KAAK,EAAE,YAAY,CAAC;AAAA,EACjE,GAAG,CAAC,WAAW,OAAO,MAAM,UAAU,CAAC;AAEvC,QAAM,cAAc,OAAO,SAAS,aAAa,SAAS;AAC1D,QAAM,aAAa,QAAQ,WAAW,KAAK,QAAQ,SAAS,KAAK,QAAQ,SAAS;AAIlF,QAAM,UAAU,QAAQ,MAAM;AAC5B,UAAM,OAAwC,CAAC;AAC/C,QAAI,YAAa,MAAK,KAAK,EAAE,IAAI,GAAG,MAAM,iBAAiB,OAAO,YAAY,QAAQ,CAAC;AACvF,eAAW,OAAO,QAAS,MAAK,KAAK,EAAE,IAAI,GAAG,MAAM,QAAQ,IAAI,GAAG,IAAI,OAAO,IAAI,KAAK,CAAC;AACxF,eAAW,OAAO,QAAS,MAAK,KAAK,EAAE,IAAI,GAAG,MAAM,YAAY,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM,CAAC;AAC7F,WAAO;AAAA,EACT,GAAG,CAAC,aAAa,SAAS,SAAS,MAAM,CAAC;AAK1C;AAAA,IACE,MACE,qBAAqB,SAAS;AAAA,MAC5B,OAAO,MAAM,SAAS,SAAS,MAAM;AAAA,MACrC,QAAQ,MAAM,SAAS,SAAS,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS,CAAC;AAAA,IACxF,CAAC;AAAA,IACH,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,YAAY;AAAA,IAChB,CAAC,MAA4C;AAC3C,UAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,WAAW;AAChD,YAAI,CAAC,aAAa,QAAQ,WAAW,EAAG;AACxC,UAAE,eAAe;AACjB,qBAAa,CAAC,MAAM;AAClB,cAAI,MAAM,GAAI,QAAO,EAAE,QAAQ,cAAc,IAAI,QAAQ,SAAS;AAClE,kBAAQ,KAAK,EAAE,QAAQ,cAAc,IAAI,MAAM,QAAQ,UAAU,QAAQ;AAAA,QAC3E,CAAC;AACD;AAAA,MACF;AACA,UAAI,EAAE,QAAQ,SAAS;AACrB,YAAI,aAAa,KAAK,YAAY,QAAQ,QAAQ;AAChD,YAAE,eAAe;AACjB,mBAAS,eAAe,QAAQ,SAAS,EAAE,EAAE,GAAG,MAAM;AACtD;AAAA,QACF;AACA,YAAI,UAAU;AACZ,YAAE,eAAe;AACjB,mBAAS,eAAe,GAAG,MAAM,MAAM,GAAG,MAAM;AAAA,QAClD;AACA;AAAA,MACF;AACA,UAAI,EAAE,QAAQ,UAAU;AAEtB,iBAAS,EAAE;AACX,qBAAa,EAAE;AACf,iBAAS,SAAS,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,IACA,CAAC,WAAW,SAAS,WAAW,UAAU,MAAM;AAAA,EAClD;AAEA,QAAM,OACJ,oBAAC,UAAK,WAAU,gBAAe,eAAa,OAAO,KAAK,SAAS,EAAE,WAAW,KAAK,QAChF,iBAAO,KAAK,SAAS,EAAE,WAAW;AAAA;AAAA;AAAA,IAGjC,oBAAC,UAAK,WAAU,sBAAqB,oBAAM;AAAA,MAE3C,oBAAC,YAAO,WAAU,uBAAsB,cAAW,YAChD,iBAAO,KAAK,SAAS,EAAE,IAAI,CAAC,MAC3B,oBAAC,YAAe,OAAO,GACpB,eADU,CAEb,CACD,GACH,GAEJ;AAGF,QAAM,MAAM,YAAY,SACtB;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,GAAG,MAAM;AAAA,MACb,WAAU;AAAA,MACV,MAAM;AAAA,MACN,cAAW;AAAA,MAEX;AAAA,4BAAC,UAAK,WAAU,qBAAoB,iBAAG;AAAA,QACvC,oBAAC,UAAK,WAAU,qBAAoB,eAAY,QAAO,oBAEvD;AAAA;AAAA;AAAA,EACF,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,GAAG,MAAM;AAAA,MACb,MAAK;AAAA,MACL,WAAU;AAAA,MACV,iBAAc;AAAA,MACd,oBAAkB,GAAG,QAAQ,IAAI,QAAQ;AAAA,MACzC,SAAS,CAAC,MAAM,EAAE,eAAe;AAAA,MAEjC;AAAA,4BAAC,UAAK,WAAU,qBAAoB,iBAAG;AAAA,QACvC,oBAAC,UAAK,WAAU,qBAAoB,eAAY,QAAO,oBAEvD;AAAA;AAAA;AAAA,EACF;AAGF,QAAM,QACJ,qBAAC,SAAI,WAAW,oBAAoB,OAAO,IACzC;AAAA,yBAAC,SAAI,WAAU,eACZ;AAAA;AAAA,MACD;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,IAAI;AAAA,UACJ,WAAU;AAAA,UACV,MAAK;AAAA,UACL,MAAK;AAAA,UACL,qBAAkB;AAAA,UAClB,iBAAe;AAAA,UACf,iBAAe,YAAY,SAAS;AAAA,UACpC,yBAAuB,aAAa,IAAI,QAAQ,SAAS,GAAG,KAAK;AAAA,UACjE,oBAAkB,GAAG,QAAQ,IAAI,QAAQ;AAAA,UACzC,gBAAc,SAAS,OAAO;AAAA,UAC9B,aAAa,WAAW,gCAAgC;AAAA,UACxD,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,UACxC;AAAA;AAAA,MACF;AAAA,MACC;AAAA,OACH;AAAA,IACA,oBAAC,OAAE,WAAU,kBAAiB,IAAI,UAC/B,oBAAU,QACb;AAAA,IAEA,oBAAC,OAAE,WAAU,2BAA0B,IAAI,UAAU,aAAU,UAC5D,kBACH;AAAA,IACC,aACC,oBAAC,SAAI,WAAU,iBAAgB,IAAI,QAAQ,MAAK,WAAU,cAAW,WAClE,uBACC,iCACG;AAAA,qBACC,oBAAC,SAAI,WAAU,iBAAgB,MAAK,SAAQ,cAAW,mBACrD;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,GAAG,MAAM;AAAA,UACb,WAAU;AAAA,UACV,MAAK;AAAA,UACL,iBAAe,cAAc;AAAA,UAC7B,MAAM,YAAY;AAAA,UAElB;AAAA,gCAAC,UAAK,WAAU,uBAAuB,sBAAY,SAAQ;AAAA,YAC3D,oBAAC,UAAK,WAAU,yBAAwB,iBAAG;AAAA;AAAA;AAAA,MAC7C,GACF;AAAA,MAED,QAAQ,SAAS,KAChB,oBAAC,SAAI,WAAU,iBAAgB,MAAK,SAAQ,cAAW,yBACpD,kBAAQ,IAAI,CAAC,QAAQ;AACpB,cAAM,MAAM,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,QAAQ,IAAI,GAAG,EAAE;AACxE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,IAAI,GAAG,MAAM,QAAQ,IAAI,GAAG;AAAA,YAC5B,WAAU;AAAA,YACV,MAAK;AAAA,YACL,iBAAe,cAAc;AAAA,YAC7B,MAAM,SAAS,IAAI,IAAI;AAAA,YAEvB;AAAA,kCAAC,UAAK,WAAU,uBAAuB,cAAI,MAAK;AAAA,cAChD,oBAAC,UAAK,WAAU,sBAAsB,cAAI,UAAS;AAAA,cACnD,oBAAC,UAAK,WAAU,wBAAwB,cAAI,OAAM;AAAA,cACjD,aAAa,GAAG;AAAA;AAAA;AAAA,UAVZ,IAAI;AAAA,QAWX;AAAA,MAEJ,CAAC,GACH;AAAA,MAED,QAAQ,SAAS,KAChB,oBAAC,SAAI,WAAU,iBAAgB,MAAK,SAAQ,cAAW,sBACpD,kBAAQ,IAAI,CAAC,QAAQ;AACpB,cAAM,MAAM,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,YAAY,IAAI,GAAG,EAAE;AAC5E,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,IAAI,GAAG,MAAM,YAAY,IAAI,GAAG;AAAA,YAChC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,iBAAe,cAAc;AAAA,YAC7B,MAAM,IAAI;AAAA,YAEV;AAAA,kCAAC,UAAK,WAAU,uBAAuB,cAAI,OAAM;AAAA,cACjD,oBAAC,UAAK,WAAU,wBAAwB,cAAI,MAAK;AAAA;AAAA;AAAA,UAR5C,IAAI;AAAA,QASX;AAAA,MAEJ,CAAC,GACH;AAAA,OAEJ,IAEA,oBAAC,SAAI,WAAU,iBAAgB,gEAAkD,GAErF;AAAA,KAEJ;AAMF,MAAI,YAAY,SAAS,cAAc;AACrC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,iBAAiB;AAAA,QAChC,cAAW;AAAA,QAEX;AAAA,8BAAC,UAAK,WAAU,4BAA2B,oBAAM;AAAA,UACjD,oBAAC,UAAK,WAAU,OAAM,qBAAE;AAAA;AAAA;AAAA,IAC1B;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,gCAAgC,OAAO,IAAI,KAAK,UAC9D;AAAA,wBAAC,WAAM,WAAU,2BAA0B,SAAS,SAAS,mDAE7D;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,IAAO,kBAAQ;","names":["callSource"]}
1
+ {"version":3,"sources":["../src/Omnibox.tsx"],"sourcesContent":["import { Fragment, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react';\nimport './omnibox.css';\nimport { parseLaunch, PROVIDERS, type Launch } from './launch';\nimport { PlatformLink } from '@immediately-run/sdk/platformLink';\nimport { focusHeroOmnibox, registerOmniboxFocus } from './omniboxFocus';\nimport type { OmniboxVariant } from './omniboxFocus';\n\n// The omnibox (R3-512; FRONT_DOOR_IA §5) — the front door's primary control. It\n// does W1 (run a repo by URL or tuple) and W2 (find an app) in one place, as a\n// WAI-ARIA list-autocomplete combobox with three result groups of ONE action per\n// row. Run and Open rows render through `PlatformLink`, which resolves the\n// host-space href and escapes the frame: a platform route navigates the HOST\n// document, and a root-relative href inside the sandboxed frame would resolve\n// against the sandbox origin and land nowhere.\n//\n// The package owns the component and the launch grammar; it owns NO data. The\n// app-directory and docs hit sources are injected per app (`hits`), because the\n// package cannot depend on a consumer's records (R3-530).\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia(query).matches\n : false,\n );\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(query);\n const onChange = () => setMatches(mq.matches);\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [query]);\n return matches;\n}\n\n/* ── the hit vocabulary a consumer's sources speak ──────────────────────── */\n\nexport interface AppHit {\n key: string;\n name: string;\n category: string;\n blurb: string;\n /** The repository the row opens — an org repo under immediately-run. */\n repo: string;\n /** The PLATFORM path the row opens, e.g. `/present/github/immediately-run/todo/main/files/src/App.tsx`.\n * Supplied by the consumer's `apps` source beside its own route builder, so the\n * package carries no second spelling of any route family. Rendered through\n * `PlatformLink` (host-space href, frame-escaping). */\n path: string;\n /** Opaque to the package: a consumer's `renderChip` reads it back. */\n provenance?: unknown;\n}\n\nexport interface DocHit {\n key: string;\n title: string;\n lead: string;\n /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */\n href: string;\n /** The app-space route behind `href`, when the consumer renders the row through\n * its own in-app link (`renderDoc`). Opaque to the package. */\n to?: string;\n}\n\n/** The data seams. Absent sources simply yield no rows of their kind; an omnibox\n * with no `hits` at all is the launch grammar only (what the Home app renders). */\nexport interface OmniboxHitSources {\n /** Candidate app hits for a query; the package ranks, filters and orders them. */\n apps?: (query: string) => AppHit[];\n /** Matched doc hits for a query, best-first, capped by the source. */\n docs?: (query: string) => DocHit[];\n}\n\n/* ── ranking ────────────────────────────────────────────────────────────── */\n\n/** name-prefix > name-substring > repo > blurb > category (FRONT_DOOR_IA §5.3).\n * Internal: the ranking is the package's policy, not part of the surface. */\nfunction appScore(hit: AppHit, q: string): number {\n if (hit.name.toLowerCase().startsWith(q)) return 4;\n if (hit.name.toLowerCase().includes(q)) return 3;\n if (hit.repo.toLowerCase().includes(q)) return 2;\n if (hit.blurb.toLowerCase().includes(q)) return 1;\n if (hit.category.toLowerCase().includes(q)) return 0;\n return -1;\n}\n\n/* ── the component ──────────────────────────────────────────────────────── */\n\n/** What a `renderDoc` anchor must spread: the combobox's option identity and state. */\nexport interface DocAnchorProps {\n id: string;\n className: string;\n role: 'option';\n 'aria-selected': boolean;\n}\n\nexport interface OmniboxProps {\n variant: OmniboxVariant;\n /** Nav variant only: true while the hero omnibox is mounted (`/`), so the\n * nav field renders as the shortcut that focuses it. Derived by the caller\n * from the route — render-time data, not an effect. */\n heroShortcut?: boolean;\n /** App-directory and docs hit sources. Absent → the launch grammar only. */\n hits?: OmniboxHitSources;\n /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a\n * site component with site data types, so the package renders what it is given. */\n renderChip?: (hit: AppHit) => ReactNode;\n /** Renders a doc ROW. `anchorProps` carries the combobox contract (the option's\n * id, class, role and aria-selected) — spread them onto the anchor you render so\n * the arrow-key highlight and the Enter walk keep working. The fallback is a\n * plain `<a href>` — its href is real and resolvable, but on-host a plain click\n * navigates the sandboxed FRAME to the target instead of routing the app, so a\n * consumer with an in-app link (the landing page's SiteLink) should supply this. */\n renderDoc?: (hit: DocHit, anchorProps: DocAnchorProps) => ReactNode;\n}\n\nfunction Omnibox({ variant, heroShortcut = false, hits, renderChip, renderDoc }: OmniboxProps) {\n const isMobile = useMediaQuery('(max-width: 720px)');\n const [query, setQuery] = useState('');\n const [highlight, setHighlight] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const outerRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n const inputId = `${listId}-input`;\n const helperId = useId();\n const noticeId = useId();\n // A source that throws is degraded, not fatal: that query's group stays empty\n // and the location row still renders. The source is called again on the next\n // keystroke — a transient throw recovers silently; only the LOG is once.\n const warnedSources = useRef<Set<keyof OmniboxHitSources>>(new Set());\n const callSource = useCallback(\n function callSource<K extends keyof OmniboxHitSources>(\n kind: K,\n source: OmniboxHitSources[K],\n q: string,\n ): ReturnType<NonNullable<OmniboxHitSources[K]>> | [] {\n try {\n return source!(q) as ReturnType<NonNullable<OmniboxHitSources[K]>>;\n } catch (error) {\n if (!warnedSources.current.has(kind)) {\n warnedSources.current.add(kind);\n console.warn(`omnibox: the \"${String(kind)}\" hit source threw; its rows are empty for this query`, error);\n }\n return [];\n }\n },\n [],\n );\n\n const parsed: Launch = useMemo(() => parseLaunch(query), [query]);\n const runnable = parsed.kind === 'location' || parsed.kind === 'platform-url';\n const runPath =\n parsed.kind === 'location'\n ? parsed.presentPath\n : parsed.kind === 'platform-url'\n ? parsed.path\n : undefined;\n\n const panelOpen = query.trim() !== '';\n\n // Adjusting state during render (the sanctioned pattern): the highlight must\n // not survive the option set changing under it, and an effect would cascade.\n const [prevQuery, setPrevQuery] = useState(query);\n if (prevQuery !== query) {\n setPrevQuery(query);\n setHighlight(-1);\n }\n\n // Unknown provider → the notice replaces the helper line's text and is\n // announced through the live region.\n const notice =\n parsed.kind === 'unknown-provider'\n ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.`\n : '';\n\n const helper =\n variant === 'new' ? 'the repo you just created' : 'Accepts provider:namespace/repository@ref · GitHub is the first provider';\n\n const appHits = useMemo(() => {\n if (!panelOpen || !hits?.apps) return [];\n const q = query.trim().toLowerCase();\n return callSource('apps', hits.apps, q)\n .map((hit) => ({ hit, score: appScore(hit, q) }))\n .filter(({ score }) => score >= 0)\n .sort((a, b) => b.score - a.score)\n .map(({ hit }) => hit);\n }, [panelOpen, query, hits, callSource]);\n\n const docHits = useMemo(() => {\n if (!panelOpen || !hits?.docs) return [];\n return callSource('docs', hits.docs, query.trim().toLowerCase());\n }, [panelOpen, query, hits, callSource]);\n\n const locationRow = parsed.kind === 'location' ? parsed : undefined;\n const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;\n\n // Flattened options, in group order — the arrow-key walk and the highlight id\n // both read this list.\n const options = useMemo(() => {\n const list: { id: string; label: string }[] = [];\n if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });\n for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });\n for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });\n return list;\n }, [locationRow, appHits, docHits, listId]);\n\n // Register with the focus registry (⌘K, the nav shortcut and the \"paste a repo\"\n // CTAs all land here). `reveal` is what lets those CTAs scroll this field into\n // view without any component querying for its CSS class.\n useEffect(\n () =>\n registerOmniboxFocus(variant, {\n focus: () => inputRef.current?.focus(),\n reveal: () => outerRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }),\n }),\n [variant],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n if (!panelOpen || options.length === 0) return;\n e.preventDefault();\n setHighlight((h) => {\n if (h === -1) return e.key === 'ArrowDown' ? 0 : options.length - 1;\n return (h + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length;\n });\n return;\n }\n if (e.key === 'Enter') {\n if (highlight >= 0 && highlight < options.length) {\n e.preventDefault();\n document.getElementById(options[highlight].id)?.click();\n return;\n }\n if (runnable) {\n e.preventDefault();\n document.getElementById(`${listId}-run`)?.click();\n }\n return;\n }\n if (e.key === 'Escape') {\n // Close the panel, then clear the highlight, then blur — in that order.\n setQuery('');\n setHighlight(-1);\n inputRef.current?.blur();\n }\n },\n [panelOpen, options, highlight, runnable, listId],\n );\n\n const chip = (\n <span className=\"omnibox-chip\" aria-hidden={Object.keys(PROVIDERS).length === 1 || undefined}>\n {Object.keys(PROVIDERS).length === 1 ? (\n // One provider: a static label with no caret — NOT a dropdown of\n // providers that do not exist.\n <span className=\"omnibox-chip-label\">github</span>\n ) : (\n <select className=\"omnibox-chip-select\" aria-label=\"Provider\">\n {Object.keys(PROVIDERS).map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n )}\n </span>\n );\n\n const run = runPath !== undefined ? (\n <PlatformLink\n id={`${listId}-run`}\n className=\"omnibox-run\"\n path={runPath}\n aria-label=\"Run\"\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </PlatformLink>\n ) : (\n <button\n id={`${listId}-run`}\n type=\"button\"\n className=\"omnibox-run\"\n aria-disabled=\"true\"\n aria-describedby={`${helperId} ${noticeId}`}\n onClick={(e) => e.preventDefault()}\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </button>\n );\n\n const field = (\n <div className={`omnibox omnibox--${variant}`}>\n <div className=\"omnibox-row\">\n {chip}\n <input\n ref={inputRef}\n id={inputId}\n className=\"omnibox-input\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? listId : undefined}\n aria-activedescendant={highlight >= 0 ? options[highlight]?.id : undefined}\n aria-describedby={`${helperId} ${noticeId}`}\n aria-invalid={notice ? true : undefined}\n placeholder={isMobile ? 'Paste a repo or an app name' : 'owner/repo@branch, a GitHub URL, or an app name'}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {run}\n </div>\n <p className=\"omnibox-helper\" id={helperId}>\n {notice || helper}\n </p>\n {/* The live region announces the notice; empty in the common case. */}\n <p className=\"omnibox-visually-hidden\" id={noticeId} aria-live=\"polite\">\n {notice}\n </p>\n {panelOpen && (\n <div className=\"omnibox-panel\" id={listId} role=\"listbox\" aria-label=\"Results\">\n {hasResults ? (\n <>\n {locationRow && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Run from source\">\n <PlatformLink\n id={`${listId}-opt-location`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === 0}\n path={locationRow.presentPath}\n >\n <span className=\"omnibox-option-name\">{locationRow.display}</span>\n <span className=\"omnibox-option-action\">Run</span>\n </PlatformLink>\n </div>\n )}\n {appHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Apps in the directory\">\n {appHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);\n return (\n <PlatformLink\n key={hit.key}\n id={`${listId}-opt-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n path={hit.path}\n >\n <span className=\"omnibox-option-name\">{hit.name}</span>\n <span className=\"omnibox-option-cat\">{hit.category}</span>\n <span className=\"omnibox-option-blurb\">{hit.blurb}</span>\n {renderChip?.(hit)}\n </PlatformLink>\n );\n })}\n </div>\n )}\n {docHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Docs and tutorials\">\n {docHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);\n const anchorProps: DocAnchorProps = {\n id: `${listId}-opt-doc-${hit.key}`,\n className: 'omnibox-option',\n role: 'option',\n 'aria-selected': highlight === idx,\n };\n if (renderDoc) {\n return <Fragment key={hit.key}>{renderDoc(hit, anchorProps)}</Fragment>;\n }\n return (\n <a\n key={hit.key}\n id={`${listId}-opt-doc-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n href={hit.href}\n >\n <span className=\"omnibox-option-name\">{hit.title}</span>\n <span className=\"omnibox-option-blurb\">{hit.lead}</span>\n </a>\n );\n })}\n </div>\n )}\n </>\n ) : (\n <div className=\"omnibox-empty\">Nothing matched. Try an app name, or paste a repo.</div>\n )}\n </div>\n )}\n </div>\n );\n\n // The nav variant collapses to a shortcut button while the hero omnibox is\n // mounted (on `/`): activating it focuses the hero field. On every other\n // route the field expands in place.\n if (variant === 'nav' && heroShortcut) {\n return (\n <button\n type=\"button\"\n className=\"omnibox-nav-button\"\n onClick={() => focusHeroOmnibox()}\n aria-label=\"Search apps and docs, or paste a repo\"\n >\n <span className=\"omnibox-nav-button-label\">Search</span>\n <span className=\"kbd\">⌘K</span>\n </button>\n );\n }\n\n return (\n <div className={`omnibox-outer omnibox-outer--${variant}`} ref={outerRef}>\n <label className=\"omnibox-visually-hidden\" htmlFor={inputId}>\n Paste a repo, or search apps and docs\n </label>\n {field}\n </div>\n );\n}\n\nexport default Omnibox;\n"],"mappings":"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","names":["Fragment","callSource"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAmC;AAEnC,oBAAuC;AAEvC,0BAAwF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit, DocAnchorProps } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAmC;AAEnC,oBAAuC;AAEvC,0BAAwF;","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { AppHit, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.cjs';
1
+ export { AppHit, DocAnchorProps, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.cjs';
2
2
  export { Launch, PROVIDERS, parseLaunch } from './launch.cjs';
3
3
  export { OmniboxHandle, OmniboxVariant, focusHeroOmnibox, focusOmnibox, registerOmniboxFocus, revealHeroOmnibox } from './omniboxFocus.cjs';
4
4
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { AppHit, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.js';
1
+ export { AppHit, DocAnchorProps, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.js';
2
2
  export { Launch, PROVIDERS, parseLaunch } from './launch.js';
3
3
  export { OmniboxHandle, OmniboxVariant, focusHeroOmnibox, focusOmnibox, registerOmniboxFocus, revealHeroOmnibox } from './omniboxFocus.js';
4
4
  import 'react';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":"AAAA,SAAoB,WAAXA,gBAA0B;AAEnC,SAAS,aAAa,iBAAiB;AAEvC,SAAS,kBAAkB,mBAAmB,cAAc,4BAA4B;","names":["default"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit, DocAnchorProps } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":"AAAA,SAAoB,WAAXA,gBAA0B;AAEnC,SAAS,aAAa,iBAAiB;AAEvC,SAAS,kBAAkB,mBAAmB,cAAc,4BAA4B;","names":["default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immediately-run/omnibox",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The front door's omnibox: one list-autocomplete combobox that runs a repo by URL or tuple and searches a consumer's app directory and docs (the launch grammar always; the hit sources injected). Shared by landing-page and the Home app so there is one component and one grammar (R3-512, R3-530).",
5
5
  "license": "MIT",
6
6
  "repository": {