@gabvdl/ui 0.0.14

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 (330) hide show
  1. package/README.md +95 -0
  2. package/dist/components/button/button.d.ts +39 -0
  3. package/dist/components/button/button.d.ts.map +1 -0
  4. package/dist/components/button/button.js +72 -0
  5. package/dist/components/button/button.js.map +1 -0
  6. package/dist/components/button/index.d.ts +5 -0
  7. package/dist/components/button/index.d.ts.map +1 -0
  8. package/dist/components/button/tooltip.d.ts +31 -0
  9. package/dist/components/button/tooltip.d.ts.map +1 -0
  10. package/dist/components/button/tooltip.js +83 -0
  11. package/dist/components/button/tooltip.js.map +1 -0
  12. package/dist/components/changelog/changelog.d.ts +52 -0
  13. package/dist/components/changelog/changelog.d.ts.map +1 -0
  14. package/dist/components/changelog/changelog.js +164 -0
  15. package/dist/components/changelog/changelog.js.map +1 -0
  16. package/dist/components/changelog/index.d.ts +3 -0
  17. package/dist/components/changelog/index.d.ts.map +1 -0
  18. package/dist/components/copy-button/copy-button.d.ts +16 -0
  19. package/dist/components/copy-button/copy-button.d.ts.map +1 -0
  20. package/dist/components/copy-button/copy-button.js +40 -0
  21. package/dist/components/copy-button/copy-button.js.map +1 -0
  22. package/dist/components/copy-button/index.d.ts +3 -0
  23. package/dist/components/copy-button/index.d.ts.map +1 -0
  24. package/dist/components/drop-zone/drop-zone.d.ts +20 -0
  25. package/dist/components/drop-zone/drop-zone.d.ts.map +1 -0
  26. package/dist/components/drop-zone/drop-zone.js +54 -0
  27. package/dist/components/drop-zone/drop-zone.js.map +1 -0
  28. package/dist/components/drop-zone/index.d.ts +5 -0
  29. package/dist/components/drop-zone/index.d.ts.map +1 -0
  30. package/dist/components/drop-zone/use-file-drop.d.ts +45 -0
  31. package/dist/components/drop-zone/use-file-drop.d.ts.map +1 -0
  32. package/dist/components/drop-zone/use-file-drop.js +97 -0
  33. package/dist/components/drop-zone/use-file-drop.js.map +1 -0
  34. package/dist/components/element-picker/element-picker-field.d.ts +30 -0
  35. package/dist/components/element-picker/element-picker-field.d.ts.map +1 -0
  36. package/dist/components/element-picker/element-picker-field.js +273 -0
  37. package/dist/components/element-picker/element-picker-field.js.map +1 -0
  38. package/dist/components/element-picker/element-picker.d.ts +45 -0
  39. package/dist/components/element-picker/element-picker.d.ts.map +1 -0
  40. package/dist/components/element-picker/element-picker.js +179 -0
  41. package/dist/components/element-picker/element-picker.js.map +1 -0
  42. package/dist/components/element-picker/element-preview.d.ts +23 -0
  43. package/dist/components/element-picker/element-preview.d.ts.map +1 -0
  44. package/dist/components/element-picker/element-preview.js +72 -0
  45. package/dist/components/element-picker/element-preview.js.map +1 -0
  46. package/dist/components/element-picker/index.d.ts +12 -0
  47. package/dist/components/element-picker/index.d.ts.map +1 -0
  48. package/dist/components/element-picker/parse.d.ts +32 -0
  49. package/dist/components/element-picker/parse.d.ts.map +1 -0
  50. package/dist/components/element-picker/parse.js +230 -0
  51. package/dist/components/element-picker/parse.js.map +1 -0
  52. package/dist/components/element-picker/types.d.ts +72 -0
  53. package/dist/components/element-picker/types.d.ts.map +1 -0
  54. package/dist/components/element-picker/use-element-picker.d.ts +56 -0
  55. package/dist/components/element-picker/use-element-picker.d.ts.map +1 -0
  56. package/dist/components/element-picker/use-element-picker.js +201 -0
  57. package/dist/components/element-picker/use-element-picker.js.map +1 -0
  58. package/dist/components/empty-state/empty-state.d.ts +16 -0
  59. package/dist/components/empty-state/empty-state.d.ts.map +1 -0
  60. package/dist/components/empty-state/empty-state.js +41 -0
  61. package/dist/components/empty-state/empty-state.js.map +1 -0
  62. package/dist/components/empty-state/index.d.ts +3 -0
  63. package/dist/components/empty-state/index.d.ts.map +1 -0
  64. package/dist/components/floating-panel/dock-context.d.ts +66 -0
  65. package/dist/components/floating-panel/dock-context.d.ts.map +1 -0
  66. package/dist/components/floating-panel/dock-context.js +96 -0
  67. package/dist/components/floating-panel/dock-context.js.map +1 -0
  68. package/dist/components/floating-panel/dock.d.ts +26 -0
  69. package/dist/components/floating-panel/dock.d.ts.map +1 -0
  70. package/dist/components/floating-panel/dock.js +46 -0
  71. package/dist/components/floating-panel/dock.js.map +1 -0
  72. package/dist/components/floating-panel/floating-panel.d.ts +69 -0
  73. package/dist/components/floating-panel/floating-panel.d.ts.map +1 -0
  74. package/dist/components/floating-panel/floating-panel.js +285 -0
  75. package/dist/components/floating-panel/floating-panel.js.map +1 -0
  76. package/dist/components/floating-panel/index.d.ts +7 -0
  77. package/dist/components/floating-panel/index.d.ts.map +1 -0
  78. package/dist/components/fuzzy-list/fuzzy-list.d.ts +96 -0
  79. package/dist/components/fuzzy-list/fuzzy-list.d.ts.map +1 -0
  80. package/dist/components/fuzzy-list/fuzzy-list.js +127 -0
  81. package/dist/components/fuzzy-list/fuzzy-list.js.map +1 -0
  82. package/dist/components/fuzzy-list/index.d.ts +4 -0
  83. package/dist/components/fuzzy-list/index.d.ts.map +1 -0
  84. package/dist/components/global-search/global-search.d.ts +78 -0
  85. package/dist/components/global-search/global-search.d.ts.map +1 -0
  86. package/dist/components/global-search/global-search.js +181 -0
  87. package/dist/components/global-search/global-search.js.map +1 -0
  88. package/dist/components/global-search/hotkey.d.ts +23 -0
  89. package/dist/components/global-search/hotkey.d.ts.map +1 -0
  90. package/dist/components/global-search/hotkey.js +41 -0
  91. package/dist/components/global-search/hotkey.js.map +1 -0
  92. package/dist/components/global-search/index.d.ts +5 -0
  93. package/dist/components/global-search/index.d.ts.map +1 -0
  94. package/dist/components/iframe-preview/iframe-preview.d.ts +64 -0
  95. package/dist/components/iframe-preview/iframe-preview.d.ts.map +1 -0
  96. package/dist/components/iframe-preview/iframe-preview.js +257 -0
  97. package/dist/components/iframe-preview/iframe-preview.js.map +1 -0
  98. package/dist/components/iframe-preview/index.d.ts +3 -0
  99. package/dist/components/iframe-preview/index.d.ts.map +1 -0
  100. package/dist/components/image-viewer/image-viewer.d.ts +30 -0
  101. package/dist/components/image-viewer/image-viewer.d.ts.map +1 -0
  102. package/dist/components/image-viewer/image-viewer.js +226 -0
  103. package/dist/components/image-viewer/image-viewer.js.map +1 -0
  104. package/dist/components/image-viewer/index.d.ts +4 -0
  105. package/dist/components/image-viewer/index.d.ts.map +1 -0
  106. package/dist/components/image-viewer/progressive-image.d.ts +20 -0
  107. package/dist/components/image-viewer/progressive-image.d.ts.map +1 -0
  108. package/dist/components/image-viewer/progressive-image.js +62 -0
  109. package/dist/components/image-viewer/progressive-image.js.map +1 -0
  110. package/dist/components/image-viewer/viewable-image.d.ts +17 -0
  111. package/dist/components/image-viewer/viewable-image.d.ts.map +1 -0
  112. package/dist/components/image-viewer/viewable-image.js +38 -0
  113. package/dist/components/image-viewer/viewable-image.js.map +1 -0
  114. package/dist/components/input/index.d.ts +3 -0
  115. package/dist/components/input/index.d.ts.map +1 -0
  116. package/dist/components/input/input.d.ts +15 -0
  117. package/dist/components/input/input.d.ts.map +1 -0
  118. package/dist/components/input/input.js +56 -0
  119. package/dist/components/input/input.js.map +1 -0
  120. package/dist/components/modal/index.d.ts +5 -0
  121. package/dist/components/modal/index.d.ts.map +1 -0
  122. package/dist/components/modal/modal-context.d.ts +37 -0
  123. package/dist/components/modal/modal-context.d.ts.map +1 -0
  124. package/dist/components/modal/modal-context.js +81 -0
  125. package/dist/components/modal/modal-context.js.map +1 -0
  126. package/dist/components/modal/modal.d.ts +28 -0
  127. package/dist/components/modal/modal.d.ts.map +1 -0
  128. package/dist/components/modal/modal.js +94 -0
  129. package/dist/components/modal/modal.js.map +1 -0
  130. package/dist/components/nav-2d/index.d.ts +3 -0
  131. package/dist/components/nav-2d/index.d.ts.map +1 -0
  132. package/dist/components/nav-2d/nav-2d.d.ts +59 -0
  133. package/dist/components/nav-2d/nav-2d.d.ts.map +1 -0
  134. package/dist/components/nav-2d/nav-2d.js +290 -0
  135. package/dist/components/nav-2d/nav-2d.js.map +1 -0
  136. package/dist/components/phone-preview/index.d.ts +3 -0
  137. package/dist/components/phone-preview/index.d.ts.map +1 -0
  138. package/dist/components/phone-preview/phone-preview.d.ts +45 -0
  139. package/dist/components/phone-preview/phone-preview.d.ts.map +1 -0
  140. package/dist/components/phone-preview/phone-preview.js +117 -0
  141. package/dist/components/phone-preview/phone-preview.js.map +1 -0
  142. package/dist/components/progressive-bash/index.d.ts +7 -0
  143. package/dist/components/progressive-bash/index.d.ts.map +1 -0
  144. package/dist/components/progressive-bash/parse.d.ts +88 -0
  145. package/dist/components/progressive-bash/parse.d.ts.map +1 -0
  146. package/dist/components/progressive-bash/parse.js +120 -0
  147. package/dist/components/progressive-bash/parse.js.map +1 -0
  148. package/dist/components/progressive-bash/playback.d.ts +50 -0
  149. package/dist/components/progressive-bash/playback.d.ts.map +1 -0
  150. package/dist/components/progressive-bash/playback.js +19 -0
  151. package/dist/components/progressive-bash/playback.js.map +1 -0
  152. package/dist/components/progressive-bash/progressive-bash.d.ts +97 -0
  153. package/dist/components/progressive-bash/progressive-bash.d.ts.map +1 -0
  154. package/dist/components/progressive-bash/progressive-bash.js +377 -0
  155. package/dist/components/progressive-bash/progressive-bash.js.map +1 -0
  156. package/dist/components/progressive-list/index.d.ts +3 -0
  157. package/dist/components/progressive-list/index.d.ts.map +1 -0
  158. package/dist/components/progressive-list/progressive-list.d.ts +55 -0
  159. package/dist/components/progressive-list/progressive-list.d.ts.map +1 -0
  160. package/dist/components/progressive-list/progressive-list.js +83 -0
  161. package/dist/components/progressive-list/progressive-list.js.map +1 -0
  162. package/dist/components/progressive-table/index.d.ts +3 -0
  163. package/dist/components/progressive-table/index.d.ts.map +1 -0
  164. package/dist/components/progressive-table/progressive-table.d.ts +58 -0
  165. package/dist/components/progressive-table/progressive-table.d.ts.map +1 -0
  166. package/dist/components/progressive-table/progressive-table.js +86 -0
  167. package/dist/components/progressive-table/progressive-table.js.map +1 -0
  168. package/dist/components/progressive-text/index.d.ts +3 -0
  169. package/dist/components/progressive-text/index.d.ts.map +1 -0
  170. package/dist/components/progressive-text/progressive-text.d.ts +54 -0
  171. package/dist/components/progressive-text/progressive-text.d.ts.map +1 -0
  172. package/dist/components/progressive-text/progressive-text.js +97 -0
  173. package/dist/components/progressive-text/progressive-text.js.map +1 -0
  174. package/dist/components/progressive-timeline/index.d.ts +3 -0
  175. package/dist/components/progressive-timeline/index.d.ts.map +1 -0
  176. package/dist/components/progressive-timeline/progressive-timeline.d.ts +46 -0
  177. package/dist/components/progressive-timeline/progressive-timeline.d.ts.map +1 -0
  178. package/dist/components/progressive-timeline/progressive-timeline.js +62 -0
  179. package/dist/components/progressive-timeline/progressive-timeline.js.map +1 -0
  180. package/dist/components/relative-time/index.d.ts +3 -0
  181. package/dist/components/relative-time/index.d.ts.map +1 -0
  182. package/dist/components/relative-time/relative-time.d.ts +14 -0
  183. package/dist/components/relative-time/relative-time.d.ts.map +1 -0
  184. package/dist/components/relative-time/relative-time.js +15 -0
  185. package/dist/components/relative-time/relative-time.js.map +1 -0
  186. package/dist/components/resizable-layout/index.d.ts +3 -0
  187. package/dist/components/resizable-layout/index.d.ts.map +1 -0
  188. package/dist/components/resizable-layout/resizable-layout.d.ts +113 -0
  189. package/dist/components/resizable-layout/resizable-layout.d.ts.map +1 -0
  190. package/dist/components/resizable-layout/resizable-layout.js +398 -0
  191. package/dist/components/resizable-layout/resizable-layout.js.map +1 -0
  192. package/dist/components/rich-input/compose.d.ts +13 -0
  193. package/dist/components/rich-input/compose.d.ts.map +1 -0
  194. package/dist/components/rich-input/compose.js +28 -0
  195. package/dist/components/rich-input/compose.js.map +1 -0
  196. package/dist/components/rich-input/index.d.ts +5 -0
  197. package/dist/components/rich-input/index.d.ts.map +1 -0
  198. package/dist/components/rich-input/parts.d.ts +53 -0
  199. package/dist/components/rich-input/parts.d.ts.map +1 -0
  200. package/dist/components/rich-input/parts.js +285 -0
  201. package/dist/components/rich-input/parts.js.map +1 -0
  202. package/dist/components/rich-input/rich-input.d.ts +64 -0
  203. package/dist/components/rich-input/rich-input.d.ts.map +1 -0
  204. package/dist/components/rich-input/rich-input.js +351 -0
  205. package/dist/components/rich-input/rich-input.js.map +1 -0
  206. package/dist/components/rich-input/types.d.ts +92 -0
  207. package/dist/components/rich-input/types.d.ts.map +1 -0
  208. package/dist/components/rich-input/use-draft.d.ts +9 -0
  209. package/dist/components/rich-input/use-draft.d.ts.map +1 -0
  210. package/dist/components/rich-input/use-draft.js +47 -0
  211. package/dist/components/rich-input/use-draft.js.map +1 -0
  212. package/dist/components/rich-input/use-file-upload.d.ts +18 -0
  213. package/dist/components/rich-input/use-file-upload.d.ts.map +1 -0
  214. package/dist/components/rich-input/use-file-upload.js +88 -0
  215. package/dist/components/rich-input/use-file-upload.js.map +1 -0
  216. package/dist/components/rich-input/use-guidelines.d.ts +16 -0
  217. package/dist/components/rich-input/use-guidelines.d.ts.map +1 -0
  218. package/dist/components/rich-input/use-guidelines.js +85 -0
  219. package/dist/components/rich-input/use-guidelines.js.map +1 -0
  220. package/dist/components/rich-input/use-input-history.d.ts +22 -0
  221. package/dist/components/rich-input/use-input-history.d.ts.map +1 -0
  222. package/dist/components/rich-input/use-input-history.js +61 -0
  223. package/dist/components/rich-input/use-input-history.js.map +1 -0
  224. package/dist/components/rich-input/use-mention.d.ts +24 -0
  225. package/dist/components/rich-input/use-mention.d.ts.map +1 -0
  226. package/dist/components/rich-input/use-mention.js +54 -0
  227. package/dist/components/rich-input/use-mention.js.map +1 -0
  228. package/dist/components/search-input/index.d.ts +3 -0
  229. package/dist/components/search-input/index.d.ts.map +1 -0
  230. package/dist/components/search-input/search-input.d.ts +14 -0
  231. package/dist/components/search-input/search-input.d.ts.map +1 -0
  232. package/dist/components/search-input/search-input.js +63 -0
  233. package/dist/components/search-input/search-input.js.map +1 -0
  234. package/dist/components/skeleton/index.d.ts +3 -0
  235. package/dist/components/skeleton/index.d.ts.map +1 -0
  236. package/dist/components/skeleton/skeleton.d.ts +19 -0
  237. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  238. package/dist/components/skeleton/skeleton.js +29 -0
  239. package/dist/components/skeleton/skeleton.js.map +1 -0
  240. package/dist/components/spinner/index.d.ts +3 -0
  241. package/dist/components/spinner/index.d.ts.map +1 -0
  242. package/dist/components/spinner/spinner.d.ts +11 -0
  243. package/dist/components/spinner/spinner.d.ts.map +1 -0
  244. package/dist/components/spinner/spinner.js +32 -0
  245. package/dist/components/spinner/spinner.js.map +1 -0
  246. package/dist/components/status-badge/index.d.ts +3 -0
  247. package/dist/components/status-badge/index.d.ts.map +1 -0
  248. package/dist/components/status-badge/status-badge.d.ts +31 -0
  249. package/dist/components/status-badge/status-badge.d.ts.map +1 -0
  250. package/dist/components/status-badge/status-badge.js +53 -0
  251. package/dist/components/status-badge/status-badge.js.map +1 -0
  252. package/dist/components/theme/index.d.ts +5 -0
  253. package/dist/components/theme/index.d.ts.map +1 -0
  254. package/dist/components/theme/theme-toggle.d.ts +11 -0
  255. package/dist/components/theme/theme-toggle.d.ts.map +1 -0
  256. package/dist/components/theme/theme-toggle.js +57 -0
  257. package/dist/components/theme/theme-toggle.js.map +1 -0
  258. package/dist/components/theme/theme.d.ts +29 -0
  259. package/dist/components/theme/theme.d.ts.map +1 -0
  260. package/dist/components/theme/theme.js +70 -0
  261. package/dist/components/theme/theme.js.map +1 -0
  262. package/dist/components/toast/index.d.ts +3 -0
  263. package/dist/components/toast/index.d.ts.map +1 -0
  264. package/dist/components/toast/toast.d.ts +64 -0
  265. package/dist/components/toast/toast.d.ts.map +1 -0
  266. package/dist/components/toast/toast.js +155 -0
  267. package/dist/components/toast/toast.js.map +1 -0
  268. package/dist/components/virtual-list/index.d.ts +3 -0
  269. package/dist/components/virtual-list/index.d.ts.map +1 -0
  270. package/dist/components/virtual-list/virtual-list.d.ts +71 -0
  271. package/dist/components/virtual-list/virtual-list.d.ts.map +1 -0
  272. package/dist/components/virtual-list/virtual-list.js +65 -0
  273. package/dist/components/virtual-list/virtual-list.js.map +1 -0
  274. package/dist/hooks/index.d.ts +12 -0
  275. package/dist/hooks/index.d.ts.map +1 -0
  276. package/dist/hooks/use-copy-to-clipboard.d.ts +26 -0
  277. package/dist/hooks/use-copy-to-clipboard.d.ts.map +1 -0
  278. package/dist/hooks/use-copy-to-clipboard.js +36 -0
  279. package/dist/hooks/use-copy-to-clipboard.js.map +1 -0
  280. package/dist/hooks/use-debounced-value.d.ts +23 -0
  281. package/dist/hooks/use-debounced-value.d.ts.map +1 -0
  282. package/dist/hooks/use-debounced-value.js +19 -0
  283. package/dist/hooks/use-debounced-value.js.map +1 -0
  284. package/dist/hooks/use-intersection.d.ts +25 -0
  285. package/dist/hooks/use-intersection.d.ts.map +1 -0
  286. package/dist/hooks/use-intersection.js +38 -0
  287. package/dist/hooks/use-intersection.js.map +1 -0
  288. package/dist/hooks/use-local-storage.d.ts +12 -0
  289. package/dist/hooks/use-local-storage.d.ts.map +1 -0
  290. package/dist/hooks/use-local-storage.js +43 -0
  291. package/dist/hooks/use-local-storage.js.map +1 -0
  292. package/dist/hooks/use-long-press.d.ts +37 -0
  293. package/dist/hooks/use-long-press.d.ts.map +1 -0
  294. package/dist/hooks/use-long-press.js +39 -0
  295. package/dist/hooks/use-long-press.js.map +1 -0
  296. package/dist/hooks/use-media-query.d.ts +17 -0
  297. package/dist/hooks/use-media-query.d.ts.map +1 -0
  298. package/dist/hooks/use-media-query.js +37 -0
  299. package/dist/hooks/use-media-query.js.map +1 -0
  300. package/dist/hooks/use-overlay.d.ts +20 -0
  301. package/dist/hooks/use-overlay.d.ts.map +1 -0
  302. package/dist/hooks/use-overlay.js +42 -0
  303. package/dist/hooks/use-overlay.js.map +1 -0
  304. package/dist/image-viewer.css +152 -0
  305. package/dist/index.d.ts +67 -0
  306. package/dist/index.d.ts.map +1 -0
  307. package/dist/index.js +161 -0
  308. package/dist/index.js.map +1 -0
  309. package/dist/lib/format.d.ts +19 -0
  310. package/dist/lib/format.d.ts.map +1 -0
  311. package/dist/lib/format.js +62 -0
  312. package/dist/lib/format.js.map +1 -0
  313. package/dist/lib/highlight.d.ts +15 -0
  314. package/dist/lib/highlight.d.ts.map +1 -0
  315. package/dist/lib/highlight.js +39 -0
  316. package/dist/lib/highlight.js.map +1 -0
  317. package/dist/lib/search.d.ts +40 -0
  318. package/dist/lib/search.d.ts.map +1 -0
  319. package/dist/lib/search.js +91 -0
  320. package/dist/lib/search.js.map +1 -0
  321. package/dist/lib/utils.d.ts +4 -0
  322. package/dist/lib/utils.d.ts.map +1 -0
  323. package/dist/lib/utils.js +9 -0
  324. package/dist/lib/utils.js.map +1 -0
  325. package/dist/overlay.css +78 -0
  326. package/dist/styles.css +6 -0
  327. package/dist/theme.css +81 -0
  328. package/dist/tooltip.css +53 -0
  329. package/dist/virtual-list.css +29 -0
  330. package/package.json +77 -0
