@publish.os/nextjs 0.0.1-alpha.81 → 0.0.1-alpha.91

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.
Files changed (265) hide show
  1. package/compiler-assets/nextjs/defaults/app/globals.css +1 -0
  2. package/compiler-assets/nextjs/defaults/group/index.tsx +50 -0
  3. package/compiler-assets/nextjs/defaults/group/layout.tsx +8 -8
  4. package/compiler-assets/nextjs/defaults/group/page.tsx +44 -43
  5. package/compiler-assets/nextjs/defaults/project/next.config.mjs +33 -13
  6. package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -3
  7. package/compiler-assets/nextjs/defaults/root/css/animation.css +131 -0
  8. package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
  9. package/compiler-assets/nextjs/defaults/root/css/components/dialog.css +4 -1
  10. package/compiler-assets/nextjs/defaults/root/css/components/menu.css +1 -1
  11. package/compiler-assets/nextjs/defaults/root/css/components/navigation-menu.css +1 -1
  12. package/compiler-assets/nextjs/defaults/root/css/components/popover.css +1 -1
  13. package/compiler-assets/nextjs/defaults/root/css/components/select.css +1 -1
  14. package/compiler-assets/nextjs/defaults/root/css/components/tooltip.css +1 -1
  15. package/compiler-assets/nextjs/defaults/root/css/shadow.css +6 -25
  16. package/compiler-assets/nextjs/defaults/root/css/typography.css +51 -68
  17. package/compiler-assets/nextjs/defaults/root/globals.css +25 -0
  18. package/compiler-assets/nextjs/defaults/root/{page.tsx → index.tsx} +6 -2
  19. package/compiler-assets/nextjs/defaults/root/layout.tsx +7 -1
  20. package/compiler-assets/nextjs/defaults/root/theme.css +22 -22
  21. package/compiler-assets/nextjs/shims/document.tsx +38 -0
  22. package/compiler-assets/nextjs/shims/generated-group-page.tsx +19 -2
  23. package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +18 -2
  24. package/compiler-assets/nextjs/shims/global-layout.tsx +19 -85
  25. package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
  26. package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
  27. package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
  28. package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
  29. package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
  30. package/compiler-assets/nextjs/shims/proxy.ts +143 -65
  31. package/compiler-assets/nextjs/shims/publish-os-theme-provider.tsx +76 -15
  32. package/compiler-assets/nextjs/shims/root-page.tsx +7 -1
  33. package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +30 -0
  34. package/compiler-assets/nextjs/shims/site-heading-level.tsx +14 -0
  35. package/compiler-assets/nextjs/shims/site-mdx-components.tsx +112 -0
  36. package/compiler-assets/nextjs/shims/site-mdx.tsx +17 -0
  37. package/compiler-assets/nextjs/shims/theme-defaults.css +41 -25
  38. package/dist/build-operation-5QMLXF7N.js +89 -0
  39. package/dist/{button-CFdx-ohV.d.ts → button-BdCScEKi.d.ts} +6 -6
  40. package/dist/capture-local-source-WGGDIUU2.js +258 -0
  41. package/dist/chunk-22RSSUNV.js +13 -0
  42. package/dist/chunk-4BC2L2KA.js +620 -0
  43. package/dist/chunk-5J3YUNRY.js +121 -0
  44. package/dist/chunk-5KAD7W53.js +248 -0
  45. package/dist/chunk-6C65KV7O.js +142 -0
  46. package/dist/chunk-6D2E6UMD.js +695 -0
  47. package/dist/chunk-7NY22B5U.js +161 -0
  48. package/dist/chunk-AI2UULNX.js +9 -0
  49. package/dist/chunk-EFO6AWXN.js +19 -0
  50. package/dist/chunk-F3AGNDF4.js +2377 -0
  51. package/dist/chunk-GBPLER5H.js +426 -0
  52. package/dist/chunk-IL4RJOKI.js +186 -0
  53. package/dist/chunk-NNBJZPFM.js +193 -0
  54. package/dist/chunk-ORIUWJBQ.js +58 -0
  55. package/dist/chunk-OXOFRXEI.js +7129 -0
  56. package/dist/chunk-UYGCOWRF.js +1709 -0
  57. package/dist/chunk-WL75GQ5M.js +80 -0
  58. package/dist/compiler.d.ts +54 -7
  59. package/dist/compiler.js +121 -13147
  60. package/dist/components/blocks/agent-actions.d.ts +81 -0
  61. package/dist/components/blocks/agent-actions.js +594 -0
  62. package/dist/components/blocks/toc.d.ts +43 -0
  63. package/dist/components/blocks/toc.js +136 -0
  64. package/dist/components/ui/button.d.ts +5 -0
  65. package/dist/components/ui/button.js +94 -0
  66. package/dist/compose-CVBJRAF6.js +16 -0
  67. package/dist/config/createNextConfig.js +27 -0
  68. package/dist/dev-operation-OSHHWRWK.js +1095 -0
  69. package/dist/framework-selection-ZVO323PK.js +11 -0
  70. package/dist/ide-support-CU6Z5PVR.js +16 -0
  71. package/dist/index.d.ts +55 -4
  72. package/dist/jsx-dev-runtime.d.ts +6 -0
  73. package/dist/jsx-dev-runtime.js +100 -0
  74. package/dist/jsx-runtime.d.ts +7 -0
  75. package/dist/jsx-runtime.js +97 -0
  76. package/dist/kernel/components/blocks/AgentActions.d.ts +35 -6
  77. package/dist/kernel/components/blocks/AgentActions.js +401 -150
  78. package/dist/kernel/components/blocks/agent-actions.d.ts +5 -0
  79. package/dist/kernel/components/blocks/agent-actions.js +594 -0
  80. package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
  81. package/dist/kernel/components/blocks/color-palette.js +4 -4
  82. package/dist/kernel/components/blocks/logo-block.js +3 -3
  83. package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +10 -2
  84. package/dist/kernel/components/blocks/nav-breadcrumb.js +22 -7
  85. package/dist/kernel/components/blocks/navbar.d.ts +2 -2
  86. package/dist/kernel/components/blocks/navbar.js +406 -65
  87. package/dist/kernel/components/blocks/navigation-progress.js +6 -3
  88. package/dist/kernel/components/blocks/next-prev.d.ts +1 -1
  89. package/dist/kernel/components/blocks/next-prev.js +12 -24
  90. package/dist/kernel/components/blocks/page-list.d.ts +1 -1
  91. package/dist/kernel/components/blocks/page-list.js +7 -6
  92. package/dist/kernel/components/blocks/search.d.ts +83 -58
  93. package/dist/kernel/components/blocks/search.js +554 -428
  94. package/dist/kernel/components/blocks/sidebar-node.d.ts +2 -2
  95. package/dist/kernel/components/blocks/sidebar-node.js +12 -10
  96. package/dist/kernel/components/blocks/sidebar.d.ts +3 -3
  97. package/dist/kernel/components/blocks/sidebar.js +24 -14
  98. package/dist/kernel/components/blocks/theme-toggle.d.ts +2 -2
  99. package/dist/kernel/components/blocks/theme-toggle.js +47 -1
  100. package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
  101. package/dist/kernel/components/blocks/toc-client.js +495 -0
  102. package/dist/kernel/components/blocks/toc.d.ts +19 -1
  103. package/dist/kernel/components/blocks/toc.js +122 -180
  104. package/dist/kernel/components/mdx/components/blockquote.js +2 -2
  105. package/dist/kernel/components/mdx/components/callout.d.ts +5 -7
  106. package/dist/kernel/components/mdx/components/callout.js +67 -36
  107. package/dist/kernel/components/mdx/components/code-block.d.ts +5 -2
  108. package/dist/kernel/components/mdx/components/code-block.js +106 -5
  109. package/dist/kernel/components/mdx/components/copy-code-button.d.ts +8 -0
  110. package/dist/kernel/components/mdx/components/copy-code-button.js +61 -0
  111. package/dist/kernel/components/mdx/components/figure-caption.d.ts +1 -1
  112. package/dist/kernel/components/mdx/components/figure-caption.js +4 -3
  113. package/dist/kernel/components/mdx/components/figure.d.ts +6 -2
  114. package/dist/kernel/components/mdx/components/figure.js +24 -14
  115. package/dist/kernel/components/mdx/components/footnotes.js +1 -1
  116. package/dist/kernel/components/mdx/components/heading-copy-link.js +4 -4
  117. package/dist/kernel/components/mdx/components/heading.js +6 -3
  118. package/dist/kernel/components/mdx/components/hr.js +2 -2
  119. package/dist/kernel/components/mdx/components/image-zoom.js +2 -2
  120. package/dist/kernel/components/mdx/components/image.d.ts +1 -1
  121. package/dist/kernel/components/mdx/components/image.js +94 -68
  122. package/dist/kernel/components/mdx/components/inline-code.js +2 -2
  123. package/dist/kernel/components/mdx/components/kbd.d.ts +2 -2
  124. package/dist/kernel/components/mdx/components/kbd.js +5 -4
  125. package/dist/kernel/components/mdx/components/link.d.ts +35 -4
  126. package/dist/kernel/components/mdx/components/link.js +3 -3
  127. package/dist/kernel/components/mdx/components/paragraph.js +2 -5
  128. package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
  129. package/dist/kernel/components/mdx/components/table.js +2 -2
  130. package/dist/kernel/components/mdx/components/task-list.js +2 -2
  131. package/dist/kernel/components/mdx/components/video-player.d.ts +6 -2
  132. package/dist/kernel/components/mdx/components/video-player.js +8 -4
  133. package/dist/kernel/components/mdx/components/video.d.ts +5 -3
  134. package/dist/kernel/components/mdx/components/video.js +8 -6
  135. package/dist/kernel/components/mdx/error-boundary.js +2 -2
  136. package/dist/kernel/components/mdx/error-fallback.js +1 -1
  137. package/dist/kernel/components/mdx/mdx.d.ts +28 -14
  138. package/dist/kernel/components/mdx/mdx.js +336 -63
  139. package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
  140. package/dist/kernel/components/mdx/rehype-heading-ids.js +6 -4
  141. package/dist/kernel/components/next-image.d.ts +12 -0
  142. package/dist/kernel/components/next-image.js +61 -0
  143. package/dist/kernel/components/ui/accordion.js +1 -1
  144. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +6 -23
  145. package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
  146. package/dist/kernel/components/ui/breadcrumb.d.ts +11 -3
  147. package/dist/kernel/components/ui/breadcrumb.js +10 -8
  148. package/dist/kernel/components/ui/button-group.js +8 -7
  149. package/dist/kernel/components/ui/button.d.ts +58 -6
  150. package/dist/kernel/components/ui/button.js +43 -39
  151. package/dist/kernel/components/ui/card.d.ts +2 -2
  152. package/dist/kernel/components/ui/card.js +1 -1
  153. package/dist/kernel/components/ui/dialog.js +1 -1
  154. package/dist/kernel/components/ui/drawer.d.ts +3 -1
  155. package/dist/kernel/components/ui/drawer.js +6 -2
  156. package/dist/kernel/components/ui/input.d.ts +2 -2
  157. package/dist/kernel/components/ui/input.js +1 -1
  158. package/dist/kernel/components/ui/kbd.js +10 -17
  159. package/dist/kernel/components/ui/link.d.ts +11 -3
  160. package/dist/kernel/components/ui/link.js +12 -11
  161. package/dist/kernel/components/ui/menu.js +6 -6
  162. package/dist/kernel/components/ui/mod-key.d.ts +10 -0
  163. package/dist/kernel/components/ui/mod-key.js +36 -0
  164. package/dist/kernel/components/ui/navigation-menu.js +3 -3
  165. package/dist/kernel/components/ui/popover.js +1 -1
  166. package/dist/kernel/components/ui/progress.js +2 -2
  167. package/dist/kernel/components/ui/scroll-area.js +5 -5
  168. package/dist/kernel/components/ui/select.js +8 -11
  169. package/dist/kernel/components/ui/separator.js +1 -1
  170. package/dist/kernel/components/ui/table.js +1 -1
  171. package/dist/kernel/components/ui/tabs.js +1 -1
  172. package/dist/kernel/components/ui/tag.js +1 -1
  173. package/dist/kernel/components/ui/text.d.ts +2 -2
  174. package/dist/kernel/components/ui/text.js +1 -1
  175. package/dist/kernel/components/ui/toast.js +1 -1
  176. package/dist/kernel/components/ui/tooltip.js +1 -1
  177. package/dist/kernel/defaults.registry.d.ts +11 -24
  178. package/dist/kernel/defaults.registry.js +11 -26
  179. package/dist/kernel/routes/agent/markdown.d.ts +3 -1
  180. package/dist/kernel/routes/agent/markdown.js +219 -48
  181. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  182. package/dist/kernel/routes/layouts/group.js +5 -7
  183. package/dist/kernel/routes/metadata/feed.d.ts +1 -1
  184. package/dist/kernel/routes/metadata/feed.js +111 -81
  185. package/dist/kernel/routes/metadata/llms.d.ts +12 -3
  186. package/dist/kernel/routes/metadata/llms.js +156 -59
  187. package/dist/kernel/routes/metadata/og-image.js +1 -1
  188. package/dist/kernel/routes/metadata/robots.d.ts +1 -1
  189. package/dist/kernel/routes/metadata/robots.js +2 -2
  190. package/dist/kernel/routes/metadata/sitemap.d.ts +26 -4
  191. package/dist/kernel/routes/metadata/sitemap.js +206 -38
  192. package/dist/kernel/routes/not-found.d.ts +34 -0
  193. package/dist/kernel/routes/not-found.js +213 -0
  194. package/dist/kernel/routes/pages/group.d.ts +2 -2
  195. package/dist/kernel/routes/pages/group.js +21 -13
  196. package/dist/kernel/routes/pages/leaf.d.ts +28 -1
  197. package/dist/kernel/routes/pages/leaf.js +25 -16
  198. package/dist/kernel/routes/pages/root.js +19 -13
  199. package/dist/keyboard-shortcuts.js +1 -1
  200. package/dist/resolvers/manifest-resolver.js +29 -6
  201. package/dist/search.d.ts +6 -7
  202. package/dist/search.js +52 -29
  203. package/dist/{sidebar-types-Bgchdfd6.d.ts → sidebar-types-DKpR27II.d.ts} +1 -1
  204. package/dist/theme-scope.js +1 -1
  205. package/dist/{types-DHBm7-j6.d.ts → types-CJWRG05y.d.ts} +20 -1
  206. package/dist/{types-B_b3C0U6.d.ts → types-CUtrppxt.d.ts} +8 -2
  207. package/dist/{types-CIwwieNw.d.ts → types-J2w_puPF.d.ts} +11 -10
  208. package/dist/types.d.ts +15 -6
  209. package/dist/utils/heading-ids.js +30 -11
  210. package/dist/utils/toc-selection.d.ts +7 -0
  211. package/dist/utils/toc-selection.js +14 -0
  212. package/dist/validate-local-source-SV44DBQT.js +16 -0
  213. package/dist/validate-publish-os-source-NZJF3TB2.js +14 -0
  214. package/init/seed/minimal/.gitignore +1 -0
  215. package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
  216. package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
  217. package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
  218. package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
  219. package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
  220. package/init/seed/minimal/publish.os/blog/index.tsx +82 -0
  221. package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
  222. package/init/seed/minimal/publish.os/blog/page.tsx +76 -0
  223. package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
  224. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +6 -11
  225. package/init/seed/minimal/publish.os/docs/content/groups.mdx +6 -7
  226. package/init/seed/minimal/publish.os/docs/content/{theme.mdx → themes.mdx} +14 -12
  227. package/init/seed/minimal/publish.os/publish.os.config.json +7 -7
  228. package/init/seed/minimal/publish.os/theme.css +52 -24
  229. package/init/seed/minimal/publish.os/tsconfig.json +3 -0
  230. package/init/seed/minimal/seed.json +12 -2
  231. package/init/seed/scratch/publish.os/docs/content/get-started.mdx +6 -0
  232. package/init/seed/scratch/publish.os/publish.os.config.json +4 -0
  233. package/init/seed/scratch/seed.json +5 -0
  234. package/package.json +55 -44
  235. package/release/app/phosphor/package.json +5 -5
  236. package/release/app/phosphor/pnpm-lock.yaml.template +553 -377
  237. package/release/app/phosphor/pnpm-workspace.yaml +3 -0
  238. package/release/compiler/package.json +5 -3
  239. package/release/compiler/pnpm-lock.yaml.template +500 -303
  240. package/release/compiler/pnpm-workspace.yaml +3 -0
  241. package/release/release.json +8 -37
  242. package/compiler-assets/nextjs/defaults/group/leaf.tsx +0 -48
  243. package/dist/icons.d.ts +0 -1
  244. package/dist/icons.js +0 -2
  245. package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
  246. package/dist/kernel/components/blocks/design-system-preview.js +0 -648
  247. package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
  248. package/dist/kernel/components/blocks/link-playground.js +0 -744
  249. package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
  250. package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
  251. package/dist/kernel/components/mdx/components/pre.d.ts +0 -6
  252. package/dist/kernel/components/mdx/components/pre.js +0 -18
  253. package/dist/kernel/components/ui/meta-key.d.ts +0 -17
  254. package/dist/kernel/components/ui/meta-key.js +0 -9
  255. package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
  256. package/dist/kernel/components/ui/theme-toggle.js +0 -58
  257. package/dist/kernel/framework-icons.d.ts +0 -1
  258. package/dist/kernel/framework-icons.js +0 -39
  259. package/dist/link-CYaCRDb6.d.ts +0 -35
  260. package/release/app/lucide/package.json +0 -30
  261. package/release/app/lucide/pnpm-lock.yaml.template +0 -2905
  262. package/release/app/lucide/pnpm-workspace.yaml +0 -11
  263. package/release/app/tabler/package.json +0 -30
  264. package/release/app/tabler/pnpm-lock.yaml.template +0 -2911
  265. package/release/app/tabler/pnpm-workspace.yaml +0 -11
@@ -1,418 +1,237 @@
1
1
  "use client";
2
2
 
3
- // src/components/block/search.tsx
4
- import { buttonVariants } from "@publish.os/nextjs/kernel/components/ui/button";
3
+ // src/modules/search/search-block.tsx
4
+ import { useRender } from "@base-ui/react/use-render";
5
+ import { Button } from "@components/ui/button";
5
6
  import {
6
7
  Dialog,
7
8
  DialogBackdrop,
8
- DialogClose,
9
9
  DialogDescription,
10
10
  DialogPopup,
11
11
  DialogPortal,
12
- DialogTitle,
13
- DialogTrigger
14
- } from "@publish.os/nextjs/kernel/components/ui/dialog";
15
- import { Input } from "@publish.os/nextjs/kernel/components/ui/input";
16
- import { Kbd } from "@publish.os/nextjs/kernel/components/ui/kbd";
12
+ DialogTitle
13
+ } from "@components/ui/dialog";
17
14
  import {
18
- Progress,
19
- ProgressIndicator,
20
- ProgressTrack
21
- } from "@publish.os/nextjs/kernel/components/ui/progress";
22
- import { ScrollArea } from "@publish.os/nextjs/kernel/components/ui/scroll-area";
23
- import { FrameworkSearchIcon as SearchIcon } from "@publish.os/nextjs/kernel/framework-icons";
15
+ Drawer,
16
+ DrawerBackdrop,
17
+ DrawerDescription,
18
+ DrawerPopup,
19
+ DrawerPortal,
20
+ DrawerTitle,
21
+ DrawerViewport,
22
+ DrawerVirtualKeyboardProvider
23
+ } from "@components/ui/drawer";
24
+ import { Input } from "@components/ui/input";
25
+ import { Kbd as Kbd2 } from "@components/ui/kbd";
26
+ import { ModKey } from "@components/ui/mod-key";
27
+ import { Separator as Separator2 } from "@components/ui/separator";
28
+ import { MagnifyingGlassIcon } from "@phosphor-icons/react/ssr";
24
29
  import { formatShortcut } from "@publish.os/nextjs/keyboard-shortcuts";