@@ -0,0 +1,127 @@
1
+ import { jsxs as k, jsx as i } from "react/jsx-runtime";
2
+ import { useState as j, useRef as J, useMemo as q, useEffect as W } from "react";
3
+ import X from "fuse.js";
4
+ import { Search as Y } from "lucide-react";
5
+ import { cn as v } from "../../lib/utils.js";
6
+ import { highlightSnippet as Z, highlightAll as _ } from "../../lib/highlight.js";
7
+ import { runSearch as O } from "../../lib/search.js";
8
+ import { useDebouncedValue as Q } from "../../hooks/use-debounced-value.js";
9
+ import { Spinner as ee } from "../spinner/spinner.js";
10
+ import { VirtualList as te } from "../virtual-list/virtual-list.js";
11
+ const re = {
12
+ includeMatches: !0,
13
+ ignoreLocation: !0,
14
+ threshold: 0.35,
15
+ minMatchCharLength: 2
16
+ };
17
+ function ne(r, l) {
18
+ let n = r;
19
+ for (const s of l.split(".")) {
20
+ if (n == null || typeof n != "object") return "";
21
+ n = n[s];
22
+ }
23
+ return n == null ? "" : String(n);
24
+ }
25
+ function pe({
26
+ items: r,
27
+ keys: l,
28
+ renderItem: n,
29
+ getItemKey: s,
30
+ onSelect: w,
31
+ placeholder: z = "Search…",
32
+ emptyState: E = "No matches.",
33
+ autoFocus: F,
34
+ limit: M,
35
+ estimateSize: I = 60,
36
+ overscan: $ = 8,
37
+ showCount: R = !0,
38
+ debounce: T = 400,
39
+ fuseOptions: N,
40
+ toolbar: U,
41
+ onQueryChange: m,
42
+ className: V,
43
+ inputClassName: B,
44
+ listClassName: K
45
+ }) {
46
+ const [S, P] = j(""), [a, h] = j(0), b = J(null), [f, C] = Q(S, T), y = q(
47
+ () => new X(r, { ...re, ...N, keys: l }),
48
+ [r, l, N]
49
+ ), c = q(
50
+ () => O(y, r, l, f, M),
51
+ [y, f, r, l, M]
52
+ );
53
+ W(() => {
54
+ h((e) => Math.min(e, Math.max(0, c.length - 1)));
55
+ }, [c.length]);
56
+ const d = (e) => {
57
+ const t = c[e];
58
+ t && w && w(t.item, t.refIndex);
59
+ }, D = (e) => {
60
+ var o;
61
+ const t = Math.min(Math.max(a + e, 0), c.length - 1);
62
+ h(t), (o = b.current) == null || o.scrollToIndex(t);
63
+ }, G = (e) => {
64
+ e.key === "ArrowDown" ? (e.preventDefault(), D(1)) : e.key === "ArrowUp" ? (e.preventDefault(), D(-1)) : e.key === "Enter" && d(a);
65
+ }, A = f.trim();
66
+ return /* @__PURE__ */ k("div", { className: v("flex min-h-0 flex-col", V), children: [
67
+ /* @__PURE__ */ k("div", { className: "flex items-center gap-2 rounded-md border border-border bg-muted px-2.5", children: [
68
+ /* @__PURE__ */ i(Y, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
69
+ /* @__PURE__ */ i(
70
+ "input",
71
+ {
72
+ value: S,
73
+ autoFocus: F,
74
+ onChange: (e) => {
75
+ P(e.target.value), m == null || m(e.target.value);
76
+ },
77
+ onKeyDown: G,
78
+ placeholder: z,
79
+ spellCheck: !1,
80
+ className: v(
81
+ "w-full bg-transparent py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground",
82
+ B
83
+ )
84
+ }
85
+ ),
86
+ C && /* @__PURE__ */ i(ee, { className: "size-3.5 shrink-0 text-muted-foreground" }),
87
+ U
88
+ ] }),
89
+ R && /* @__PURE__ */ i("div", { className: "px-1 pt-2 mono text-[11px] text-muted-foreground", children: A ? `${c.length} of ${r.length}` : `${r.length} items` }),
90
+ /* @__PURE__ */ i(
91
+ te,
92
+ {
93
+ items: c,
94
+ apiRef: b,
95
+ estimateSize: I,
96
+ overscan: $,
97
+ getItemKey: s ? (e, t) => s(e.item, t) : void 0,
98
+ className: v("min-h-0 flex-1 pt-1.5", K),
99
+ emptyState: /* @__PURE__ */ i("p", { className: "px-2 py-8 text-center text-sm text-muted-foreground", children: E }),
100
+ renderItem: ({ item: e, matches: t }, o) => /* @__PURE__ */ i(
101
+ "div",
102
+ {
103
+ onMouseMove: () => h(o),
104
+ onClick: () => d(o),
105
+ style: { paddingBottom: 4 },
106
+ children: n({
107
+ item: e,
108
+ index: o,
109
+ query: A,
110
+ matches: t,
111
+ active: o === a,
112
+ highlight: (L, u) => {
113
+ const p = ne(e, L), g = t.find((H) => H.key === L), x = (g == null ? void 0 : g.indices) ?? [];
114
+ return x.length === 0 ? p : u != null && u.snippet ? Z(p, x, u.window) : _(p, x);
115
+ },
116
+ select: () => d(o)
117
+ })
118
+ }
119
+ )
120
+ }
121
+ )
122
+ ] });
123
+ }
124
+ export {
125
+ pe as FuzzyList
126
+ };
127
+ //# sourceMappingURL=fuzzy-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy-list.js","sources":["../../../src/components/fuzzy-list/fuzzy-list.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type Key, type ReactNode } from 'react';\nimport Fuse, { type FuseOptionKey, type FuseResultMatch, type IFuseOptions } from 'fuse.js';\nimport { Search } from 'lucide-react';\n\nimport { cn } from '../../lib/utils';\nimport { highlightAll, highlightSnippet } from '../../lib/highlight';\nimport { runSearch, type SearchResult } from '../../lib/search';\nimport { useDebouncedValue } from '../../hooks/use-debounced-value';\nimport { Spinner } from '../spinner';\nimport { VirtualList, type VirtualListHandle } from '../virtual-list';\n\ntype Result<T> = SearchResult<T>;\n\n/** What `renderItem` receives for each row. */\nexport interface FuzzyRenderContext<T> {\n /** The row's data object. */\n item: T;\n /** Its index within the currently shown (filtered) list. */\n index: number;\n /** The live search query (trimmed). */\n query: string;\n /** Fuse match metadata for this row (empty when the query is empty). */\n matches: readonly FuseResultMatch[];\n /** Whether this row is the keyboard-focused one. */\n active: boolean;\n /**\n * Render one searched string field with its fuzzy matches wrapped in `<mark>`.\n * Pass `{ snippet: true }` for long fields (windowed, with ellipses); the\n * default highlights the whole value inline. Falls back to the plain value\n * when there's no match.\n */\n highlight: (key: string, opts?: { snippet?: boolean; window?: number }) => ReactNode;\n /** Fire `onSelect` for this row. */\n select: () => void;\n}\n\nexport interface FuzzyListProps<T> {\n /** The data to search — any array of JSON-like objects. */\n items: T[];\n /** Fields Fuse should search. Accepts dotted paths and weighted keys. */\n keys: FuseOptionKey<T>[];\n /** Render one row from its {@link FuzzyRenderContext}. */\n renderItem: (ctx: FuzzyRenderContext<T>) => ReactNode;\n /** Stable React key per row (defaults to the array index). */\n getItemKey?: (item: T, index: number) => Key;\n /** Called when a row is activated (click or Enter). */\n onSelect?: (item: T, index: number) => void;\n placeholder?: string;\n /** Shown when nothing matches (defaults to \"No matches.\"). */\n emptyState?: ReactNode;\n /** Focus the search box on mount. */\n autoFocus?: boolean;\n /** Cap the number of results (Fuse `limit`). */\n limit?: number;\n /** First-paint row-height guess for the virtual list, px. Default 60 (compact\n * rows). Bump it when rendering taller rows/cards to cut first-paint jank. */\n estimateSize?: number;\n /** Off-screen rows kept mounted as a scroll buffer. Default 8. */\n overscan?: number;\n /** Show the \"N of M\" count line above the list. */\n showCount?: boolean;\n /**\n * How long to wait (ms) after the last keystroke before re-running the search.\n * The input stays instant; only the Fuse pass and the re-render of the list\n * trail behind it, which is what keeps a big index from stuttering while\n * typing. Default 400. Set `0` to search on every keystroke.\n */\n debounce?: number;\n /** Extra Fuse options, merged over the defaults. */\n fuseOptions?: IFuseOptions<T>;\n /** Anything to render inline to the right of the search box. */\n toolbar?: ReactNode;\n /** Called with the live (un-debounced) query on every keystroke. */\n onQueryChange?: (query: string) => void;\n className?: string;\n inputClassName?: string;\n listClassName?: string;\n}\n\nconst DEFAULTS = {\n includeMatches: true,\n ignoreLocation: true,\n threshold: 0.35,\n minMatchCharLength: 2,\n} satisfies IFuseOptions<unknown>;\n\nfunction getPath(obj: unknown, path: string): string {\n let cur: unknown = obj;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return '';\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur == null ? '' : String(cur);\n}\n\n/**\n * A generic, self-contained fuzzy-search list. Give it any array of JSON-like\n * objects, the {@link FuzzyListProps.keys} to search, and a `renderItem` render\n * function — it owns the search box, the Fuse index, keyboard navigation and\n * match highlighting. Reads its colours from the design tokens.\n *\n * The search box is quote-aware: a bare query fuzzy-matches, while any\n * `\"double-quoted\"` segment must appear as an exact (case-insensitive)\n * substring. The two can mix — `parser \"utils.ts\"` fuzzy-matches `parser` and\n * then keeps only rows whose fields contain the literal `utils.ts`.\n *\n * ```tsx\n * <FuzzyList\n * items={services}\n * keys={['name', 'desc']}\n * getItemKey={(s) => s.name}\n * renderItem={({ highlight, active }) => (\n * <div data-active={active}>\n * <strong>{highlight('name')}</strong>\n * <p>{highlight('desc', { snippet: true })}</p>\n * </div>\n * )}\n * />\n * ```\n */\nexport function FuzzyList<T>({\n items,\n keys,\n renderItem,\n getItemKey,\n onSelect,\n placeholder = 'Search…',\n emptyState = 'No matches.',\n autoFocus,\n limit,\n estimateSize = 60,\n overscan = 8,\n showCount = true,\n debounce = 400,\n fuseOptions,\n toolbar,\n onQueryChange,\n className,\n inputClassName,\n listClassName,\n}: FuzzyListProps<T>) {\n const [query, setQuery] = useState('');\n const [active, setActive] = useState(0);\n const apiRef = useRef<VirtualListHandle>(null);\n\n // The input is always live; the search trails it by `debounce` ms.\n const [searched, pending] = useDebouncedValue(query, debounce);\n\n const fuse = useMemo(\n () => new Fuse(items, { ...DEFAULTS, ...fuseOptions, keys }),\n [items, keys, fuseOptions],\n );\n\n const results = useMemo<Result<T>[]>(\n () => runSearch(fuse, items, keys, searched, limit),\n [fuse, searched, items, keys, limit],\n );\n\n // Keep the keyboard cursor in range as the result set changes.\n useEffect(() => {\n setActive((a) => Math.min(a, Math.max(0, results.length - 1)));\n }, [results.length]);\n\n const commit = (index: number) => {\n const r = results[index];\n if (r && onSelect) onSelect(r.item, r.refIndex);\n };\n\n // Move the keyboard cursor and keep it in view (the list is virtualized, so\n // the active row may not be mounted — ask the virtualizer to scroll to it).\n const move = (delta: number) => {\n const next = Math.min(Math.max(active + delta, 0), results.length - 1);\n setActive(next);\n apiRef.current?.scrollToIndex(next);\n };\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n move(1);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n move(-1);\n } else if (e.key === 'Enter') {\n commit(active);\n }\n };\n\n // Everything downstream (count line, highlighting, empty state) describes the\n // results, so it reads the searched query, not the one still being typed.\n const q = searched.trim();\n\n return (\n <div className={cn('flex min-h-0 flex-col', className)}>\n <div className=\"flex items-center gap-2 rounded-md border border-border bg-muted px-2.5\">\n <Search className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <input\n value={query}\n autoFocus={autoFocus}\n onChange={(e) => {\n setQuery(e.target.value);\n onQueryChange?.(e.target.value);\n }}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n spellCheck={false}\n className={cn(\n 'w-full bg-transparent py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground',\n inputClassName,\n )}\n />\n {pending && <Spinner className=\"size-3.5 shrink-0 text-muted-foreground\" />}\n {toolbar}\n </div>\n\n {showCount && (\n <div className=\"px-1 pt-2 mono text-[11px] text-muted-foreground\">\n {q ? `${results.length} of ${items.length}` : `${items.length} items`}\n </div>\n )}\n\n <VirtualList\n items={results}\n apiRef={apiRef}\n estimateSize={estimateSize}\n overscan={overscan}\n getItemKey={getItemKey ? (r, i) => getItemKey(r.item, i) : undefined}\n className={cn('min-h-0 flex-1 pt-1.5', listClassName)}\n emptyState={<p className=\"px-2 py-8 text-center text-sm text-muted-foreground\">{emptyState}</p>}\n renderItem={({ item, matches }, index) => {\n const highlight = (key: string, opts?: { snippet?: boolean; window?: number }): ReactNode => {\n const value = getPath(item, key);\n const m = matches.find((mm) => mm.key === key);\n const indices = (m?.indices ?? []) as [number, number][];\n if (indices.length === 0) return value;\n return opts?.snippet\n ? highlightSnippet(value, indices, opts.window)\n : highlightAll(value, indices);\n };\n return (\n <div\n onMouseMove={() => setActive(index)}\n onClick={() => commit(index)}\n style={{ paddingBottom: 4 }}\n >\n {renderItem({\n item,\n index,\n query: q,\n matches,\n active: index === active,\n highlight,\n select: () => commit(index),\n })}\n </div>\n );\n }}\n />\n </div>\n );\n}\n"],"names":["DEFAULTS","getPath","obj","path","cur","seg","FuzzyList","items","keys","renderItem","getItemKey","onSelect","placeholder","emptyState","autoFocus","limit","estimateSize","overscan","showCount","debounce","fuseOptions","toolbar","onQueryChange","className","inputClassName","listClassName","query","setQuery","useState","active","setActive","apiRef","useRef","searched","pending","useDebouncedValue","fuse","useMemo","Fuse","results","runSearch","useEffect","a","commit","index","r","move","delta","next","_a","onKeyDown","q","cn","jsxs","jsx","Search","Spinner","VirtualList","i","item","matches","key","opts","value","m","mm","indices","highlightSnippet","highlightAll"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { FuzzyList } from './fuzzy-list';
2
+ export type { FuzzyListProps, FuzzyRenderContext } from './fuzzy-list';
3
+ export { highlightAll, highlightSnippet } from '../../lib/highlight';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/fuzzy-list/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { Key, ReactNode } from 'react';
2
+ import { FuseOptionKey, IFuseOptions } from 'fuse.js';
3
+ import { FuzzyRenderContext } from '../fuzzy-list';
4
+ /** Items may be given up front, or loaded the first time the palette opens —
5
+ * which is how you keep a big build-time JSON index out of the initial bundle. */
6
+ export type GlobalSearchSource<T> = T[] | (() => T[] | Promise<T[]>);
7
+ export interface GlobalSearchProps<T> {
8
+ /** The searchable set, or a loader called once on first open. */
9
+ items: GlobalSearchSource<T>;
10
+ /** Fields to search. Dotted paths and weighted keys, same as {@link FuzzyList}. */
11
+ keys: FuseOptionKey<T>[];
12
+ /** Fired when a result is picked (click or Enter). */
13
+ onSelect: (item: T, index: number) => void;
14
+ /**
15
+ * Global shortcut that opens the palette — `Mod+K` (Cmd on Apple, Ctrl
16
+ * elsewhere), `Ctrl+K`, `Cmd+Shift+P`, or a bare key like `/`. Pass `null` for
17
+ * no shortcut. Default `Mod+K`.
18
+ */
19
+ searchKey?: string | null;
20
+ /** Row renderer. Defaults to title / description / badge from the `*Key` props. */
21
+ renderItem?: (ctx: FuzzyRenderContext<T>) => ReactNode;
22
+ /** Field shown as the row's title in the default renderer. Defaults to the first `keys` entry. */
23
+ titleKey?: string;
24
+ /** Field shown under the title (snippet-highlighted) in the default renderer. */
25
+ descriptionKey?: string;
26
+ /** Field shown as the right-hand badge in the default renderer (a kind/section). */
27
+ badgeKey?: string;
28
+ /** Stable React key per row. */
29
+ getItemKey?: (item: T, index: number) => Key;
30
+ placeholder?: string;
31
+ /** Shown when nothing matches. */
32
+ emptyState?: ReactNode;
33
+ /** Cap the result count. Default 50 — a palette is for finding, not browsing. */
34
+ limit?: number;
35
+ /** Search debounce, ms. Default 400 (see {@link FuzzyList}). */
36
+ debounce?: number;
37
+ /** Row-height guess for the virtual list, px. Default 56. */
38
+ estimateSize?: number;
39
+ /** Extra Fuse options. */
40
+ fuseOptions?: IFuseOptions<T>;
41
+ /** Close the palette after a selection. Default true. */
42
+ closeOnSelect?: boolean;
43
+ /** The trigger. `icon` = square search button (default), `bar` = a fake search
44
+ * field with the shortcut hint, `none` = no trigger (drive it with `open`). */
45
+ trigger?: 'icon' | 'bar' | 'none';
46
+ /** Trigger label for the `bar` variant. Default "Search…". */
47
+ triggerLabel?: string;
48
+ /** Controlled open state. Omit to let the component own it. */
49
+ open?: boolean;
50
+ onOpenChange?: (open: boolean) => void;
51
+ /** Footer hint line under the results. Pass `null` to drop it. */
52
+ hint?: ReactNode;
53
+ className?: string;
54
+ }
55
+ /**
56
+ * The Cmd-K palette, assembled from the pieces this library already ships: a
57
+ * {@link Modal} holding a {@link FuzzyList} (which is itself a debounced,
58
+ * quote-aware Fuse search over a `VirtualList`, so an index of thousands of
59
+ * entries still scrolls at 60fps and only the visible rows are in the DOM).
60
+ *
61
+ * `items` can be a loader — the palette calls it the first time it opens, which
62
+ * is how you lazily pull a static, build-time-generated `search-index.json`
63
+ * without paying for it on first paint.
64
+ *
65
+ * ```tsx
66
+ * <GlobalSearch
67
+ * searchKey="Ctrl+K"
68
+ * items={() => fetch('/search-index.json').then((r) => r.json())}
69
+ * keys={['name', 'summary', 'props']}
70
+ * titleKey="name"
71
+ * descriptionKey="summary"
72
+ * badgeKey="kind"
73
+ * onSelect={(entry) => navigate(entry.route)}
74
+ * />
75
+ * ```
76
+ */
77
+ export declare function GlobalSearch<T>({ items, keys, onSelect, searchKey, renderItem, titleKey, descriptionKey, badgeKey, getItemKey, placeholder, emptyState, limit, debounce, estimateSize, fuseOptions, closeOnSelect, trigger, triggerLabel, open: openProp, onOpenChange, hint, className, }: GlobalSearchProps<T>): import("react").JSX.Element;
78
+ //# sourceMappingURL=global-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-search.d.ts","sourceRoot":"","sources":["../../../src/components/global-search/global-search.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3F,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAKhE,OAAO,EAAa,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAKnE;kFACkF;AAClF,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAErE,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,iEAAiE;IACjE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC7B,mFAAmF;IACnF,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,sDAAsD;IACtD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mFAAmF;IACnF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACvD,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;mFAC+E;IAC/E,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAClC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kEAAkE;IAClE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAC9B,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,SAAmB,EACnB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,UAAU,EACV,WAAuB,EACvB,UAA0B,EAC1B,KAAU,EACV,QAAc,EACd,YAAiB,EACjB,WAAW,EACX,aAAoB,EACpB,OAAgB,EAChB,YAAwB,EACxB,IAAI,EAAE,QAAQ,EACd,YAAY,EACZ,IAAI,EACJ,SAAS,GACV,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAuJtB"}
@@ -0,0 +1,181 @@
1
+ import { jsxs as s, Fragment as z, jsx as e } from "react/jsx-runtime";
2
+ import { useState as m, useCallback as H, useRef as $, useEffect as L } from "react";
3
+ import "fuse.js";
4
+ import { Search as E } from "lucide-react";
5
+ import { cn as F } from "../../lib/utils.js";
6
+ import { useHotkey as K, formatHotkey as O } from "./hotkey.js";
7
+ import { Button as ee } from "../button/button.js";
8
+ import { Modal as re } from "../modal/modal.js";
9
+ import { Spinner as te } from "../spinner/spinner.js";
10
+ import { FuzzyList as ne } from "../fuzzy-list/fuzzy-list.js";
11
+ function be({
12
+ items: r,
13
+ keys: t,
14
+ onSelect: o,
15
+ searchKey: l = "Mod+K",
16
+ renderItem: q,
17
+ titleKey: M,
18
+ descriptionKey: b,
19
+ badgeKey: h,
20
+ getItemKey: R,
21
+ placeholder: B = "Search…",
22
+ emptyState: C = "No matches.",
23
+ limit: G = 50,
24
+ debounce: I = 400,
25
+ estimateSize: P = 56,
26
+ fuseOptions: D,
27
+ closeOnSelect: J = !0,
28
+ trigger: g = "icon",
29
+ triggerLabel: Q = "Search…",
30
+ open: f,
31
+ onOpenChange: d,
32
+ hint: y,
33
+ className: v
34
+ }) {
35
+ const [T, U] = m(!1), i = f ?? T, a = H(
36
+ (n) => {
37
+ f === void 0 && U(n), d == null || d(n);
38
+ },
39
+ [f, d]
40
+ ), [V, N] = m(Array.isArray(r) ? r : null), [k, S] = m(!1), [p, W] = m(null), A = $(!1);
41
+ L(() => {
42
+ Array.isArray(r) && N(r);
43
+ }, [r]), L(() => {
44
+ !i || Array.isArray(r) || A.current || (A.current = !0, S(!0), Promise.resolve(r()).then((n) => N(n)).catch((n) => W(n instanceof Error ? n.message : String(n))).finally(() => S(!1)));
45
+ }, [i, r]);
46
+ const X = H(() => a(!i), [i, a]);
47
+ K(l, X);
48
+ const c = l ? O(l) : null, Y = ({ highlight: n, item: x, active: _ }) => {
49
+ const j = M ?? oe(t), w = h ? String(se(x, h) ?? "") : "";
50
+ return /* @__PURE__ */ s(
51
+ "div",
52
+ {
53
+ className: F(
54
+ "flex items-start justify-between gap-3 rounded-lg border border-transparent px-3 py-2.5 transition-colors",
55
+ _ ? "border-border bg-muted" : "hover:bg-muted/60"
56
+ ),
57
+ children: [
58
+ /* @__PURE__ */ s("div", { className: "min-w-0", children: [
59
+ /* @__PURE__ */ e("div", { className: "mono truncate text-sm text-foreground", children: j ? n(j) : null }),
60
+ b && /* @__PURE__ */ e("p", { className: "mt-0.5 line-clamp-2 text-[13px] leading-snug text-muted-foreground", children: n(b, { snippet: !0 }) })
61
+ ] }),
62
+ w && /* @__PURE__ */ e("span", { className: "mono shrink-0 rounded border border-border px-1.5 py-0.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground", children: w })
63
+ ]
64
+ }
65
+ );
66
+ }, Z = (n, x) => {
67
+ o(n, x), J && a(!1);
68
+ };
69
+ return /* @__PURE__ */ s(z, { children: [
70
+ g === "icon" && /* @__PURE__ */ e(
71
+ ee,
72
+ {
73
+ variant: "outline",
74
+ size: "icon-md",
75
+ "aria-label": "Search",
76
+ onClick: () => a(!0),
77
+ tooltip: c ? c.join(" ") : void 0,
78
+ className: v,
79
+ children: /* @__PURE__ */ e(E, {})
80
+ }
81
+ ),
82
+ g === "bar" && /* @__PURE__ */ s(
83
+ "button",
84
+ {
85
+ type: "button",
86
+ onClick: () => a(!0),
87
+ className: F(
88
+ "flex h-9 min-w-56 items-center gap-2 rounded-md border border-border bg-[var(--surface,transparent)] px-2.5 text-sm text-muted-foreground transition-colors hover:bg-muted",
89
+ v
90
+ ),
91
+ children: [
92
+ /* @__PURE__ */ e(E, { className: "size-4 shrink-0" }),
93
+ /* @__PURE__ */ e("span", { className: "flex-1 text-left", children: Q }),
94
+ c && /* @__PURE__ */ e(u, { keys: c })
95
+ ]
96
+ }
97
+ ),
98
+ /* @__PURE__ */ e(
99
+ re,
100
+ {
101
+ open: i,
102
+ onClose: () => a(!1),
103
+ size: "lg",
104
+ hideHeader: !0,
105
+ bodyClassName: "min-h-0 flex-1 overflow-hidden p-3 sm:p-4",
106
+ className: "ds-global-search",
107
+ children: /* @__PURE__ */ s("div", { className: "flex h-[min(60vh,32rem)] min-h-0 flex-col", children: [
108
+ k && /* @__PURE__ */ e(te, { center: !0, label: "Loading index…" }),
109
+ p && /* @__PURE__ */ s("p", { className: "px-2 py-8 text-center text-sm text-destructive", children: [
110
+ "Search index failed: ",
111
+ p
112
+ ] }),
113
+ !k && !p && /* @__PURE__ */ e(
114
+ ne,
115
+ {
116
+ items: V ?? [],
117
+ keys: t,
118
+ autoFocus: !0,
119
+ debounce: I,
120
+ limit: G,
121
+ estimateSize: P,
122
+ fuseOptions: D,
123
+ getItemKey: R,
124
+ placeholder: B,
125
+ emptyState: C,
126
+ onSelect: Z,
127
+ renderItem: q ?? Y,
128
+ className: "min-h-0 flex-1",
129
+ inputClassName: "py-2.5 text-base sm:text-sm"
130
+ }
131
+ ),
132
+ y !== null && /* @__PURE__ */ e("div", { className: "mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-border px-1 pt-2 text-[11px] text-muted-foreground", children: y ?? /* @__PURE__ */ s(z, { children: [
133
+ /* @__PURE__ */ s("span", { children: [
134
+ /* @__PURE__ */ e(u, { keys: ["↑", "↓"] }),
135
+ " navigate"
136
+ ] }),
137
+ /* @__PURE__ */ s("span", { children: [
138
+ /* @__PURE__ */ e(u, { keys: ["↵"] }),
139
+ " open"
140
+ ] }),
141
+ /* @__PURE__ */ s("span", { children: [
142
+ /* @__PURE__ */ e(u, { keys: ["esc"] }),
143
+ " close"
144
+ ] }),
145
+ /* @__PURE__ */ e("span", { className: "mono", children: '"quoted" = exact match' })
146
+ ] }) })
147
+ ] })
148
+ }
149
+ )
150
+ ] });
151
+ }
152
+ function u({ keys: r }) {
153
+ return /* @__PURE__ */ e("span", { className: "inline-flex items-center gap-0.5 align-middle", children: r.map((t) => /* @__PURE__ */ e(
154
+ "kbd",
155
+ {
156
+ className: "mono rounded border border-border bg-muted px-1 py-0.5 text-[10px] leading-none text-muted-foreground",
157
+ children: t
158
+ },
159
+ t
160
+ )) });
161
+ }
162
+ function oe(r) {
163
+ const t = r[0];
164
+ if (t == null) return;
165
+ if (typeof t == "string") return t;
166
+ if (Array.isArray(t)) return t.join(".");
167
+ const o = t.name;
168
+ return Array.isArray(o) ? o.join(".") : o;
169
+ }
170
+ function se(r, t) {
171
+ let o = r;
172
+ for (const l of t.split(".")) {
173
+ if (o == null || typeof o != "object") return;
174
+ o = o[l];
175
+ }
176
+ return o;
177
+ }
178
+ export {
179
+ be as GlobalSearch
180
+ };
181
+ //# sourceMappingURL=global-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-search.js","sources":["../../../src/components/global-search/global-search.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState, type Key, type ReactNode } from 'react';\nimport { type FuseOptionKey, type IFuseOptions } from 'fuse.js';\nimport { Search } from 'lucide-react';\n\nimport { cn } from '../../lib/utils';\nimport { Button } from '../button';\nimport { FuzzyList, type FuzzyRenderContext } from '../fuzzy-list';\nimport { Modal } from '../modal';\nimport { Spinner } from '../spinner';\nimport { formatHotkey, useHotkey } from './hotkey';\n\n/** Items may be given up front, or loaded the first time the palette opens —\n * which is how you keep a big build-time JSON index out of the initial bundle. */\nexport type GlobalSearchSource<T> = T[] | (() => T[] | Promise<T[]>);\n\nexport interface GlobalSearchProps<T> {\n /** The searchable set, or a loader called once on first open. */\n items: GlobalSearchSource<T>;\n /** Fields to search. Dotted paths and weighted keys, same as {@link FuzzyList}. */\n keys: FuseOptionKey<T>[];\n /** Fired when a result is picked (click or Enter). */\n onSelect: (item: T, index: number) => void;\n /**\n * Global shortcut that opens the palette — `Mod+K` (Cmd on Apple, Ctrl\n * elsewhere), `Ctrl+K`, `Cmd+Shift+P`, or a bare key like `/`. Pass `null` for\n * no shortcut. Default `Mod+K`.\n */\n searchKey?: string | null;\n /** Row renderer. Defaults to title / description / badge from the `*Key` props. */\n renderItem?: (ctx: FuzzyRenderContext<T>) => ReactNode;\n /** Field shown as the row's title in the default renderer. Defaults to the first `keys` entry. */\n titleKey?: string;\n /** Field shown under the title (snippet-highlighted) in the default renderer. */\n descriptionKey?: string;\n /** Field shown as the right-hand badge in the default renderer (a kind/section). */\n badgeKey?: string;\n /** Stable React key per row. */\n getItemKey?: (item: T, index: number) => Key;\n placeholder?: string;\n /** Shown when nothing matches. */\n emptyState?: ReactNode;\n /** Cap the result count. Default 50 — a palette is for finding, not browsing. */\n limit?: number;\n /** Search debounce, ms. Default 400 (see {@link FuzzyList}). */\n debounce?: number;\n /** Row-height guess for the virtual list, px. Default 56. */\n estimateSize?: number;\n /** Extra Fuse options. */\n fuseOptions?: IFuseOptions<T>;\n /** Close the palette after a selection. Default true. */\n closeOnSelect?: boolean;\n /** The trigger. `icon` = square search button (default), `bar` = a fake search\n * field with the shortcut hint, `none` = no trigger (drive it with `open`). */\n trigger?: 'icon' | 'bar' | 'none';\n /** Trigger label for the `bar` variant. Default \"Search…\". */\n triggerLabel?: string;\n /** Controlled open state. Omit to let the component own it. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Footer hint line under the results. Pass `null` to drop it. */\n hint?: ReactNode;\n className?: string;\n}\n\n/**\n * The Cmd-K palette, assembled from the pieces this library already ships: a\n * {@link Modal} holding a {@link FuzzyList} (which is itself a debounced,\n * quote-aware Fuse search over a `VirtualList`, so an index of thousands of\n * entries still scrolls at 60fps and only the visible rows are in the DOM).\n *\n * `items` can be a loader — the palette calls it the first time it opens, which\n * is how you lazily pull a static, build-time-generated `search-index.json`\n * without paying for it on first paint.\n *\n * ```tsx\n * <GlobalSearch\n * searchKey=\"Ctrl+K\"\n * items={() => fetch('/search-index.json').then((r) => r.json())}\n * keys={['name', 'summary', 'props']}\n * titleKey=\"name\"\n * descriptionKey=\"summary\"\n * badgeKey=\"kind\"\n * onSelect={(entry) => navigate(entry.route)}\n * />\n * ```\n */\nexport function GlobalSearch<T>({\n items,\n keys,\n onSelect,\n searchKey = 'Mod+K',\n renderItem,\n titleKey,\n descriptionKey,\n badgeKey,\n getItemKey,\n placeholder = 'Search…',\n emptyState = 'No matches.',\n limit = 50,\n debounce = 400,\n estimateSize = 56,\n fuseOptions,\n closeOnSelect = true,\n trigger = 'icon',\n triggerLabel = 'Search…',\n open: openProp,\n onOpenChange,\n hint,\n className,\n}: GlobalSearchProps<T>) {\n const [openState, setOpenState] = useState(false);\n const open = openProp ?? openState;\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (openProp === undefined) setOpenState(next);\n onOpenChange?.(next);\n },\n [openProp, onOpenChange],\n );\n\n // Lazily resolve the source the first time the palette opens, then keep it.\n const [loaded, setLoaded] = useState<T[] | null>(Array.isArray(items) ? items : null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const requested = useRef(false);\n\n useEffect(() => {\n if (Array.isArray(items)) setLoaded(items);\n }, [items]);\n\n useEffect(() => {\n if (!open || Array.isArray(items) || requested.current) return;\n requested.current = true;\n setLoading(true);\n Promise.resolve(items())\n .then((rows) => setLoaded(rows))\n .catch((e: unknown) => setError(e instanceof Error ? e.message : String(e)))\n .finally(() => setLoading(false));\n }, [open, items]);\n\n const toggle = useCallback(() => setOpen(!open), [open, setOpen]);\n useHotkey(searchKey, toggle);\n\n const keyHint = searchKey ? formatHotkey(searchKey) : null;\n\n const defaultRender = ({ highlight, item, active }: FuzzyRenderContext<T>): ReactNode => {\n const title = titleKey ?? firstPath(keys);\n const badge = badgeKey ? String(readPath(item, badgeKey) ?? '') : '';\n return (\n <div\n className={cn(\n 'flex items-start justify-between gap-3 rounded-lg border border-transparent px-3 py-2.5 transition-colors',\n active ? 'border-border bg-muted' : 'hover:bg-muted/60',\n )}\n >\n <div className=\"min-w-0\">\n <div className=\"mono truncate text-sm text-foreground\">{title ? highlight(title) : null}</div>\n {descriptionKey && (\n <p className=\"mt-0.5 line-clamp-2 text-[13px] leading-snug text-muted-foreground\">\n {highlight(descriptionKey, { snippet: true })}\n </p>\n )}\n </div>\n {badge && (\n <span className=\"mono shrink-0 rounded border border-border px-1.5 py-0.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n );\n };\n\n const select = (item: T, index: number) => {\n onSelect(item, index);\n if (closeOnSelect) setOpen(false);\n };\n\n return (\n <>\n {trigger === 'icon' && (\n <Button\n variant=\"outline\"\n size=\"icon-md\"\n aria-label=\"Search\"\n onClick={() => setOpen(true)}\n tooltip={keyHint ? keyHint.join(' ') : undefined}\n className={className}\n >\n <Search />\n </Button>\n )}\n {trigger === 'bar' && (\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n className={cn(\n 'flex h-9 min-w-56 items-center gap-2 rounded-md border border-border bg-[var(--surface,transparent)] px-2.5 text-sm text-muted-foreground transition-colors hover:bg-muted',\n className,\n )}\n >\n <Search className=\"size-4 shrink-0\" />\n <span className=\"flex-1 text-left\">{triggerLabel}</span>\n {keyHint && <Kbd keys={keyHint} />}\n </button>\n )}\n\n <Modal\n open={open}\n onClose={() => setOpen(false)}\n size=\"lg\"\n hideHeader\n bodyClassName=\"min-h-0 flex-1 overflow-hidden p-3 sm:p-4\"\n className=\"ds-global-search\"\n >\n <div className=\"flex h-[min(60vh,32rem)] min-h-0 flex-col\">\n {loading && <Spinner center label=\"Loading index…\" />}\n {error && (\n <p className=\"px-2 py-8 text-center text-sm text-destructive\">Search index failed: {error}</p>\n )}\n {!loading && !error && (\n <FuzzyList\n items={loaded ?? []}\n keys={keys}\n autoFocus\n debounce={debounce}\n limit={limit}\n estimateSize={estimateSize}\n fuseOptions={fuseOptions}\n getItemKey={getItemKey}\n placeholder={placeholder}\n emptyState={emptyState}\n onSelect={select}\n renderItem={renderItem ?? defaultRender}\n className=\"min-h-0 flex-1\"\n inputClassName=\"py-2.5 text-base sm:text-sm\"\n />\n )}\n {hint !== null && (\n <div className=\"mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-border px-1 pt-2 text-[11px] text-muted-foreground\">\n {hint ?? (\n <>\n <span>\n <Kbd keys={['↑', '↓']} /> navigate\n </span>\n <span>\n <Kbd keys={['↵']} /> open\n </span>\n <span>\n <Kbd keys={['esc']} /> close\n </span>\n <span className=\"mono\">\"quoted\" = exact match</span>\n </>\n )}\n </div>\n )}\n </div>\n </Modal>\n </>\n );\n}\n\nfunction Kbd({ keys }: { keys: string[] }) {\n return (\n <span className=\"inline-flex items-center gap-0.5 align-middle\">\n {keys.map((k) => (\n <kbd\n key={k}\n className=\"mono rounded border border-border bg-muted px-1 py-0.5 text-[10px] leading-none text-muted-foreground\"\n >\n {k}\n </kbd>\n ))}\n </span>\n );\n}\n\n/** The first key of a Fuse `keys` list, as a dotted path — the default title field. */\nfunction firstPath<T>(keys: FuseOptionKey<T>[]): string | undefined {\n const k = keys[0];\n if (k == null) return undefined;\n if (typeof k === 'string') return k;\n if (Array.isArray(k)) return k.join('.');\n const name = (k as { name: string | string[] }).name;\n return Array.isArray(name) ? name.join('.') : name;\n}\n\nfunction readPath(obj: unknown, path: string): unknown {\n let cur: unknown = obj;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur;\n}\n"],"names":["GlobalSearch","items","keys","onSelect","searchKey","renderItem","titleKey","descriptionKey","badgeKey","getItemKey","placeholder","emptyState","limit","debounce","estimateSize","fuseOptions","closeOnSelect","trigger","triggerLabel","openProp","onOpenChange","hint","className","openState","setOpenState","useState","open","setOpen","useCallback","next","loaded","setLoaded","loading","setLoading","error","setError","requested","useRef","useEffect","rows","e","toggle","useHotkey","keyHint","formatHotkey","defaultRender","highlight","item","active","title","firstPath","badge","readPath","jsxs","cn","jsx","select","index","Fragment","Button","Search","Kbd","Modal","Spinner","FuzzyList","k","name","obj","path","cur","seg"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface Hotkey {
2
+ key: string;
3
+ ctrl: boolean;
4
+ meta: boolean;
5
+ shift: boolean;
6
+ alt: boolean;
7
+ /** `Mod` — Cmd on Apple platforms, Ctrl everywhere else. */
8
+ mod: boolean;
9
+ }
10
+ /**
11
+ * Parse a combo string — `Ctrl+K`, `Meta+K`, `Cmd+Shift+P`, `Mod+K`, `/` — into
12
+ * the flags a `keydown` handler compares against. `Mod` is the portable one: it
13
+ * means Cmd on a Mac and Ctrl elsewhere.
14
+ */
15
+ export declare function parseHotkey(combo: string): Hotkey;
16
+ /**
17
+ * Bind a global keyboard shortcut. Combos with a modifier (`Mod+K`) fire even
18
+ * while an input has focus; bare keys (`/`) stand down so they can be typed.
19
+ */
20
+ export declare function useHotkey(combo: string | null | undefined, handler: () => void, enabled?: boolean): void;
21
+ /** Render a combo the way the current platform writes it: `⌘K` / `Ctrl K`. */
22
+ export declare function formatHotkey(combo: string): string[];
23
+ //# sourceMappingURL=hotkey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkey.d.ts","sourceRoot":"","sources":["../../../src/components/global-search/hotkey.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,4DAA4D;IAC5D,GAAG,EAAE,OAAO,CAAC;CACd;AAKD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYjD;AA4BD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE,OAAO,UAAO,QAc9F;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAWpD"}
@@ -0,0 +1,41 @@
1
+ import { useEffect as l } from "react";
2
+ const s = () => typeof navigator < "u" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);
3
+ function f(e) {
4
+ const t = e.split("+").map((o) => o.trim().toLowerCase()).filter(Boolean), n = t[t.length - 1] ?? "", r = (...o) => t.slice(0, -1).some((a) => o.includes(a));
5
+ return {
6
+ key: n,
7
+ ctrl: r("ctrl", "control"),
8
+ meta: r("meta", "cmd", "command"),
9
+ shift: r("shift"),
10
+ alt: r("alt", "option"),
11
+ mod: r("mod")
12
+ };
13
+ }
14
+ function u(e, t) {
15
+ if (e.key.toLowerCase() !== t.key) return !1;
16
+ const n = s() ? e.metaKey : e.ctrlKey;
17
+ return !(t.mod && !n || t.ctrl && !e.ctrlKey || t.meta && !e.metaKey || t.shift !== e.shiftKey || t.alt !== e.altKey || !t.mod && !t.ctrl && !t.meta && (e.ctrlKey || e.metaKey));
18
+ }
19
+ function c(e) {
20
+ const t = e;
21
+ return !t || !t.tagName ? !1 : t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable;
22
+ }
23
+ function p(e, t, n = !0) {
24
+ l(() => {
25
+ if (!e || !n) return;
26
+ const r = f(e), o = !r.mod && !r.ctrl && !r.meta && !r.alt, a = (i) => {
27
+ o && c(i.target) || u(i, r) && (i.preventDefault(), t());
28
+ };
29
+ return window.addEventListener("keydown", a), () => window.removeEventListener("keydown", a);
30
+ }, [e, n, t]);
31
+ }
32
+ function y(e) {
33
+ const t = f(e), n = s(), r = [];
34
+ return t.mod && r.push(n ? "⌘" : "Ctrl"), t.ctrl && r.push(n ? "⌃" : "Ctrl"), t.meta && !t.mod && r.push(n ? "⌘" : "Win"), t.alt && r.push(n ? "⌥" : "Alt"), t.shift && r.push(n ? "⇧" : "Shift"), r.push(t.key.length === 1 ? t.key.toUpperCase() : t.key), r;
35
+ }
36
+ export {
37
+ y as formatHotkey,
38
+ f as parseHotkey,
39
+ p as useHotkey
40
+ };
41
+ //# sourceMappingURL=hotkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkey.js","sources":["../../../src/components/global-search/hotkey.ts"],"sourcesContent":["import { useEffect } from 'react';\n\nexport interface Hotkey {\n key: string;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n alt: boolean;\n /** `Mod` — Cmd on Apple platforms, Ctrl everywhere else. */\n mod: boolean;\n}\n\nconst isApple = () =>\n typeof navigator !== 'undefined' && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent);\n\n/**\n * Parse a combo string — `Ctrl+K`, `Meta+K`, `Cmd+Shift+P`, `Mod+K`, `/` — into\n * the flags a `keydown` handler compares against. `Mod` is the portable one: it\n * means Cmd on a Mac and Ctrl elsewhere.\n */\nexport function parseHotkey(combo: string): Hotkey {\n const parts = combo.split('+').map((p) => p.trim().toLowerCase()).filter(Boolean);\n const key = parts[parts.length - 1] ?? '';\n const has = (...names: string[]) => parts.slice(0, -1).some((p) => names.includes(p));\n return {\n key,\n ctrl: has('ctrl', 'control'),\n meta: has('meta', 'cmd', 'command'),\n shift: has('shift'),\n alt: has('alt', 'option'),\n mod: has('mod'),\n };\n}\n\nfunction matches(e: KeyboardEvent, h: Hotkey): boolean {\n if (e.key.toLowerCase() !== h.key) return false;\n const mod = isApple() ? e.metaKey : e.ctrlKey;\n if (h.mod && !mod) return false;\n if (h.ctrl && !e.ctrlKey) return false;\n if (h.meta && !e.metaKey) return false;\n if (h.shift !== e.shiftKey) return false;\n if (h.alt !== e.altKey) return false;\n // A bare key (no modifier in the combo) must not fire while a modifier is held\n // — `/` shouldn't hijack Ctrl+/.\n if (!h.mod && !h.ctrl && !h.meta && (e.ctrlKey || e.metaKey)) return false;\n return true;\n}\n\n/** Whether the event came from somewhere the user is typing. */\nfunction isTyping(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null;\n if (!el || !el.tagName) return false;\n return (\n el.tagName === 'INPUT' ||\n el.tagName === 'TEXTAREA' ||\n el.tagName === 'SELECT' ||\n el.isContentEditable\n );\n}\n\n/**\n * Bind a global keyboard shortcut. Combos with a modifier (`Mod+K`) fire even\n * while an input has focus; bare keys (`/`) stand down so they can be typed.\n */\nexport function useHotkey(combo: string | null | undefined, handler: () => void, enabled = true) {\n useEffect(() => {\n if (!combo || !enabled) return;\n const hk = parseHotkey(combo);\n const bare = !hk.mod && !hk.ctrl && !hk.meta && !hk.alt;\n const onKeyDown = (e: KeyboardEvent) => {\n if (bare && isTyping(e.target)) return;\n if (!matches(e, hk)) return;\n e.preventDefault();\n handler();\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [combo, enabled, handler]);\n}\n\n/** Render a combo the way the current platform writes it: `⌘K` / `Ctrl K`. */\nexport function formatHotkey(combo: string): string[] {\n const hk = parseHotkey(combo);\n const apple = isApple();\n const out: string[] = [];\n if (hk.mod) out.push(apple ? '⌘' : 'Ctrl');\n if (hk.ctrl) out.push(apple ? '⌃' : 'Ctrl');\n if (hk.meta && !hk.mod) out.push(apple ? '⌘' : 'Win');\n if (hk.alt) out.push(apple ? '⌥' : 'Alt');\n if (hk.shift) out.push(apple ? '⇧' : 'Shift');\n out.push(hk.key.length === 1 ? hk.key.toUpperCase() : hk.key);\n return out;\n}\n"],"names":["isApple","parseHotkey","combo","parts","p","key","has","names","matches","h","mod","isTyping","target","el","useHotkey","handler","enabled","useEffect","hk","bare","onKeyDown","e","formatHotkey","apple","out"],"mappings":";AAYA,MAAMA,IAAU,MACd,OAAO,YAAc,OAAe,wBAAwB,KAAK,UAAU,YAAY,UAAU,SAAS;AAOrG,SAASC,EAAYC,GAAuB;AACjD,QAAMC,IAAQD,EAAM,MAAM,GAAG,EAAE,IAAI,CAACE,MAAMA,EAAE,OAAO,YAAA,CAAa,EAAE,OAAO,OAAO,GAC1EC,IAAMF,EAAMA,EAAM,SAAS,CAAC,KAAK,IACjCG,IAAM,IAAIC,MAAoBJ,EAAM,MAAM,GAAG,EAAE,EAAE,KAAK,CAACC,MAAMG,EAAM,SAASH,CAAC,CAAC;AACpF,SAAO;AAAA,IACL,KAAAC;AAAA,IACA,MAAMC,EAAI,QAAQ,SAAS;AAAA,IAC3B,MAAMA,EAAI,QAAQ,OAAO,SAAS;AAAA,IAClC,OAAOA,EAAI,OAAO;AAAA,IAClB,KAAKA,EAAI,OAAO,QAAQ;AAAA,IACxB,KAAKA,EAAI,KAAK;AAAA,EAAA;AAElB;AAEA,SAASE,EAAQ,GAAkBC,GAAoB;AACrD,MAAI,EAAE,IAAI,YAAA,MAAkBA,EAAE,IAAK,QAAO;AAC1C,QAAMC,IAAMV,EAAA,IAAY,EAAE,UAAU,EAAE;AAQtC,SAPI,EAAAS,EAAE,OAAO,CAACC,KACVD,EAAE,QAAQ,CAAC,EAAE,WACbA,EAAE,QAAQ,CAAC,EAAE,WACbA,EAAE,UAAU,EAAE,YACdA,EAAE,QAAQ,EAAE,UAGZ,CAACA,EAAE,OAAO,CAACA,EAAE,QAAQ,CAACA,EAAE,SAAS,EAAE,WAAW,EAAE;AAEtD;AAGA,SAASE,EAASC,GAAqC;AACrD,QAAMC,IAAKD;AACX,SAAI,CAACC,KAAM,CAACA,EAAG,UAAgB,KAE7BA,EAAG,YAAY,WACfA,EAAG,YAAY,cACfA,EAAG,YAAY,YACfA,EAAG;AAEP;AAMO,SAASC,EAAUZ,GAAkCa,GAAqBC,IAAU,IAAM;AAC/F,EAAAC,EAAU,MAAM;AACd,QAAI,CAACf,KAAS,CAACc,EAAS;AACxB,UAAME,IAAKjB,EAAYC,CAAK,GACtBiB,IAAO,CAACD,EAAG,OAAO,CAACA,EAAG,QAAQ,CAACA,EAAG,QAAQ,CAACA,EAAG,KAC9CE,IAAY,CAACC,MAAqB;AACtC,MAAIF,KAAQR,EAASU,EAAE,MAAM,KACxBb,EAAQa,GAAGH,CAAE,MAClBG,EAAE,eAAA,GACFN,EAAA;AAAA,IACF;AACA,kBAAO,iBAAiB,WAAWK,CAAS,GACrC,MAAM,OAAO,oBAAoB,WAAWA,CAAS;AAAA,EAC9D,GAAG,CAAClB,GAAOc,GAASD,CAAO,CAAC;AAC9B;AAGO,SAASO,EAAapB,GAAyB;AACpD,QAAMgB,IAAKjB,EAAYC,CAAK,GACtBqB,IAAQvB,EAAA,GACRwB,IAAgB,CAAA;AACtB,SAAIN,EAAG,OAAKM,EAAI,KAAKD,IAAQ,MAAM,MAAM,GACrCL,EAAG,QAAMM,EAAI,KAAKD,IAAQ,MAAM,MAAM,GACtCL,EAAG,QAAQ,CAACA,EAAG,OAAKM,EAAI,KAAKD,IAAQ,MAAM,KAAK,GAChDL,EAAG,OAAKM,EAAI,KAAKD,IAAQ,MAAM,KAAK,GACpCL,EAAG,SAAOM,EAAI,KAAKD,IAAQ,MAAM,OAAO,GAC5CC,EAAI,KAAKN,EAAG,IAAI,WAAW,IAAIA,EAAG,IAAI,gBAAgBA,EAAG,GAAG,GACrDM;AACT;"}
@@ -0,0 +1,5 @@
1
+ export { GlobalSearch } from './global-search';
2
+ export type { GlobalSearchProps, GlobalSearchSource } from './global-search';
3
+ export { formatHotkey, parseHotkey, useHotkey } from './hotkey';
4
+ export type { Hotkey } from './hotkey';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/global-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChE,YAAY,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,64 @@
1
+ import * as React from 'react';
2
+ export type IframePreviewDevice = 'desktop' | 'phone';
3
+ export interface IframePreviewOverlayProps {
4
+ open: boolean;
5
+ onClose: () => void;
6
+ /** The page to frame. Changing it (while open) navigates the iframe. */
7
+ url: string;
8
+ /** Called whenever the user commits a new URL in the address field. */
9
+ onUrlChange?: (url: string) => void;
10
+ title?: string;
11
+ /** Show the editable address field. Default `true`. */
12
+ editableUrl?: boolean;
13
+ /** Extra controls, rendered in the toolbar next to the built-in ones. */
14
+ actions?: React.ReactNode;
15
+ /** Phone/desktop tier toggle (desktop viewports only). Default `true`. */
16
+ devices?: boolean;
17
+ device?: IframePreviewDevice;
18
+ onDeviceChange?: (device: IframePreviewDevice) => void;
19
+ /**
20
+ * Append a cache-busting query param on every (re)load, so a just-deployed
21
+ * page can't be served from the browser cache. Default `false`.
22
+ */
23
+ cacheBust?: boolean;
24
+ sandbox?: string;
25
+ allow?: string;
26
+ className?: string;
27
+ /** Rendered under the toolbar, above the frame — a banner, a tab bar… */
28
+ children?: React.ReactNode;
29
+ }
30
+ /**
31
+ * The full-screen half of {@link IframePreview}, driven entirely from props —
32
+ * use it directly when the trigger lives somewhere else (a menu item, a
33
+ * floating gizmo) or when the URL is owned by the app.
34
+ *
35
+ * The iframe is keyed on the resolved source, so every open — and every hit of
36
+ * the reload button — remounts it and re-fetches the page rather than showing a
37
+ * stale render.
38
+ */
39
+ export declare function IframePreviewOverlay({ open, onClose, url, onUrlChange, title, editableUrl, actions, devices, device: deviceProp, onDeviceChange, cacheBust, sandbox, allow, className, children, }: IframePreviewOverlayProps): React.ReactPortal | null;
40
+ export interface IframePreviewProps extends Omit<IframePreviewOverlayProps, 'open' | 'onClose' | 'url' | 'children'> {
41
+ /** Initial URL. The field can navigate away from it; reopening resets to it. */
42
+ url: string;
43
+ /** Controlled open state. Omit to let the component own it. */
44
+ open?: boolean;
45
+ defaultOpen?: boolean;
46
+ onOpenChange?: (open: boolean) => void;
47
+ /** Custom trigger. A render prop gets `open()`; a node is wrapped in a button. */
48
+ children?: React.ReactNode | ((api: {
49
+ open: () => void;
50
+ }) => React.ReactNode);
51
+ /** Label of the default button trigger. */
52
+ label?: string;
53
+ /** Class for the default trigger. */
54
+ triggerClassName?: string;
55
+ }
56
+ /**
57
+ * A trigger — a button by default, any element you like — that opens the page
58
+ * at `url` full-screen in an iframe, with an editable address field, a reload
59
+ * that really re-fetches, a phone/desktop tier and a slot for your own
60
+ * controls. Built for phones: `100dvh`, safe-area padding, tap-sized buttons
61
+ * and a toolbar that stays one row wide.
62
+ */
63
+ export declare function IframePreview({ url, open: openProp, defaultOpen, onOpenChange, children, label, triggerClassName, className, ...overlay }: IframePreviewProps): React.JSX.Element;
64
+ //# sourceMappingURL=iframe-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe-preview.d.ts","sourceRoot":"","sources":["../../../src/components/iframe-preview/iframe-preview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgB/B,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC;AAQtD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yEAAyE;IACzE,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACvD;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,OAAO,EACP,GAAG,EACH,WAAW,EACX,KAAK,EACL,WAAkB,EAClB,OAAO,EACP,OAAc,EACd,MAAM,EAAE,UAAU,EAClB,cAAc,EACd,SAAiB,EACjB,OAAO,EACP,KAAkD,EAClD,SAAS,EACT,QAAQ,GACT,EAAE,yBAAyB,4BAkM3B;AAED,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,yBAAyB,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,UAAU,CAAC;IAChF,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9E,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC5B,GAAG,EACH,IAAI,EAAE,QAAQ,EACd,WAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,SAAS,EACT,GAAG,OAAO,EACX,EAAE,kBAAkB,qBAgDpB"}