25
30
  import {
26
- SearchProvider,
27
- useSearchBlock
31
+ SearchProvider as Root,
32
+ useSearchBlock as useSearchBlock3
28
33
  } from "@publish.os/nextjs/search";
29
- import { cn } from "@publish.os/nextjs/utils/cn";
30
- import NextLink from "next/link";
34
+ import { cn as cn3 } from "@publish.os/nextjs/utils/cn";
31
35
  import {
32
- cloneElement,
33
- useCallback,
34
- useEffect,
35
- useMemo,
36
- useRef,
37
- useState
36
+ useEffect as useEffect2,
37
+ useState as useState2
38
38
  } from "react";
39
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
40
- var SEARCH_ROW_HEIGHT = 58, SEARCH_ROW_WITH_DESCRIPTION_HEIGHT = 72, SEARCH_RESULTS_PADDING = 16, SEARCH_RESULTS_MAX_HEIGHT = 360, SEARCH_RESULT_SNIPPET_LENGTH = 180, searchProgressConfig = {
41
- completeDelay: 100,
42
- exitDuration: 150,
43
- fastPhaseEnd: 25,
44
- initialProgress: 5,
45
- maxDuration: 5e3,
46
- minDuration: 50,
47
- targetProgress: 95
48
- };
49
- function SearchProgressBar({ className }) {
50
- let {
51
- state: { isTyping, loading, status }
52
- } = useSearchBlock(), [progress, setProgress] = useState(0), [isExiting, setIsExiting] = useState(!1), animationFrame = useRef(null), cleanupTimer = useRef(null), progressRef = useRef(0), active = loading || status === "building" || status === "stale", setProgressValue = useCallback((value) => {
53
- progressRef.current = value, setProgress(value);
54
- }, []), cleanup = useCallback(() => {
55
- animationFrame.current !== null && (window.cancelAnimationFrame(animationFrame.current), animationFrame.current = null), cleanupTimer.current && (window.clearTimeout(cleanupTimer.current), cleanupTimer.current = null);
56
- }, []);
57
- useEffect(() => {
58
- if (isTyping) {
59
- cleanup(), setProgressValue(0), setIsExiting(!1);
60
- return;
61
- }
62
- if (!active) {
63
- progressRef.current > 0 && (cleanup(), setProgressValue(100), cleanupTimer.current = window.setTimeout(() => {
64
- setIsExiting(!0), cleanupTimer.current = window.setTimeout(() => {
65
- setProgressValue(0), setIsExiting(!1), cleanupTimer.current = null;
66
- }, searchProgressConfig.exitDuration);
67
- }, searchProgressConfig.completeDelay));
68
- return;
69
- }
70
- cleanup(), setIsExiting(!1), setProgressValue(searchProgressConfig.initialProgress);
71
- let start = performance.now(), animate = (now) => {
72
- let elapsed = now - start, progressValue;
73
- if (elapsed < searchProgressConfig.minDuration)
74
- progressValue = searchProgressConfig.initialProgress + elapsed / searchProgressConfig.minDuration * (searchProgressConfig.fastPhaseEnd - searchProgressConfig.initialProgress);
75
- else {
76
- let remainingProgress = searchProgressConfig.targetProgress - searchProgressConfig.fastPhaseEnd, easedTime = 1 - (1 - Math.min(
77
- 1,
78
- (elapsed - searchProgressConfig.minDuration) / (searchProgressConfig.maxDuration - searchProgressConfig.minDuration)
79
- )) ** 3;
80
- progressValue = searchProgressConfig.fastPhaseEnd + easedTime * remainingProgress;
81
- }
82
- setProgressValue(
83
- Math.min(searchProgressConfig.targetProgress, progressValue)
84
- ), animationFrame.current = window.requestAnimationFrame(animate);
85
- };
86
- return animationFrame.current = window.requestAnimationFrame(animate), cleanup;
87
- }, [active, cleanup, isTyping, setProgressValue]);
88
- let isVisible = progress > 0;
89
- return /* @__PURE__ */ jsx(
90
- Progress,
91
- {
92
- "aria-hidden": !isVisible,
93
- className: cn(
94
- "pointer-events-none h-[1.5px] overflow-hidden opacity-75 transition-opacity duration-300",
95
- isVisible ? "opacity-100" : "opacity-0",
96
- className
97
- ),
98
- value: isVisible ? progress : null,
99
- children: /* @__PURE__ */ jsx(ProgressTrack, { className: "h-full rounded-none bg-transparent", children: /* @__PURE__ */ jsx(
100
- ProgressIndicator,
101
- {
102
- className: "h-full w-full rounded-none bg-accent-1",
103
- style: {
104
- transform: isExiting ? "scaleX(0)" : `scaleX(${Math.max(0, Math.min(100, progress)) / 100})`,
105
- transformOrigin: isExiting ? "right" : "left",
106
- transition: isExiting ? `transform ${searchProgressConfig.exitDuration}ms cubic-bezier(.18,.66,.89,.35)` : "transform 200ms cubic-bezier(.04,.06,0,.61)"
107
- }
108
- }
109
- ) })
110
- }
111
- );
112
- }
113
- function RootDialogFrame({
114
- children,
115
- className
39
+
40
+ // src/modules/search/results.tsx
41
+ import { Kbd } from "@components/ui/kbd";
42
+ import {
43
+ ScrollAreaContent,
44
+ ScrollAreaRoot,
45
+ ScrollAreaScrollbar,
46
+ ScrollAreaThumb,
47
+ ScrollAreaViewport
48
+ } from "@components/ui/scroll-area";
49
+ import { Separator } from "@components/ui/separator";
50
+ import { ArrowElbowDownLeftIcon } from "@phosphor-icons/react/ssr";
51
+ import { useSearchBlock } from "@publish.os/nextjs/search";
52
+ import { cn } from "@publish.os/nextjs/utils/cn";
53
+ import NextLink from "next/link";
54
+ import { useEffect } from "react";
55
+ import { Fragment, jsx, jsxs } from "@publish.os/nextjs/jsx-runtime";
56
+ var SEARCH_RESULT_SNIPPET_LENGTH = 180;
57
+ function getSearchPanel({
58
+ displayResults,
59
+ isTyping,
60
+ loading,
61
+ query,
62
+ status
116
63
  }) {
117
- let {
118
- actions: { setOpen },
119
- meta: { variant },
120
- state: { open }
121
- } = useSearchBlock();
122
- return /* @__PURE__ */ jsx(Dialog, { onOpenChange: setOpen, open, children: /* @__PURE__ */ jsx("div", { className, "data-search-root": "", "data-variant": variant, children }) });
64
+ return query.trim() ? displayResults.length > 0 ? "results" : isTyping || loading ? null : status === "ready" ? "empty" : status === "building" || status === "stale" || status === "error" ? "status" : null : null;
123
65
  }
124
- function Root({ children, className, ...providerProps }) {
125
- return /* @__PURE__ */ jsx(SearchProvider, { ...providerProps, children: /* @__PURE__ */ jsx(RootDialogFrame, { className, children }) });
126
- }
127
- function Trigger({
128
- asChild = !1,
66
+ function SearchResults({
129
67
  children,
130
68
  className,
131
- icon,
132
- placeholder = "Search...",
133
- shortcut,
134
- shortcutClassName,
135
- showIcon = !0,
136
- showShortcut = !0,
137
- size = "sm",
138
- variant = "outline"
69
+ emptyText = "No results found.",
70
+ itemClassName,
71
+ ...props
139
72
  }) {
140
73
  let {
141
- meta: { inputId, shortcut: registeredShortcut },
142
- state: { open }
143
- } = useSearchBlock(), visibleShortcut = shortcut ?? registeredShortcut, shortcutTokens = useMemo(
144
- () => formatShortcut(visibleShortcut),
145
- [visibleShortcut]
146
- );
147
- return asChild && children ? /* @__PURE__ */ jsx(
148
- DialogTrigger,
149
- {
150
- render: cloneElement(children, {
151
- "aria-controls": inputId,
152
- "aria-expanded": open,
153
- className: cn(children.props.className, className)
154
- })
155
- }
156
- ) : /* @__PURE__ */ jsxs(
157
- DialogTrigger,
74
+ actions: { navigateToResult, setOpen, setSelectedValue },
75
+ meta: { listId, listRef },
76
+ state
77
+ } = useSearchBlock(), {
78
+ displayResults,
79
+ isTyping,
80
+ loading,
81
+ message,
82
+ query,
83
+ selectedValue,
84
+ status
85
+ } = state, hasQuery = query.trim().length > 0, panel = getSearchPanel(state), showResults = panel === "results", settled = hasQuery && !isTyping && !loading, showStatusPanel = panel === "status", showEmptyPanel = panel === "empty";
86
+ return useEffect(() => {
87
+ let list = listRef.current;
88
+ if (!list || !selectedValue || !showResults) return;
89
+ let win = list.ownerDocument.defaultView;
90
+ if (!win) return;
91
+ let frame = win.requestAnimationFrame(() => {
92
+ let index = selectedIndex(displayResults, selectedValue);
93
+ list.ownerDocument.getElementById(resultOptionId(listId, index))?.scrollIntoView({ block: "nearest" });
94
+ });
95
+ return () => win.cancelAnimationFrame(frame);
96
+ }, [displayResults, listId, listRef, selectedValue, showResults]), panel ? /* @__PURE__ */ jsxs(
97
+ ScrollAreaRoot,
158
98
  {
159
- "aria-controls": inputId,
160
- "aria-expanded": open,
161
- "aria-label": "Open search",
162
99
  className: cn(
163
- buttonVariants({ size, variant }),
164
- "justify-start gap-2 px-2.5 text-foreground-3",
165
- "hover:text-foreground-1",
100
+ "flex min-h-0 flex-1 flex-col bg-transparent md:max-h-90",
166
101
  className
167
102
  ),
103
+ ...props,
168
104
  children: [
169
- showIcon ? icon ?? /* @__PURE__ */ jsx(SearchIcon, { "aria-hidden": "true", size: 16 }) : null,
170
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: placeholder }),
171
- showShortcut ? /* @__PURE__ */ jsx(
172
- "span",
173
- {
174
- "aria-hidden": "true",
175
- className: cn(
176
- "hidden shrink-0 items-center gap-1 md:inline-flex",
177
- shortcutClassName
178
- ),
179
- children: shortcutTokens.map((token) => /* @__PURE__ */ jsx(Kbd, { size: "xs", children: token }, token))
180
- }
181
- ) : null
182
- ]
183
- }
184
- );
185
- }
186
- function DialogContent({
187
- children,
188
- className,
189
- description = "Search this site and navigate to a result.",
190
- title = "Search"
191
- }) {
192
- let {
193
- meta: { variant }
194
- } = useSearchBlock();
195
- return /* @__PURE__ */ jsxs(DialogPortal, { children: [
196
- /* @__PURE__ */ jsx(DialogBackdrop, { className: "bg-backdrop backdrop-blur-[2px]" }),
197
- /* @__PURE__ */ jsxs(
198
- DialogPopup,
199
- {
200
- className: cn(
201
- "top-[12dvh] flex max-h-[min(42rem,82dvh)] w-[min(92vw,575px)] translate-y-0 flex-col overflow-hidden p-0 shadow-xl",
202
- variant === "mobile" && "bottom-auto left-1/2 top-[8dvh] h-auto max-h-[86dvh] w-[min(94vw,575px)] max-w-none -translate-x-1/2 translate-y-0",
203
- className
204
- ),
205
- children: [
206
- /* @__PURE__ */ jsx(DialogTitle, { className: "sr-only", children: title }),
207
- /* @__PURE__ */ jsx(DialogDescription, { className: "sr-only", children: description }),
208
- children
209
- ]
210
- }
211
- )
212
- ] });
213
- }
214
- function SearchInputField({
215
- className,
216
- closeClassName,
217
- closeLabel = "ESC",
218
- placeholder = "Search docs...",
219
- rootClassName,
220
- showCloseShortcut = !0
221
- }) {
222
- let {
223
- actions: { handleInputChange, navigateToResult, setOpen, setSelectedValue },
224
- meta: { inputId, inputRef, listId },
225
- state: { displayResults, query, selectedValue }
226
- } = useSearchBlock(), closeDisplayLabel = typeof closeLabel == "string" ? closeLabel.toUpperCase() : closeLabel, selectedIndex2 = Math.max(
227
- 0,
228
- displayResults.findIndex((result) => result.id === selectedValue)
229
- ), selectedOptionId = displayResults.length > 0 ? resultOptionId(listId, selectedIndex2) : void 0, handleKeyDown = (event) => {
230
- if (event.key === "Escape") {
231
- event.preventDefault(), setOpen(!1);
232
- return;
233
- }
234
- if (event.key === "ArrowDown") {
235
- event.preventDefault();
236
- let next = displayResults[Math.min(selectedIndex2 + 1, displayResults.length - 1)];
237
- next && setSelectedValue(next.id);
238
- return;
239
- }
240
- if (event.key === "ArrowUp") {
241
- event.preventDefault();
242
- let next = displayResults[Math.max(selectedIndex2 - 1, 0)];
243
- next && setSelectedValue(next.id);
244
- return;
245
- }
246
- if (event.key === "Enter") {
247
- let selected = displayResults[selectedIndex2];
248
- if (!selected) return;
249
- event.preventDefault(), navigateToResult(selected);
250
- }
251
- };
252
- return /* @__PURE__ */ jsxs(
253
- "div",
254
- {
255
- className: cn("relative rounded-t-[inherit] bg-surface-1", rootClassName),
256
- children: [
105
+ /* @__PURE__ */ jsx(Separator, { className: "absolute inset-x-0 top-0 z-content hidden md:block group-data-[search-presentation=drawer]/search:hidden group-data-[search-presentation=dialog]/search:block" }),
106
+ /* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", children: settled && showResults ? `${displayResults.length} search ${displayResults.length === 1 ? "result" : "results"}` : "" }),
107
+ /* @__PURE__ */ jsx(ScrollAreaViewport, { className: "min-h-0 h-auto max-h-[inherit] flex-1 overscroll-contain", children: /* @__PURE__ */ jsxs(ScrollAreaContent, { children: [
108
+ showStatusPanel ? /* @__PURE__ */ jsx(
109
+ "div",
110
+ {
111
+ "aria-live": "polite",
112
+ className: "flex min-h-36 items-center justify-center px-6 py-10 text-center text-sm",
113
+ children: /* @__PURE__ */ jsx("p", { className: "max-w-full text-foreground-2", children: message ?? statusLabel(status) })
114
+ }
115
+ ) : null,
116
+ showEmptyPanel ? /* @__PURE__ */ jsx(
117
+ "div",
118
+ {
119
+ "aria-live": "polite",
120
+ className: "flex min-h-36 items-center justify-center px-6 py-10 text-center text-sm",
121
+ children: /* @__PURE__ */ jsxs("p", { className: "min-w-0 max-w-full text-foreground-2", children: [
122
+ emptyText.replace(/\.$/, ""),
123
+ " for",
124
+ " ",
125
+ /* @__PURE__ */ jsxs("span", { className: "inline-block max-w-full truncate align-bottom font-medium text-foreground-1", children: [
126
+ '"',
127
+ query.trim(),
128
+ '"'
129
+ ] })
130
+ ] })
131
+ }
132
+ ) : null,
133
+ /* @__PURE__ */ jsx(
134
+ "div",
135
+ {
136
+ "aria-label": "Search results",
137
+ className: showResults ? "space-y-1 p-2" : void 0,
138
+ id: listId,
139
+ ref: listRef,
140
+ role: "listbox",
141
+ children: showResults ? displayResults.map((result, index) => {
142
+ let snippet = resultSnippet({ query, result });
143
+ return /* @__PURE__ */ jsx(
144
+ NextLink,
145
+ {
146
+ "aria-describedby": !children && snippet ? `${resultOptionId(listId, index)}-snippet` : void 0,
147
+ "aria-labelledby": children ? void 0 : `${resultOptionId(listId, index)}-title`,
148
+ "aria-selected": result.id === selectedValue,
149
+ className: cn(
150
+ "block min-h-14.5 min-w-0 overflow-hidden rounded-button px-3 py-3 text-start",
151
+ "focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-focus-stroke",
152
+ result.id === selectedValue ? "bg-surface-active text-foreground-1" : "text-foreground-2",
153
+ itemClassName
154
+ ),
155
+ href: result.url,
156
+ id: resultOptionId(listId, index),
157
+ onClick: () => setOpen(!1),
158
+ onKeyDown: (event) => {
159
+ event.key !== "Enter" || event.nativeEvent.isComposing || (event.preventDefault(), navigateToResult(result));
160
+ },
161
+ onMouseMove: () => {
162
+ selectedValue !== result.id && setSelectedValue(result.id);
163
+ },
164
+ role: "option",
165
+ tabIndex: -1,
166
+ children: children ? children(result) : /* @__PURE__ */ jsxs(Fragment, { children: [
167
+ /* @__PURE__ */ jsx(
168
+ "span",
169
+ {
170
+ className: "line-clamp-2 wrap-break-word text-base leading-6 font-medium text-foreground-1 md:text-sm md:leading-5",
171
+ id: `${resultOptionId(listId, index)}-title`,
172
+ children: /* @__PURE__ */ jsx(
173
+ HighlightedText,
174
+ {
175
+ text: result.title,
176
+ query
177
+ }
178
+ )
179
+ }
180
+ ),
181
+ snippet ? /* @__PURE__ */ jsx(
182
+ "span",
183
+ {
184
+ className: "mt-1.5 line-clamp-2 wrap-break-word text-sm leading-5 text-foreground-2",
185
+ id: `${resultOptionId(listId, index)}-snippet`,
186
+ children: /* @__PURE__ */ jsx(HighlightedText, { text: snippet, query })
187
+ }
188
+ ) : null
189
+ ] })
190
+ },
191
+ result.id
192
+ );
193
+ }) : null
194
+ }
195
+ )
196
+ ] }) }),
257
197
  /* @__PURE__ */ jsx(
258
- Input,
259
- {
260
- "aria-activedescendant": selectedOptionId,
261
- "aria-autocomplete": "list",
262
- "aria-controls": listId,
263
- "aria-expanded": displayResults.length > 0,
264
- autoComplete: "off",
265
- className: cn(
266
- "supports-[caret-color:var(--accent-1)]:caret-(--accent-1)",
267
- "h-12 rounded-none border-0 bg-transparent px-4 pr-16 text-sm shadow-none outline-none focus:border-transparent focus-visible:outline-0",
268
- className
269
- ),
270
- id: inputId,
271
- onChange: (event) => handleInputChange(event.currentTarget.value),
272
- onKeyDown: handleKeyDown,
273
- placeholder,
274
- ref: inputRef,
275
- role: "combobox",
276
- spellCheck: !1,
277
- type: "text",
278
- value: query
279
- }
280
- ),
281
- showCloseShortcut ? /* @__PURE__ */ jsx(
282
- DialogClose,
198
+ ScrollAreaScrollbar,
283
199
  {
284
- "aria-label": "Close search",
285
- className: cn(
286
- "absolute right-3 top-1/2 size-auto -translate-y-1/2 bg-transparent p-0 text-foreground-3 hover:bg-transparent hover:text-foreground-1",
287
- closeClassName
288
- ),
289
- children: /* @__PURE__ */ jsx(Kbd, { className: "text-foreground-2", size: "sm", children: closeDisplayLabel })
200
+ className: "absolute inset-y-2 right-0 w-1.5 rounded-scrollbar-thumb bg-transparent p-0",
201
+ orientation: "vertical",
202
+ children: /* @__PURE__ */ jsx(ScrollAreaThumb, {})
290
203
  }
291
- ) : null
204
+ )
292
205
  ]
293
206
  }
294
- );
207
+ ) : null;
295
208
  }
296
- function SearchResults({
209
+ function SearchFooter({
210
+ children,
297
211
  className,
298
- emptyText = "No results found."
212
+ ...props
299
213
  }) {
300
214
  let {
301
- actions: { navigateToResult, setOpen, setSelectedValue },
302
- meta: { listId, listRef },
303
- state: {
304
- displayResults,
305
- isTyping,
306
- loading,
307
- message,
308
- query,
309
- selectedValue,
310
- status
311
- }
312
- } = useSearchBlock(), hasQuery = query.trim().length > 0, showResults = displayResults.length > 0, statusMessage = message ?? statusLabel(status), showStatusPanel = hasQuery && !isTyping && !loading && !showResults && (status === "building" || status === "stale" || status === "error"), showEmptyPanel = hasQuery && !isTyping && !loading && !showResults && !showStatusPanel && status === "ready", showPanel = showResults || showStatusPanel || showEmptyPanel, resultRowHeight = displayResults.some(
313
- (result) => resultSnippet({ query, result })
314
- ) ? SEARCH_ROW_WITH_DESCRIPTION_HEIGHT : SEARCH_ROW_HEIGHT, fullResultsHeight = displayResults.length * resultRowHeight + SEARCH_RESULTS_PADDING, resultsAreScrollable = fullResultsHeight > SEARCH_RESULTS_MAX_HEIGHT, resultsHeight = Math.min(fullResultsHeight, SEARCH_RESULTS_MAX_HEIGHT), panelHeight = showResults ? resultsHeight : showStatusPanel || showEmptyPanel ? 144 : 0, containerDuration = showResults ? Math.min(320, 150 + displayResults.length * 18) : 180;
315
- return useEffect(() => {
316
- if (!selectedValue || !showResults) return;
317
- let frame = window.requestAnimationFrame(() => {
318
- let index = selectedIndex(displayResults, selectedValue);
319
- document.getElementById(resultOptionId(listId, index))?.scrollIntoView({ block: "nearest" });
320
- });
321
- return () => window.cancelAnimationFrame(frame);
322
- }, [displayResults, listId, selectedValue, showResults]), /* @__PURE__ */ jsx(
215
+ state: { displayResults, isTyping, loading, query, status }
216
+ } = useSearchBlock(), hasResults = displayResults.length > 0, empty = !isTyping && !loading && status === "ready";
217
+ return !query.trim() || !hasResults && !empty ? null : /* @__PURE__ */ jsx(
323
218
  "div",
324
219
  {
325
220
  className: cn(
326
- "relative grid rounded-b-[inherit] bg-surface-1 transition-[grid-template-rows,opacity] ease-[cubic-bezier(0.4,0,0.2,1)] before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-content before:h-px before:bg-stroke-3 before:transition-opacity motion-reduce:transition-none",
327
- showPanel ? "opacity-100" : "opacity-0",
328
- showPanel ? "before:opacity-100" : "before:opacity-0",
221
+ "flex shrink-0 items-center gap-2 border-t border-stroke-3 px-4 py-3 text-xs text-foreground-3",
329
222
  className
330
223
  ),
331
- style: {
332
- gridTemplateRows: `${panelHeight}px`,
333
- transitionDuration: `${containerDuration}ms`
334
- },
335
- children: /* @__PURE__ */ jsxs("div", { className: "min-h-0 overflow-hidden", children: [
336
- showStatusPanel ? /* @__PURE__ */ jsx(
337
- "div",
338
- {
339
- "aria-live": "polite",
340
- className: "flex h-full items-center justify-center px-6 py-10 text-center text-sm",
341
- children: /* @__PURE__ */ jsx("p", { className: "max-w-full text-foreground-2", children: statusMessage })
342
- }
343
- ) : null,
344
- showEmptyPanel ? /* @__PURE__ */ jsx(
345
- "div",
346
- {
347
- "aria-live": "polite",
348
- className: "flex h-full items-center justify-center px-6 py-10 text-center text-sm",
349
- children: /* @__PURE__ */ jsxs("p", { className: "max-w-full text-base text-foreground-2", children: [
350
- emptyText.replace(/\.$/, ""),
351
- " for",
352
- " ",
353
- /* @__PURE__ */ jsxs("span", { className: "inline-block max-w-full truncate align-bottom font-medium text-foreground-1", children: [
354
- '"',
355
- query.trim(),
356
- '"'
357
- ] })
358
- ] })
359
- }
360
- ) : null,
361
- showResults ? /* @__PURE__ */ jsx("div", { className: "h-full", children: /* @__PURE__ */ jsx(
362
- ScrollArea,
363
- {
364
- className: "h-full",
365
- mask: resultsAreScrollable ? { height: 40, triggerSize: 32 } : !1,
366
- scrollbar: resultsAreScrollable,
367
- variant: "gradient",
368
- children: /* @__PURE__ */ jsx(
369
- "div",
370
- {
371
- "aria-label": "Search results",
372
- className: "p-2",
373
- id: listId,
374
- ref: listRef,
375
- role: "listbox",
376
- children: displayResults.map((result, index) => {
377
- let snippet = resultSnippet({ query, result });
378
- return /* @__PURE__ */ jsxs(
379
- NextLink,
380
- {
381
- "aria-selected": result.id === selectedValue,
382
- className: cn(
383
- "block min-h-[58px] min-w-0 overflow-hidden rounded-[max(calc(var(--radius-dialog)_-_0.25rem),0px)] px-3 py-2 text-left transition-colors",
384
- "focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-focus-stroke",
385
- result.id === selectedValue ? "bg-surface-active text-foreground-1" : "text-foreground-2"
386
- ),
387
- href: result.url,
388
- id: resultOptionId(listId, index),
389
- onClick: () => setOpen(!1),
390
- onKeyDown: (event) => {
391
- event.key === "Enter" && (event.preventDefault(), navigateToResult(result));
392
- },
393
- onMouseEnter: () => setSelectedValue(result.id),
394
- onMouseMove: () => setSelectedValue(result.id),
395
- role: "option",
396
- children: [
397
- /* @__PURE__ */ jsx("span", { className: "block truncate break-all text-xs leading-4 text-foreground-3", children: /* @__PURE__ */ jsx(
398
- HighlightedText,
399
- {
400
- text: resultSubtitle(result),
401
- query
402
- }
403
- ) }),
404
- /* @__PURE__ */ jsx("span", { className: "line-clamp-1 break-all text-sm font-medium", children: /* @__PURE__ */ jsx(HighlightedText, { text: result.title, query }) }),
405
- snippet ? /* @__PURE__ */ jsx("span", { className: "mt-1 line-clamp-2 break-words text-xs leading-4 text-foreground-3", children: /* @__PURE__ */ jsx(HighlightedText, { text: snippet, query }) }) : null
406
- ]
407
- },
408
- result.id
409
- );
410
- })
411
- }
412
- )
413
- }
414
- ) }) : null
415
- ] })
224
+ ...props,
225
+ children: children === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
226
+ /* @__PURE__ */ jsxs("span", { className: "hidden items-center gap-2 md:inline-flex", children: [
227
+ /* @__PURE__ */ jsx(Kbd, { size: "xs", square: hasResults, children: hasResults ? /* @__PURE__ */ jsxs(Fragment, { children: [
228
+ /* @__PURE__ */ jsx(ArrowElbowDownLeftIcon, { "aria-hidden": "true", size: 12 }),
229
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Enter" })
230
+ ] }) : "Esc" }),
231
+ /* @__PURE__ */ jsx("span", { children: hasResults ? "Go to page" : "Close search" })
232
+ ] }),
233
+ /* @__PURE__ */ jsx("span", { className: "md:hidden", children: hasResults ? "Tap a result to open" : "Swipe down to close" })
234
+ ] }) : children
416
235
  }
417
236
  );
418
237
  }
@@ -428,22 +247,9 @@ function selectedIndex(results, selectedValue) {
428
247
  results.findIndex((result) => result.id === selectedValue)
429
248
  );
430
249
  }
431
- function cleanResultPath(url) {
432
- return (url.split("#")[0]?.replace(/^\/+|\/+$/g, "") ?? "") || "/";
433
- }
434
- function resultSubtitle(result) {
435
- let section = result.meta.section ?? result.meta.group, path = cleanResultPath(result.meta.path ?? result.url);
436
- return section && path && !path.startsWith(section) ? `${section} / ${path}` : path || section || result.url;
437
- }
438
250
  function normalizedSnippetText(text) {
439
251
  return (text ?? "").replace(/\s+/g, " ").trim();
440
252
  }
441
- function queryMatches(text, query) {
442
- let normalizedQuery = query.trim().toLowerCase();
443
- if (!normalizedQuery) return !1;
444
- let lower = text.toLowerCase();
445
- return lower.includes(normalizedQuery) ? !0 : normalizedQuery.split(/\s+/).filter((term) => term.length > 1).some((term) => lower.includes(term));
446
- }
447
253
  function firstMatchIndex(text, query) {
448
254
  let normalizedQuery = query.trim().toLowerCase();
449
255
  if (!normalizedQuery) return -1;
@@ -458,7 +264,7 @@ function contextualSnippet({
458
264
  let normalizedText = normalizedSnippetText(text);
459
265
  if (normalizedText.length <= length) return normalizedText;
460
266
  let matchIndex = firstMatchIndex(normalizedText, query);
461
- if (matchIndex < 0) return `${normalizedText.slice(0, length).trimEnd()}...`;
267
+ if (matchIndex < 0) return `${normalizedText.slice(0, length).trimEnd()}\u2026`;
462
268
  let halfLength = Math.floor(length / 2), start = Math.max(0, matchIndex - halfLength), end = Math.min(normalizedText.length, start + length);
463
269
  if (end - start < length && (start = Math.max(0, end - length)), start > 0) {
464
270
  let nextSpace = normalizedText.indexOf(" ", start);
@@ -468,7 +274,7 @@ function contextualSnippet({
468
274
  let previousSpace = normalizedText.lastIndexOf(" ", end);
469
275
  previousSpace > matchIndex && (end = previousSpace);
470
276
  }
471
- let prefix = start > 0 ? "... " : "", suffix = end < normalizedText.length ? " ..." : "";
277
+ let prefix = start > 0 ? "\u2026 " : "", suffix = end < normalizedText.length ? " \u2026" : "";
472
278
  return `${prefix}${normalizedText.slice(start, end).trim()}${suffix}`;
473
279
  }
474
280
  function resultSnippet({
@@ -476,10 +282,10 @@ function resultSnippet({
476
282
  result
477
283
  }) {
478
284
  let description = normalizedSnippetText(result.meta.description);
479
- if (description && queryMatches(description, query))
285
+ if (description)
480
286
  return contextualSnippet({ query, text: description });
481
287
  let excerpt = normalizedSnippetText(result.plainExcerpt);
482
- return excerpt ? contextualSnippet({ query, text: excerpt }) : description ? contextualSnippet({ query, text: description }) : "";
288
+ return excerpt ? contextualSnippet({ query, text: excerpt }) : "";
483
289
  }
484
290
  function HighlightedText({ query, text }) {
485
291
  let normalizedQuery = query.trim().toLowerCase();
@@ -503,7 +309,7 @@ function HighlightedText({ query, text }) {
503
309
  /* @__PURE__ */ jsx(
504
310
  "mark",
505
311
  {
506
- className: "rounded-[1px] bg-accent-2 text-accent-1",
312
+ className: "rounded-[min(var(--theme-radius),2px)] bg-accent-1/15 text-accent-1",
507
313
  children: text.slice(range.start, range.end)
508
314
  },
509
315
  `${range.start}-${range.end}`
@@ -511,52 +317,372 @@ function HighlightedText({ query, text }) {
511
317
  ), cursor = range.end;
512
318
  return cursor < text.length && parts.push(text.slice(cursor)), /* @__PURE__ */ jsx(Fragment, { children: parts });
513
319
  }
514
- function Command({ children, className } = {}) {
515
- return /* @__PURE__ */ jsx(
516
- "div",
320
+
321
+ // src/modules/search/search-progress.tsx
322
+ import {
323
+ Progress,
324
+ ProgressIndicator,
325
+ ProgressTrack
326
+ } from "@components/ui/progress";
327
+ import { useSearchBlock as useSearchBlock2 } from "@publish.os/nextjs/search";
328
+ import { cn as cn2 } from "@publish.os/nextjs/utils/cn";
329
+ import { useLayoutEffect, useRef, useState } from "react";
330
+ import { jsx as jsx2 } from "@publish.os/nextjs/jsx-runtime";
331
+ var INITIAL_PROGRESS = 5, FAST_PHASE_END = 25, TARGET_PROGRESS = 95, FAST_DURATION = 50, MAX_DURATION = 5e3, COMPLETE_DURATION = 200, EXIT_DURATION = 150;
332
+ function SearchProgressBar({ className }) {
333
+ let {
334
+ meta: { inputRef, triggerRef },
335
+ state: { isTyping, loading, open, query, status }
336
+ } = useSearchBlock2(), enabled = open && !!query.trim(), active = enabled && (isTyping || loading || status === "building" || status === "stale"), [progress, setProgress] = useState(active ? INITIAL_PROGRESS : 0), [isExiting, setIsExiting] = useState(!1), progressRef = useRef(progress);
337
+ useLayoutEffect(() => {
338
+ let win = inputRef.current?.ownerDocument.defaultView ?? triggerRef.current?.ownerDocument.defaultView ?? window, frame = null, timer = null, updateProgress = (value) => {
339
+ progressRef.current = value, setProgress(value);
340
+ };
341
+ if (!enabled)
342
+ updateProgress(0), setIsExiting(!1);
343
+ else if (active)
344
+ if (setIsExiting(!1), updateProgress(INITIAL_PROGRESS), win.matchMedia("(prefers-reduced-motion: reduce)").matches)
345
+ updateProgress(FAST_PHASE_END);
346
+ else {
347
+ let start = win.performance.now(), animate = (now) => {
348
+ let elapsed = Math.max(0, now - start), normalizedTime = Math.min(
349
+ 1,
350
+ Math.max(0, elapsed - FAST_DURATION) / (MAX_DURATION - FAST_DURATION)
351
+ );
352
+ updateProgress(
353
+ elapsed < FAST_DURATION ? INITIAL_PROGRESS + elapsed / FAST_DURATION * (FAST_PHASE_END - INITIAL_PROGRESS) : FAST_PHASE_END + (1 - (1 - normalizedTime) ** 3) * (TARGET_PROGRESS - FAST_PHASE_END)
354
+ ), normalizedTime < 1 && (frame = win.requestAnimationFrame(animate));
355
+ };
356
+ frame = win.requestAnimationFrame(animate);
357
+ }
358
+ else progressRef.current > 0 && (updateProgress(100), timer = win.setTimeout(() => {
359
+ setIsExiting(!0), timer = win.setTimeout(() => {
360
+ updateProgress(0), setIsExiting(!1);
361
+ }, EXIT_DURATION);
362
+ }, COMPLETE_DURATION));
363
+ return () => {
364
+ frame !== null && win.cancelAnimationFrame(frame), timer !== null && win.clearTimeout(timer);
365
+ };
366
+ }, [active, enabled, inputRef, triggerRef]);
367
+ let visible = enabled && progress > 0, phase = visible ? isExiting ? "exiting" : active ? "loading" : "complete" : "idle";
368
+ return /* @__PURE__ */ jsx2(
369
+ Progress,
517
370
  {
518
- className: cn(
519
- "relative overflow-hidden rounded-dialog bg-surface-1 text-foreground-1",
371
+ "aria-label": "Searching",
372
+ "aria-hidden": !visible,
373
+ className: cn2(
374
+ "pointer-events-none h-px shrink-0 overflow-hidden transition-opacity duration-100",
375
+ visible ? "opacity-100" : "opacity-0",
520
376
  className
521
377
  ),
522
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
523
- /* @__PURE__ */ jsx(SearchInputField, {}),
524
- /* @__PURE__ */ jsx(SearchProgressBar, { className: "absolute inset-x-0 top-12 z-content" }),
525
- /* @__PURE__ */ jsx(SearchResults, {})
526
- ] })
378
+ "data-state": phase,
379
+ value: null,
380
+ children: /* @__PURE__ */ jsx2(ProgressTrack, { className: "h-full rounded-none bg-transparent", children: /* @__PURE__ */ jsx2(
381
+ ProgressIndicator,
382
+ {
383
+ className: "animate-search-progress h-full w-full rounded-none",
384
+ "data-state": phase,
385
+ style: {
386
+ width: "100%",
387
+ "--search-progress": progress / 100
388
+ }
389
+ }
390
+ ) })
527
391
  }
528
392
  );
529
393
  }
530
- function DefaultDesktop({ children, ...rootProps }) {
531
- return /* @__PURE__ */ jsx(Root, { variant: "desktop", ...rootProps, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
532
- /* @__PURE__ */ jsx(Trigger, {}),
533
- /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Command, {}) })
534
- ] }) });
394
+
395
+ // src/modules/search/search-block.tsx
396
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "@publish.os/nextjs/jsx-runtime";
397
+ function Trigger({
398
+ children,
399
+ className,
400
+ icon = /* @__PURE__ */ jsx3(MagnifyingGlassIcon, { "aria-hidden": "true", size: 16 }),
401
+ placeholder = "Search",
402
+ ref,
403
+ render,
404
+ shortcutClassName,
405
+ size = "sm",
406
+ variant = "outline",
407
+ ...props
408
+ }) {
409
+ let {
410
+ actions: { setOpen },
411
+ meta: { popupId, shortcut: registeredShortcut, triggerRef },
412
+ state: { open }
413
+ } = useSearchBlock3();
414
+ return useRender({
415
+ defaultTagName: "button",
416
+ render: render ?? /* @__PURE__ */ jsx3(Button, { size, variant }),
417
+ ref: [triggerRef, ref ?? null],
418
+ state: { open },
419
+ props: {
420
+ ...props,
421
+ "aria-controls": open ? popupId : void 0,
422
+ "aria-expanded": open,
423
+ "aria-haspopup": "dialog",
424
+ "aria-label": props["aria-label"] ?? placeholder,
425
+ className: cn3("md:min-w-32", className),
426
+ onClick: (event) => {
427
+ props.onClick?.(event), event.defaultPrevented || (triggerRef.current = event.currentTarget, setOpen(!0));
428
+ },
429
+ children: children ?? /* @__PURE__ */ jsxs2(Fragment2, { children: [
430
+ icon,
431
+ /* @__PURE__ */ jsx3("span", { className: "hidden min-w-0 flex-1 truncate text-start leading-none md:inline", children: placeholder }),
432
+ registeredShortcut ? /* @__PURE__ */ jsx3(
433
+ "span",
434
+ {
435
+ "aria-hidden": "true",
436
+ className: cn3(
437
+ "hidden shrink-0 items-center gap-1 md:inline-flex",
438
+ shortcutClassName
439
+ ),
440
+ children: /* @__PURE__ */ jsx3(SearchShortcutHint, { shortcut: registeredShortcut })
441
+ }
442
+ ) : null
443
+ ] })
444
+ }
445
+ });
446
+ }
447
+ function SearchShortcutHint({ shortcut }) {
448
+ let [tokens, setTokens] = useState2(null);
449
+ return useEffect2(() => {
450
+ setTokens(formatShortcut(shortcut));
451
+ }, [shortcut]), shortcut.toLowerCase() === "mod+k" ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
452
+ /* @__PURE__ */ jsx3(ModKey, { size: "xs" }),
453
+ /* @__PURE__ */ jsx3(Kbd2, { size: "xs", children: "K" })
454
+ ] }) : (tokens ?? ["Ctrl", "K"]).map((token) => /* @__PURE__ */ jsx3(
455
+ Kbd2,
456
+ {
457
+ className: tokens === null ? "invisible" : void 0,
458
+ size: "xs",
459
+ children: token
460
+ },
461
+ token
462
+ ));
535
463
  }
536
- function DefaultMobile({ children, ...rootProps }) {
537
- return /* @__PURE__ */ jsx(Root, { variant: "mobile", ...rootProps, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
538
- /* @__PURE__ */ jsx(Trigger, { showShortcut: !1 }),
539
- /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(Command, {}) })
464
+ function DialogContent({
465
+ children,
466
+ className,
467
+ container,
468
+ description = "Search this site and navigate to a result.",
469
+ mobileQuery = "(max-width: 767px)",
470
+ title = "Search"
471
+ }) {
472
+ let {
473
+ actions: { setOpen },
474
+ meta: { inputRef, popupId, triggerRef },
475
+ state: { open }
476
+ } = useSearchBlock3(), [mobile, setMobile] = useState2(!1);
477
+ return useEffect2(() => {
478
+ let media = (triggerRef.current?.ownerDocument.defaultView ?? window).matchMedia(mobileQuery), update = () => setMobile(media.matches);
479
+ return update(), media.addEventListener("change", update), () => media.removeEventListener("change", update);
480
+ }, [mobileQuery, triggerRef]), mobile ? /* @__PURE__ */ jsx3(Drawer, { onOpenChange: setOpen, open, swipeDirection: "down", children: /* @__PURE__ */ jsx3(DrawerVirtualKeyboardProvider, { children: /* @__PURE__ */ jsxs2(DrawerPortal, { container, children: [
481
+ /* @__PURE__ */ jsx3(DrawerBackdrop, { className: "animate-search-backdrop bg-backdrop" }),
482
+ /* @__PURE__ */ jsx3(DrawerViewport, { children: /* @__PURE__ */ jsxs2(
483
+ DrawerPopup,
484
+ {
485
+ "aria-label": title,
486
+ "data-search-presentation": "drawer",
487
+ id: popupId,
488
+ initialFocus: inputRef,
489
+ finalFocus: triggerRef,
490
+ className: cn3(
491
+ "group/search animate-search-drawer inset-x-0 top-auto bottom-(--drawer-keyboard-inset,0px) flex h-[min(94dvh,52rem)] max-h-[calc(100dvh-var(--drawer-keyboard-inset,0)-env(safe-area-inset-top))] w-full max-w-none flex-col overflow-hidden rounded-t-dialog border-0 bg-surface-1 p-0 pb-[env(safe-area-inset-bottom)] text-foreground-1 border-shadow-1 overscroll-contain",
492
+ className
493
+ ),
494
+ children: [
495
+ /* @__PURE__ */ jsx3(DrawerTitle, { className: "sr-only", children: title }),
496
+ /* @__PURE__ */ jsx3(DrawerDescription, { className: "sr-only", children: description }),
497
+ /* @__PURE__ */ jsx3(
498
+ "div",
499
+ {
500
+ "aria-hidden": "true",
501
+ className: "mx-auto mt-2 h-1.5 w-10 shrink-0 rounded-scrollbar-thumb bg-stroke-2"
502
+ }
503
+ ),
504
+ /* @__PURE__ */ jsx3("div", { className: "flex min-h-0 flex-1 flex-col", children: children === void 0 ? /* @__PURE__ */ jsx3(Command, {}) : children })
505
+ ]
506
+ }
507
+ ) })
508
+ ] }) }) }) : /* @__PURE__ */ jsx3(Dialog, { onOpenChange: setOpen, open, children: /* @__PURE__ */ jsxs2(DialogPortal, { container, children: [
509
+ /* @__PURE__ */ jsx3(DialogBackdrop, { className: "animate-search-backdrop bg-dialog-backdrop" }),
510
+ /* @__PURE__ */ jsxs2(
511
+ DialogPopup,
512
+ {
513
+ "data-search-presentation": "dialog",
514
+ id: popupId,
515
+ initialFocus: inputRef,
516
+ finalFocus: triggerRef,
517
+ className: cn3(
518
+ "group/search animate-search-dialog top-[12dvh] flex max-h-[min(42rem,82dvh)] w-[min(92vw,575px)] -translate-x-1/2 translate-y-0 flex-col overflow-hidden border-0 p-0",
519
+ className
520
+ ),
521
+ children: [
522
+ /* @__PURE__ */ jsx3(DialogTitle, { className: "sr-only", children: title }),
523
+ /* @__PURE__ */ jsx3(DialogDescription, { className: "sr-only", children: description }),
524
+ children === void 0 ? /* @__PURE__ */ jsx3(Command, {}) : children
525
+ ]
526
+ }
527
+ )
540
528
  ] }) });
541
529
  }
542
- var Search = {
543
- Command,
544
- DefaultDesktop,
545
- DefaultMobile,
546
- DesktopDialog: DialogContent,
547
- Dialog: DialogContent,
548
- Input: SearchInputField,
549
- MobileDialog: DialogContent,
550
- Progress: SearchProgressBar,
551
- Results: SearchResults,
552
- Root,
553
- Trigger
554
- };
530
+ function SearchInputField({
531
+ className,
532
+ closeClassName,
533
+ closeLabel = "ESC",
534
+ icon = /* @__PURE__ */ jsx3(MagnifyingGlassIcon, { "aria-hidden": "true", size: 20, weight: "light" }),
535
+ onChange,
536
+ onKeyDown,
537
+ placeholder = "Search\u2026",
538
+ ref,
539
+ rootClassName,
540
+ showCloseShortcut = !0,
541
+ ...props
542
+ }) {
543
+ let {
544
+ actions: { handleInputChange, navigateToResult, setOpen, setSelectedValue },
545
+ meta: { inputId, inputRef, listId },
546
+ state: { displayResults, query, selectedValue }
547
+ } = useSearchBlock3(), selectedIndex2 = Math.max(
548
+ 0,
549
+ displayResults.findIndex((result) => result.id === selectedValue)
550
+ ), selectedOptionId = displayResults.length > 0 ? resultOptionId(listId, selectedIndex2) : void 0, handleKeyDown = (event) => {
551
+ if (onKeyDown?.(event), !(event.defaultPrevented || event.nativeEvent.isComposing || event.keyCode === 229)) {
552
+ if (event.key === "Escape") {
553
+ event.preventDefault(), setOpen(!1);
554
+ return;
555
+ }
556
+ if (event.key === "ArrowDown") {
557
+ event.preventDefault();
558
+ let next = displayResults[Math.min(selectedIndex2 + 1, displayResults.length - 1)];
559
+ next && setSelectedValue(next.id);
560
+ return;
561
+ }
562
+ if (event.key === "ArrowUp") {
563
+ event.preventDefault();
564
+ let next = displayResults[Math.max(selectedIndex2 - 1, 0)];
565
+ next && setSelectedValue(next.id);
566
+ return;
567
+ }
568
+ if (event.key === "Enter") {
569
+ let selected = displayResults[selectedIndex2];
570
+ if (!selected) return;
571
+ event.preventDefault(), navigateToResult(selected);
572
+ }
573
+ }
574
+ };
575
+ return /* @__PURE__ */ jsxs2("div", { className: cn3("relative shrink-0 bg-transparent", rootClassName), children: [
576
+ icon ? /* @__PURE__ */ jsx3(
577
+ "span",
578
+ {
579
+ "aria-hidden": "true",
580
+ className: "pointer-events-none absolute left-4 top-1/2 -translate-y-1/2 text-foreground-3/50",
581
+ children: icon
582
+ }
583
+ ) : null,
584
+ /* @__PURE__ */ jsx3(
585
+ Input,
586
+ {
587
+ ...props,
588
+ "aria-activedescendant": selectedOptionId,
589
+ "aria-autocomplete": "list",
590
+ "aria-controls": listId,
591
+ "aria-expanded": displayResults.length > 0,
592
+ autoComplete: "off",
593
+ "aria-label": props["aria-label"] ?? "Search this site",
594
+ className: cn3(
595
+ "supports-[caret-color:var(--accent-1)]:caret-(--accent-1)",
596
+ "h-14 rounded-none border-0 bg-transparent px-4 text-base shadow-none focus:border-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-focus-stroke",
597
+ icon && "pl-12",
598
+ showCloseShortcut && "md:pr-16",
599
+ className
600
+ ),
601
+ id: inputId,
602
+ name: "search",
603
+ onChange: (event) => {
604
+ onChange?.(event), event.defaultPrevented || handleInputChange(event.currentTarget.value);
605
+ },
606
+ onKeyDown: handleKeyDown,
607
+ placeholder,
608
+ ref: (node) => {
609
+ if (inputRef.current = node, typeof ref == "function") {
610
+ let cleanup = ref(node);
611
+ if (typeof cleanup == "function")
612
+ return () => {
613
+ inputRef.current = null, cleanup();
614
+ };
615
+ } else ref && (ref.current = node);
616
+ },
617
+ role: "combobox",
618
+ spellCheck: !1,
619
+ type: "text",
620
+ value: query
621
+ }
622
+ ),
623
+ showCloseShortcut ? /* @__PURE__ */ jsx3(
624
+ "button",
625
+ {
626
+ "aria-label": "Close search",
627
+ className: cn3(
628
+ "absolute right-4 top-1/2 hidden -translate-y-1/2 cursor-pointer before:absolute before:left-1/2 before:top-1/2 before:size-10 before:-translate-1/2 before:content-[''] active:translate-y-[calc(-50%_+_1px)] md:inline-flex",
629
+ closeClassName
630
+ ),
631
+ onClick: () => setOpen(!1),
632
+ type: "button",
633
+ children: /* @__PURE__ */ jsx3(Kbd2, { size: "xs", children: closeLabel })
634
+ }
635
+ ) : null,
636
+ /* @__PURE__ */ jsx3(Separator2, { className: "absolute inset-x-0 bottom-0 z-content md:hidden group-data-[search-presentation=drawer]/search:block group-data-[search-presentation=dialog]/search:hidden" })
637
+ ] });
638
+ }
639
+ function Command({ children, className, ...props } = {}) {
640
+ let { state } = useSearchBlock3();
641
+ return /* @__PURE__ */ jsx3(
642
+ "div",
643
+ {
644
+ className: cn3(
645
+ // The popup owns the fill; opaque children would cover its inset edge.
646
+ "relative flex min-h-0 flex-1 flex-col overflow-hidden bg-transparent text-foreground-1",
647
+ className
648
+ ),
649
+ ...props,
650
+ children: children === void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
651
+ /* @__PURE__ */ jsx3(SearchInputField, {}),
652
+ /* @__PURE__ */ jsx3(SearchProgressBar, { className: "absolute inset-x-0 top-14 z-content -translate-y-full" }),
653
+ /* @__PURE__ */ jsx3(
654
+ "div",
655
+ {
656
+ className: "animate-search-results grid min-h-0 flex-1",
657
+ "data-expanded": getSearchPanel(state) !== null,
658
+ children: /* @__PURE__ */ jsxs2("div", { className: "flex min-h-0 flex-col overflow-hidden", children: [
659
+ /* @__PURE__ */ jsx3(SearchResults, {}),
660
+ /* @__PURE__ */ jsx3(SearchFooter, {})
661
+ ] })
662
+ }
663
+ )
664
+ ] }) : children
665
+ }
666
+ );
667
+ }
668
+ function Search(props) {
669
+ return /* @__PURE__ */ jsxs2(Root, { ...props, children: [
670
+ /* @__PURE__ */ jsx3(Trigger, {}),
671
+ /* @__PURE__ */ jsx3(DialogContent, {})
672
+ ] });
673
+ }
674
+ Search.Root = Root;
675
+ Search.Trigger = Trigger;
676
+ Search.Dialog = DialogContent;
677
+ Search.Command = Command;
678
+ Search.Input = SearchInputField;
679
+ Search.Progress = SearchProgressBar;
680
+ Search.Results = SearchResults;
681
+ Search.Footer = SearchFooter;
555
682
  export {
556
683
  Command,
557
- DefaultDesktop,
558
- DefaultMobile,
559
684
  DialogContent as Dialog,
685
+ SearchFooter as Footer,
560
686
  SearchInputField as Input,
561
687
  SearchProgressBar as Progress,
562
688
  SearchResults as Results,