@kodffe/ui 0.0.0-stage → 0.10.1

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 (304) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +11 -0
  2. package/dist/accordion/accordion.d.ts +44 -0
  3. package/dist/accordion/accordion.js +84 -0
  4. package/dist/accordion/accordion.js.map +1 -0
  5. package/dist/alert/alert.d.ts +17 -0
  6. package/dist/alert/alert.js +59 -0
  7. package/dist/alert/alert.js.map +1 -0
  8. package/dist/app-shell/app-footer.d.ts +29 -0
  9. package/dist/app-shell/app-footer.js +39 -0
  10. package/dist/app-shell/app-footer.js.map +1 -0
  11. package/dist/app-shell/app-shell-context.d.ts +10 -0
  12. package/dist/app-shell/app-shell-context.js +12 -0
  13. package/dist/app-shell/app-shell-context.js.map +1 -0
  14. package/dist/app-shell/app-shell.d.ts +42 -0
  15. package/dist/app-shell/app-shell.js +191 -0
  16. package/dist/app-shell/app-shell.js.map +1 -0
  17. package/dist/app-shell/floating-actions.d.ts +19 -0
  18. package/dist/app-shell/floating-actions.js +59 -0
  19. package/dist/app-shell/floating-actions.js.map +1 -0
  20. package/dist/app-shell/workspace-switcher.d.ts +25 -0
  21. package/dist/app-shell/workspace-switcher.js +82 -0
  22. package/dist/app-shell/workspace-switcher.js.map +1 -0
  23. package/dist/badge/badge.d.ts +19 -0
  24. package/dist/badge/badge.js +59 -0
  25. package/dist/badge/badge.js.map +1 -0
  26. package/dist/banner/banner.d.ts +22 -0
  27. package/dist/banner/banner.js +80 -0
  28. package/dist/banner/banner.js.map +1 -0
  29. package/dist/breadcrumbs/breadcrumbs.d.ts +18 -0
  30. package/dist/breadcrumbs/breadcrumbs.js +45 -0
  31. package/dist/breadcrumbs/breadcrumbs.js.map +1 -0
  32. package/dist/button/button.d.ts +38 -0
  33. package/dist/button/button.js +83 -0
  34. package/dist/button/button.js.map +1 -0
  35. package/dist/card/card.d.ts +159 -0
  36. package/dist/card/card.js +390 -0
  37. package/dist/card/card.js.map +1 -0
  38. package/dist/card/insight-card.d.ts +19 -0
  39. package/dist/card/insight-card.js +51 -0
  40. package/dist/card/insight-card.js.map +1 -0
  41. package/dist/card/integration-card.d.ts +19 -0
  42. package/dist/card/integration-card.js +70 -0
  43. package/dist/card/integration-card.js.map +1 -0
  44. package/dist/charts/charts.d.ts +75 -0
  45. package/dist/charts/charts.js +453 -0
  46. package/dist/charts/charts.js.map +1 -0
  47. package/dist/choice/choice.d.ts +39 -0
  48. package/dist/choice/choice.js +143 -0
  49. package/dist/choice/choice.js.map +1 -0
  50. package/dist/combobox/combobox.d.ts +46 -0
  51. package/dist/combobox/combobox.js +196 -0
  52. package/dist/combobox/combobox.js.map +1 -0
  53. package/dist/command-palette/command-palette.d.ts +35 -0
  54. package/dist/command-palette/command-palette.js +164 -0
  55. package/dist/command-palette/command-palette.js.map +1 -0
  56. package/dist/confirm-dialog/confirm-dialog.d.ts +37 -0
  57. package/dist/confirm-dialog/confirm-dialog.js +106 -0
  58. package/dist/confirm-dialog/confirm-dialog.js.map +1 -0
  59. package/dist/content/assistant.d.ts +86 -0
  60. package/dist/content/assistant.js +213 -0
  61. package/dist/content/assistant.js.map +1 -0
  62. package/dist/content/content.d.ts +45 -0
  63. package/dist/content/content.js +136 -0
  64. package/dist/content/content.js.map +1 -0
  65. package/dist/data-display/avatar-sizes.d.ts +8 -0
  66. package/dist/data-display/avatar-sizes.js +12 -0
  67. package/dist/data-display/avatar-sizes.js.map +1 -0
  68. package/dist/data-display/avatar.d.ts +21 -0
  69. package/dist/data-display/avatar.js +53 -0
  70. package/dist/data-display/avatar.js.map +1 -0
  71. package/dist/data-display/chip.d.ts +20 -0
  72. package/dist/data-display/chip.js +64 -0
  73. package/dist/data-display/chip.js.map +1 -0
  74. package/dist/data-display/code-block.d.ts +14 -0
  75. package/dist/data-display/code-block.js +50 -0
  76. package/dist/data-display/code-block.js.map +1 -0
  77. package/dist/data-display/data-display.d.ts +73 -0
  78. package/dist/data-display/data-display.js +227 -0
  79. package/dist/data-display/data-display.js.map +1 -0
  80. package/dist/data-display/insights.d.ts +120 -0
  81. package/dist/data-display/insights.js +220 -0
  82. package/dist/data-display/insights.js.map +1 -0
  83. package/dist/data-table/cells.d.ts +86 -0
  84. package/dist/data-table/cells.js +163 -0
  85. package/dist/data-table/cells.js.map +1 -0
  86. package/dist/data-table/data-table.d.ts +112 -0
  87. package/dist/data-table/data-table.js +558 -0
  88. package/dist/data-table/data-table.js.map +1 -0
  89. package/dist/date-picker/date-picker.d.ts +61 -0
  90. package/dist/date-picker/date-picker.js +309 -0
  91. package/dist/date-picker/date-picker.js.map +1 -0
  92. package/dist/drawer/drawer.d.ts +32 -0
  93. package/dist/drawer/drawer.js +72 -0
  94. package/dist/drawer/drawer.js.map +1 -0
  95. package/dist/empty-state/empty-state.d.ts +25 -0
  96. package/dist/empty-state/empty-state.js +78 -0
  97. package/dist/empty-state/empty-state.js.map +1 -0
  98. package/dist/error-state/error-state.d.ts +19 -0
  99. package/dist/error-state/error-state.js +56 -0
  100. package/dist/error-state/error-state.js.map +1 -0
  101. package/dist/event-calendar/calendar-logic.test.d.ts +1 -0
  102. package/dist/event-calendar/dates.d.ts +35 -0
  103. package/dist/event-calendar/dates.js +55 -0
  104. package/dist/event-calendar/dates.js.map +1 -0
  105. package/dist/event-calendar/event-calendar.d.ts +125 -0
  106. package/dist/event-calendar/event-calendar.js +795 -0
  107. package/dist/event-calendar/event-calendar.js.map +1 -0
  108. package/dist/event-calendar/event-details.d.ts +50 -0
  109. package/dist/event-calendar/event-details.js +124 -0
  110. package/dist/event-calendar/event-details.js.map +1 -0
  111. package/dist/event-calendar/layout.d.ts +48 -0
  112. package/dist/event-calendar/layout.js +55 -0
  113. package/dist/event-calendar/layout.js.map +1 -0
  114. package/dist/file-upload/file-upload.d.ts +70 -0
  115. package/dist/file-upload/file-upload.js +307 -0
  116. package/dist/file-upload/file-upload.js.map +1 -0
  117. package/dist/filters/filters.d.ts +48 -0
  118. package/dist/filters/filters.js +103 -0
  119. package/dist/filters/filters.js.map +1 -0
  120. package/dist/form-field/form-field.d.ts +39 -0
  121. package/dist/form-field/form-field.js +88 -0
  122. package/dist/form-field/form-field.js.map +1 -0
  123. package/dist/hover-card/hover-card.d.ts +15 -0
  124. package/dist/hover-card/hover-card.js +27 -0
  125. package/dist/hover-card/hover-card.js.map +1 -0
  126. package/dist/hover-card/person-hover-card.d.ts +26 -0
  127. package/dist/hover-card/person-hover-card.js +85 -0
  128. package/dist/hover-card/person-hover-card.js.map +1 -0
  129. package/dist/icon/icon-tile.d.ts +20 -0
  130. package/dist/icon/icon-tile.js +55 -0
  131. package/dist/icon/icon-tile.js.map +1 -0
  132. package/dist/icon/icon.d.ts +14 -0
  133. package/dist/icon/icon.js +28 -0
  134. package/dist/icon/icon.js.map +1 -0
  135. package/dist/icon/icons.generated.d.ts +358 -0
  136. package/dist/icon/icons.generated.js +362 -0
  137. package/dist/icon/icons.generated.js.map +1 -0
  138. package/dist/index.d.ts +90 -0
  139. package/dist/index.js +88 -0
  140. package/dist/input/extra-inputs.d.ts +122 -0
  141. package/dist/input/extra-inputs.js +351 -0
  142. package/dist/input/extra-inputs.js.map +1 -0
  143. package/dist/input/field-styles.d.ts +5 -0
  144. package/dist/input/field-styles.js +14 -0
  145. package/dist/input/field-styles.js.map +1 -0
  146. package/dist/input/input.d.ts +50 -0
  147. package/dist/input/input.js +107 -0
  148. package/dist/input/input.js.map +1 -0
  149. package/dist/layout/layout.d.ts +41 -0
  150. package/dist/layout/layout.js +90 -0
  151. package/dist/layout/layout.js.map +1 -0
  152. package/dist/lib/control-styles.d.ts +9 -0
  153. package/dist/lib/control-styles.js +16 -0
  154. package/dist/lib/control-styles.js.map +1 -0
  155. package/dist/lib/cx.d.ts +2 -0
  156. package/dist/lib/cx.js +8 -0
  157. package/dist/lib/cx.js.map +1 -0
  158. package/dist/lib/glyphs.d.ts +13 -0
  159. package/dist/lib/glyphs.js +67 -0
  160. package/dist/lib/glyphs.js.map +1 -0
  161. package/dist/lib/segmented-styles.d.ts +8 -0
  162. package/dist/lib/segmented-styles.js +12 -0
  163. package/dist/lib/segmented-styles.js.map +1 -0
  164. package/dist/lib/select-on-arrow.d.ts +7 -0
  165. package/dist/lib/select-on-arrow.js +21 -0
  166. package/dist/lib/select-on-arrow.js.map +1 -0
  167. package/dist/lib/skip-link.d.ts +5 -0
  168. package/dist/lib/skip-link.js +13 -0
  169. package/dist/lib/skip-link.js.map +1 -0
  170. package/dist/lib/use-media-query.d.ts +4 -0
  171. package/dist/lib/use-media-query.js +15 -0
  172. package/dist/lib/use-media-query.js.map +1 -0
  173. package/dist/lists/lists.d.ts +76 -0
  174. package/dist/lists/lists.js +133 -0
  175. package/dist/lists/lists.js.map +1 -0
  176. package/dist/locale-switch/locale-switch.d.ts +29 -0
  177. package/dist/locale-switch/locale-switch.js +62 -0
  178. package/dist/locale-switch/locale-switch.js.map +1 -0
  179. package/dist/logo/logo.d.ts +31 -0
  180. package/dist/logo/logo.js +157 -0
  181. package/dist/logo/logo.js.map +1 -0
  182. package/dist/logo/product-logo.d.ts +19 -0
  183. package/dist/logo/product-logo.js +46 -0
  184. package/dist/logo/product-logo.js.map +1 -0
  185. package/dist/marketing/marketing.d.ts +176 -0
  186. package/dist/marketing/marketing.js +451 -0
  187. package/dist/marketing/marketing.js.map +1 -0
  188. package/dist/marketing/newsletter-form.d.ts +21 -0
  189. package/dist/marketing/newsletter-form.js +100 -0
  190. package/dist/marketing/newsletter-form.js.map +1 -0
  191. package/dist/mascot/mascot.d.ts +28 -0
  192. package/dist/mascot/mascot.js +28 -0
  193. package/dist/mascot/mascot.js.map +1 -0
  194. package/dist/mascot/mascots.generated.d.ts +284 -0
  195. package/dist/mascot/mascots.generated.js +287 -0
  196. package/dist/mascot/mascots.generated.js.map +1 -0
  197. package/dist/master-detail/master-detail.d.ts +30 -0
  198. package/dist/master-detail/master-detail.js +71 -0
  199. package/dist/master-detail/master-detail.js.map +1 -0
  200. package/dist/menu/account-menu.d.ts +44 -0
  201. package/dist/menu/account-menu.js +78 -0
  202. package/dist/menu/account-menu.js.map +1 -0
  203. package/dist/menu/context-menu.d.ts +31 -0
  204. package/dist/menu/context-menu.js +111 -0
  205. package/dist/menu/context-menu.js.map +1 -0
  206. package/dist/menu/dropdown-menu.d.ts +49 -0
  207. package/dist/menu/dropdown-menu.js +152 -0
  208. package/dist/menu/dropdown-menu.js.map +1 -0
  209. package/dist/menu/menu-styles.d.ts +8 -0
  210. package/dist/menu/menu-styles.js +6 -0
  211. package/dist/menu/menu-styles.js.map +1 -0
  212. package/dist/menu/menubar.d.ts +31 -0
  213. package/dist/menu/menubar.js +125 -0
  214. package/dist/menu/menubar.js.map +1 -0
  215. package/dist/modal/modal.d.ts +34 -0
  216. package/dist/modal/modal.js +58 -0
  217. package/dist/modal/modal.js.map +1 -0
  218. package/dist/notification-center/notification-center.d.ts +51 -0
  219. package/dist/notification-center/notification-center.js +244 -0
  220. package/dist/notification-center/notification-center.js.map +1 -0
  221. package/dist/otp-input/otp-input.d.ts +23 -0
  222. package/dist/otp-input/otp-input.js +61 -0
  223. package/dist/otp-input/otp-input.js.map +1 -0
  224. package/dist/overlay/overlay.d.ts +53 -0
  225. package/dist/overlay/overlay.js +103 -0
  226. package/dist/overlay/overlay.js.map +1 -0
  227. package/dist/page-header/page-header.d.ts +55 -0
  228. package/dist/page-header/page-header.js +114 -0
  229. package/dist/page-header/page-header.js.map +1 -0
  230. package/dist/page-header/record-headers.d.ts +51 -0
  231. package/dist/page-header/record-headers.js +134 -0
  232. package/dist/page-header/record-headers.js.map +1 -0
  233. package/dist/page-header/section-header.d.ts +21 -0
  234. package/dist/page-header/section-header.js +44 -0
  235. package/dist/page-header/section-header.js.map +1 -0
  236. package/dist/page-navigation/page-navigation.d.ts +59 -0
  237. package/dist/page-navigation/page-navigation.js +136 -0
  238. package/dist/page-navigation/page-navigation.js.map +1 -0
  239. package/dist/pagination/pagination.d.ts +28 -0
  240. package/dist/pagination/pagination.js +102 -0
  241. package/dist/pagination/pagination.js.map +1 -0
  242. package/dist/phone-input/phone-input.d.ts +34 -0
  243. package/dist/phone-input/phone-input.js +171 -0
  244. package/dist/phone-input/phone-input.js.map +1 -0
  245. package/dist/popover/popover.d.ts +23 -0
  246. package/dist/popover/popover.js +40 -0
  247. package/dist/popover/popover.js.map +1 -0
  248. package/dist/progress/progress.d.ts +21 -0
  249. package/dist/progress/progress.js +49 -0
  250. package/dist/progress/progress.js.map +1 -0
  251. package/dist/segmented-control/segmented-control.d.ts +32 -0
  252. package/dist/segmented-control/segmented-control.js +29 -0
  253. package/dist/segmented-control/segmented-control.js.map +1 -0
  254. package/dist/select/select.d.ts +48 -0
  255. package/dist/select/select.js +136 -0
  256. package/dist/select/select.js.map +1 -0
  257. package/dist/settings/permission-matrix.d.ts +29 -0
  258. package/dist/settings/permission-matrix.js +101 -0
  259. package/dist/settings/permission-matrix.js.map +1 -0
  260. package/dist/settings/settings-row.d.ts +32 -0
  261. package/dist/settings/settings-row.js +63 -0
  262. package/dist/settings/settings-row.js.map +1 -0
  263. package/dist/side-nav/side-nav.d.ts +36 -0
  264. package/dist/side-nav/side-nav.js +123 -0
  265. package/dist/side-nav/side-nav.js.map +1 -0
  266. package/dist/site-header/site-header.d.ts +32 -0
  267. package/dist/site-header/site-header.js +99 -0
  268. package/dist/site-header/site-header.js.map +1 -0
  269. package/dist/skeleton/skeleton.d.ts +16 -0
  270. package/dist/skeleton/skeleton.js +19 -0
  271. package/dist/skeleton/skeleton.js.map +1 -0
  272. package/dist/slider/slider.d.ts +15 -0
  273. package/dist/slider/slider.js +48 -0
  274. package/dist/slider/slider.js.map +1 -0
  275. package/dist/spinner/spinner.d.ts +15 -0
  276. package/dist/spinner/spinner.js +42 -0
  277. package/dist/spinner/spinner.js.map +1 -0
  278. package/dist/stepper/step-dots.d.ts +16 -0
  279. package/dist/stepper/step-dots.js +26 -0
  280. package/dist/stepper/step-dots.js.map +1 -0
  281. package/dist/stepper/stepper.d.ts +26 -0
  282. package/dist/stepper/stepper.js +113 -0
  283. package/dist/stepper/stepper.js.map +1 -0
  284. package/dist/tabs/tabs.d.ts +31 -0
  285. package/dist/tabs/tabs.js +66 -0
  286. package/dist/tabs/tabs.js.map +1 -0
  287. package/dist/templates/app-templates.d.ts +126 -0
  288. package/dist/templates/app-templates.js +153 -0
  289. package/dist/templates/app-templates.js.map +1 -0
  290. package/dist/templates/site-templates.d.ts +49 -0
  291. package/dist/templates/site-templates.js +110 -0
  292. package/dist/templates/site-templates.js.map +1 -0
  293. package/dist/toast/toast-store.d.ts +54 -0
  294. package/dist/toast/toast-store.js +49 -0
  295. package/dist/toast/toast-store.js.map +1 -0
  296. package/dist/toast/toaster.d.ts +15 -0
  297. package/dist/toast/toaster.js +124 -0
  298. package/dist/toast/toaster.js.map +1 -0
  299. package/dist/tooltip/tooltip.d.ts +29 -0
  300. package/dist/tooltip/tooltip.js +54 -0
  301. package/dist/tooltip/tooltip.js.map +1 -0
  302. package/package.json +88 -3
  303. package/styles.css +521 -0
  304. package/README.md +0 -3
@@ -0,0 +1,164 @@
1
+ "use client";
2
+ import { cx as e } from "../lib/cx.js";
3
+ import { Icon as t } from "../icon/icon.js";
4
+ import { EmptyState as n } from "../empty-state/empty-state.js";
5
+ import { Glyph as r } from "../lib/glyphs.js";
6
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
+ import { useEffect as o, useId as s, useMemo as c, useRef as l, useState as u } from "react";
8
+ import * as d from "@radix-ui/react-dialog";
9
+ //#region src/command-palette/command-palette.tsx
10
+ var f = (e) => e.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "");
11
+ function p(e, t) {
12
+ let n = f(t).split(/\s+/).filter(Boolean);
13
+ return n.length ? e.map((e) => {
14
+ let t = e.items.map((e) => {
15
+ let t = f([
16
+ e.label,
17
+ e.hint,
18
+ ...e.keywords ?? []
19
+ ].join(" "));
20
+ return n.every((e) => t.includes(e)) ? {
21
+ item: e,
22
+ score: +!f(e.label).startsWith(n[0])
23
+ } : null;
24
+ }).filter((e) => e !== null).sort((e, t) => e.score - t.score);
25
+ return {
26
+ heading: e.heading,
27
+ items: t.map((e) => e.item)
28
+ };
29
+ }).filter((e) => e.items.length > 0) : e;
30
+ }
31
+ function m({ open: f, onOpenChange: m, groups: h, placeholder: g = "Search actions and pages…", emptyTitle: _ = "No matches", emptyDescription: v = "Try another word, or check the spelling.", label: y = "Command palette", hotkey: b = !0 }) {
32
+ let [x, S] = u(""), [C, w] = u(0), T = s(), E = l(null), D = c(() => p(h, x), [h, x]), O = D.flatMap((e) => e.items);
33
+ o(() => {
34
+ if (!b) return;
35
+ let e = (e) => {
36
+ e.key.toLowerCase() === "k" && (e.metaKey || e.ctrlKey) && (e.preventDefault(), m(!f));
37
+ };
38
+ return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
39
+ }, [
40
+ b,
41
+ f,
42
+ m
43
+ ]), o(() => w(0), [x]), o(() => {
44
+ f || S("");
45
+ }, [f]), o(() => {
46
+ E.current?.querySelector("[data-active=\"true\"]")?.scrollIntoView({ block: "nearest" });
47
+ }, [C]);
48
+ let k = (e) => {
49
+ e && (m(!1), e.onSelect());
50
+ }, A = (e) => {
51
+ e.key === "ArrowDown" ? (e.preventDefault(), w((e) => O.length ? (e + 1) % O.length : 0)) : e.key === "ArrowUp" ? (e.preventDefault(), w((e) => O.length ? (e - 1 + O.length) % O.length : 0)) : e.key === "Home" ? w(0) : e.key === "End" ? w(Math.max(0, O.length - 1)) : e.key === "Enter" && (e.preventDefault(), k(O[C]));
52
+ }, j = -1, M = (e) => `${T}-opt-${e}`;
53
+ return /* @__PURE__ */ i(d.Root, {
54
+ open: f,
55
+ onOpenChange: m,
56
+ children: /* @__PURE__ */ a(d.Portal, { children: [/* @__PURE__ */ i(d.Overlay, { className: "kf-overlay fixed inset-0 z-50 bg-overlay" }), /* @__PURE__ */ a(d.Content, {
57
+ "aria-describedby": void 0,
58
+ className: e("kf-palette fixed inset-0 z-50 flex flex-col bg-surface font-sans text-fg shadow-overlay focus:outline-none", "pt-[env(safe-area-inset-top)] sm:inset-x-0 sm:top-[12vh] sm:bottom-auto sm:mx-auto sm:max-h-[min(34rem,76vh)] sm:w-[calc(100%-2rem)] sm:max-w-xl sm:rounded-xl sm:border sm:border-border sm:pt-0"),
59
+ children: [
60
+ /* @__PURE__ */ i(d.Title, {
61
+ className: "sr-only",
62
+ children: y
63
+ }),
64
+ /* @__PURE__ */ a("div", {
65
+ className: "flex items-center gap-3 border-b border-border px-4",
66
+ children: [
67
+ /* @__PURE__ */ i(r, {
68
+ name: "search",
69
+ size: 20,
70
+ className: "shrink-0 text-fg-muted"
71
+ }),
72
+ /* @__PURE__ */ i("input", {
73
+ autoFocus: !0,
74
+ role: "combobox",
75
+ "aria-expanded": "true",
76
+ "aria-controls": T,
77
+ "aria-autocomplete": "list",
78
+ "aria-activedescendant": O.length ? M(C) : void 0,
79
+ "aria-label": g,
80
+ placeholder: g,
81
+ value: x,
82
+ onChange: (e) => S(e.target.value),
83
+ onKeyDown: A,
84
+ className: "h-14 min-w-0 flex-1 border-0 bg-transparent font-sans text-base text-fg outline-none placeholder:text-fg-muted"
85
+ }),
86
+ /* @__PURE__ */ i(d.Close, {
87
+ className: "cursor-pointer rounded-xs border border-border bg-transparent px-1.5 py-0.5 font-mono text-[11px] text-fg-muted focus-visible:outline-3 focus-visible:outline-focus",
88
+ children: "Esc"
89
+ })
90
+ ]
91
+ }),
92
+ /* @__PURE__ */ i("div", {
93
+ ref: E,
94
+ id: T,
95
+ role: "listbox",
96
+ "aria-label": y,
97
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain p-2",
98
+ children: D.length === 0 ? /* @__PURE__ */ i(n, {
99
+ size: "sm",
100
+ mascot: "lost",
101
+ headingLevel: 3,
102
+ title: _,
103
+ description: v
104
+ }) : D.map((n) => /* @__PURE__ */ a("div", {
105
+ role: "group",
106
+ "aria-label": n.heading,
107
+ className: "mb-1",
108
+ children: [/* @__PURE__ */ i("div", {
109
+ "aria-hidden": "true",
110
+ className: "px-3 pt-2 pb-1 text-xs font-semibold tracking-wide text-fg-muted uppercase",
111
+ children: n.heading
112
+ }), n.items.map((n) => {
113
+ j += 1;
114
+ let r = j, o = r === C;
115
+ return /* @__PURE__ */ a("div", {
116
+ id: M(r),
117
+ role: "option",
118
+ "aria-selected": o,
119
+ "data-active": o,
120
+ onMouseMove: () => w(r),
121
+ onClick: () => k(n),
122
+ className: e("flex min-h-11 cursor-pointer items-center gap-3 rounded-sm px-3 py-2 text-[15px]", o && "bg-surface-muted"),
123
+ children: [
124
+ n.icon && /* @__PURE__ */ i(t, {
125
+ name: n.icon,
126
+ size: 22,
127
+ className: o ? "text-link" : "text-fg-muted"
128
+ }),
129
+ /* @__PURE__ */ a("span", {
130
+ className: "min-w-0 flex-1",
131
+ children: [/* @__PURE__ */ i("span", {
132
+ className: "block truncate font-medium",
133
+ children: n.label
134
+ }), n.hint && /* @__PURE__ */ i("span", {
135
+ className: "block truncate text-xs text-fg-muted",
136
+ children: n.hint
137
+ })]
138
+ }),
139
+ n.shortcut && /* @__PURE__ */ i("kbd", {
140
+ className: "font-mono text-xs text-fg-muted",
141
+ children: n.shortcut
142
+ })
143
+ ]
144
+ }, n.id);
145
+ })]
146
+ }, n.heading))
147
+ }),
148
+ /* @__PURE__ */ a("div", {
149
+ "aria-hidden": "true",
150
+ className: "hidden gap-4 border-t border-border px-4 py-2 text-xs text-fg-muted sm:flex",
151
+ children: [
152
+ /* @__PURE__ */ i("span", { children: "↑↓ to move" }),
153
+ /* @__PURE__ */ i("span", { children: "↵ to run" }),
154
+ /* @__PURE__ */ i("span", { children: "esc to close" })
155
+ ]
156
+ })
157
+ ]
158
+ })] })
159
+ });
160
+ }
161
+ //#endregion
162
+ export { m as CommandPalette, p as filterCommands };
163
+
164
+ //# sourceMappingURL=command-palette.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-palette.js","names":["Dialog","normalize","s","filterCommands","words","query","groups","scored","g","haystack","item","w","x","a","b","CommandPalette","setQuery","useState","active","setActive","listId","useId","listRef","useRef","filtered","useMemo","flat","useEffect","hotkey","onKey","onOpenChange","open","run","onKeyDown","index","optionId","i","cx","label","Glyph","placeholder","EmptyState","emptyTitle","emptyDescription","group","isActive","Icon"],"sources":["../../src/command-palette/command-palette.tsx"],"sourcesContent":["'use client';\n\nimport * as Dialog from '@radix-ui/react-dialog';\nimport { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport { cx } from '../lib/cx';\nimport { Glyph } from '../lib/glyphs';\nimport { Icon, type IconName } from '../icon/icon';\nimport { EmptyState } from '../empty-state/empty-state';\n\nexport interface CommandItem {\n id: string;\n label: string;\n /** Secondary text (e.g. a path or description). */\n hint?: string;\n icon?: IconName;\n shortcut?: string;\n /** Extra search terms (synonyms, Spanish words…). */\n keywords?: string[];\n onSelect: () => void;\n}\n\nexport interface CommandGroup {\n heading: string;\n items: CommandItem[];\n}\n\nexport interface CommandPaletteProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n groups: CommandGroup[];\n placeholder?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n /** Accessible name of the dialog. */\n label?: string;\n /** Opens with ⌘K / Ctrl+K. Set `false` to wire your own shortcut. */\n hotkey?: boolean;\n}\n\nconst normalize = (s: string) => s.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');\n\n/** Every query word must appear in the label, hint or keywords (accent-insensitive). Label-start matches rank first. */\nexport function filterCommands(groups: CommandGroup[], query: string): CommandGroup[] {\n const words = normalize(query).split(/\\s+/).filter(Boolean);\n if (!words.length) return groups;\n return groups\n .map((g) => {\n const scored = g.items\n .map((item) => {\n const haystack = normalize([item.label, item.hint, ...(item.keywords ?? [])].join(' '));\n if (!words.every((w) => haystack.includes(w))) return null;\n return { item, score: normalize(item.label).startsWith(words[0]!) ? 0 : 1 };\n })\n .filter((x): x is { item: CommandItem; score: number } => x !== null)\n .sort((a, b) => a.score - b.score);\n return { heading: g.heading, items: scored.map((s) => s.item) };\n })\n .filter((g) => g.items.length > 0);\n}\n\n/**\n * ⌘K search across a product's actions and pages. Combobox pattern: type to filter, arrows to\n * move, Enter to run, Escape to close. Full-screen sheet on mobile.\n */\nexport function CommandPalette({\n open,\n onOpenChange,\n groups,\n placeholder = 'Search actions and pages…',\n emptyTitle = 'No matches',\n emptyDescription = 'Try another word, or check the spelling.',\n label = 'Command palette',\n hotkey = true,\n}: CommandPaletteProps) {\n const [query, setQuery] = useState('');\n const [active, setActive] = useState(0);\n const listId = useId();\n const listRef = useRef<HTMLDivElement>(null);\n const filtered = useMemo(() => filterCommands(groups, query), [groups, query]);\n const flat = filtered.flatMap((g) => g.items);\n\n useEffect(() => {\n if (!hotkey) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key.toLowerCase() === 'k' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n onOpenChange(!open);\n }\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [hotkey, open, onOpenChange]);\n\n useEffect(() => setActive(0), [query]);\n useEffect(() => {\n if (!open) setQuery('');\n }, [open]);\n useEffect(() => {\n listRef.current?.querySelector('[data-active=\"true\"]')?.scrollIntoView({ block: 'nearest' });\n }, [active]);\n\n const run = (item: CommandItem | undefined) => {\n if (!item) return;\n onOpenChange(false);\n item.onSelect();\n };\n\n const onKeyDown = (e: ReactKeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setActive((a) => (flat.length ? (a + 1) % flat.length : 0));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setActive((a) => (flat.length ? (a - 1 + flat.length) % flat.length : 0));\n } else if (e.key === 'Home') {\n setActive(0);\n } else if (e.key === 'End') {\n setActive(Math.max(0, flat.length - 1));\n } else if (e.key === 'Enter') {\n e.preventDefault();\n run(flat[active]);\n }\n };\n\n let index = -1;\n const optionId = (i: number) => `${listId}-opt-${i}`;\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"kf-overlay fixed inset-0 z-50 bg-overlay\" />\n <Dialog.Content\n aria-describedby={undefined}\n className={cx(\n 'kf-palette fixed inset-0 z-50 flex flex-col bg-surface font-sans text-fg shadow-overlay focus:outline-none',\n 'pt-[env(safe-area-inset-top)] sm:inset-x-0 sm:top-[12vh] sm:bottom-auto sm:mx-auto sm:max-h-[min(34rem,76vh)] sm:w-[calc(100%-2rem)] sm:max-w-xl sm:rounded-xl sm:border sm:border-border sm:pt-0',\n )}\n >\n <Dialog.Title className=\"sr-only\">{label}</Dialog.Title>\n <div className=\"flex items-center gap-3 border-b border-border px-4\">\n <Glyph name=\"search\" size={20} className=\"shrink-0 text-fg-muted\" />\n <input\n autoFocus\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n aria-activedescendant={flat.length ? optionId(active) : undefined}\n aria-label={placeholder}\n placeholder={placeholder}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n className=\"h-14 min-w-0 flex-1 border-0 bg-transparent font-sans text-base text-fg outline-none placeholder:text-fg-muted\"\n />\n <Dialog.Close className=\"cursor-pointer rounded-xs border border-border bg-transparent px-1.5 py-0.5 font-mono text-[11px] text-fg-muted focus-visible:outline-3 focus-visible:outline-focus\">\n Esc\n </Dialog.Close>\n </div>\n <div\n ref={listRef}\n id={listId}\n role=\"listbox\"\n aria-label={label}\n className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain p-2\"\n >\n {filtered.length === 0 ? (\n <EmptyState size=\"sm\" mascot=\"lost\" headingLevel={3} title={emptyTitle} description={emptyDescription} />\n ) : (\n filtered.map((group) => (\n <div key={group.heading} role=\"group\" aria-label={group.heading} className=\"mb-1\">\n <div\n aria-hidden=\"true\"\n className=\"px-3 pt-2 pb-1 text-xs font-semibold tracking-wide text-fg-muted uppercase\"\n >\n {group.heading}\n </div>\n {group.items.map((item) => {\n index += 1;\n const i = index;\n const isActive = i === active;\n return (\n <div\n key={item.id}\n id={optionId(i)}\n role=\"option\"\n aria-selected={isActive}\n data-active={isActive}\n onMouseMove={() => setActive(i)}\n onClick={() => run(item)}\n className={cx(\n 'flex min-h-11 cursor-pointer items-center gap-3 rounded-sm px-3 py-2 text-[15px]',\n isActive && 'bg-surface-muted',\n )}\n >\n {item.icon && (\n <Icon name={item.icon} size={22} className={isActive ? 'text-link' : 'text-fg-muted'} />\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate font-medium\">{item.label}</span>\n {item.hint && <span className=\"block truncate text-xs text-fg-muted\">{item.hint}</span>}\n </span>\n {item.shortcut && <kbd className=\"font-mono text-xs text-fg-muted\">{item.shortcut}</kbd>}\n </div>\n );\n })}\n </div>\n ))\n )}\n </div>\n <div\n aria-hidden=\"true\"\n className=\"hidden gap-4 border-t border-border px-4 py-2 text-xs text-fg-muted sm:flex\"\n >\n <span>↑↓ to move</span>\n <span>↵ to run</span>\n <span>esc to close</span>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { type ReactElement, type ReactNode } from 'react';
2
+ export type ConfirmTone = 'default' | 'danger';
3
+ export interface ConfirmDialogProps {
4
+ /** Element that opens the dialog (usually a Button). Omit when controlling `open`. */
5
+ trigger?: ReactElement;
6
+ open?: boolean;
7
+ onOpenChange?: (open: boolean) => void;
8
+ /** State the action and its object: "Delete “Invoice intake”?" */
9
+ title: ReactNode;
10
+ /** Consequences: what is lost, what keeps working. */
11
+ description?: ReactNode;
12
+ /** Extra content between description and actions (e.g. a list of affected items). */
13
+ children?: ReactNode;
14
+ tone?: ConfirmTone;
15
+ /** Verb that matches the title: "Delete workflow", not "OK". */
16
+ confirmLabel: string;
17
+ cancelLabel?: string;
18
+ /**
19
+ * Typed confirmation for irreversible, high-impact actions: the confirm button stays disabled
20
+ * until the user types this exact text.
21
+ */
22
+ confirmText?: string;
23
+ /** Label for the typed-confirmation field. `{text}` is replaced by `confirmText`. */
24
+ confirmTextLabel?: string;
25
+ /**
26
+ * Runs on confirm. If it returns a promise, the dialog shows a loading state and stays open until
27
+ * it settles; if it rejects, the error message is shown inside the dialog and it stays open.
28
+ */
29
+ onConfirm: () => void | Promise<unknown>;
30
+ onCancel?: () => void;
31
+ }
32
+ /**
33
+ * Confirmation for destructive or irreversible actions. Uses `role="alertdialog"`: focus starts on
34
+ * Cancel, clicking the backdrop does not close it, Escape cancels. For reversible actions prefer
35
+ * acting immediately and offering Undo in a toast.
36
+ */
37
+ export declare function ConfirmDialog({ trigger, open: openProp, onOpenChange, title, description, children, tone, confirmLabel, cancelLabel, confirmText, confirmTextLabel, onConfirm, onCancel, }: ConfirmDialogProps): import("react").JSX.Element;
@@ -0,0 +1,106 @@
1
+ "use client";
2
+ import { cx as e } from "../lib/cx.js";
3
+ import { Icon as t } from "../icon/icon.js";
4
+ import { Button as n } from "../button/button.js";
5
+ import { Alert as r } from "../alert/alert.js";
6
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
+ import { useId as o, useRef as s, useState as c } from "react";
8
+ import * as l from "@radix-ui/react-alert-dialog";
9
+ //#region src/confirm-dialog/confirm-dialog.tsx
10
+ function u({ trigger: u, open: d, onOpenChange: f, title: p, description: m, children: h, tone: g = "danger", confirmLabel: _, cancelLabel: v = "Cancel", confirmText: y, confirmTextLabel: b = "Type {text} to confirm", onConfirm: x, onCancel: S }) {
11
+ let [C, w] = c(!1), [T, E] = c(""), [D, O] = c(!1), [k, A] = c(null), j = s(null), M = o(), N = d ?? C, P = (e) => {
12
+ D || (e || (E(""), A(null)), d === void 0 && w(e), f?.(e));
13
+ }, F = async () => {
14
+ A(null);
15
+ try {
16
+ let e = x();
17
+ e instanceof Promise && (O(!0), await e), O(!1), E(""), d === void 0 && w(!1), f?.(!1);
18
+ } catch (e) {
19
+ O(!1), A(e instanceof Error ? e.message : "Something went wrong. Try again.");
20
+ }
21
+ }, I = y !== void 0 && T.trim() !== y;
22
+ return /* @__PURE__ */ a(l.Root, {
23
+ open: N,
24
+ onOpenChange: P,
25
+ children: [u && /* @__PURE__ */ i(l.Trigger, {
26
+ asChild: !0,
27
+ children: u
28
+ }), /* @__PURE__ */ a(l.Portal, { children: [/* @__PURE__ */ i(l.Overlay, { className: "kf-overlay fixed inset-0 z-50 bg-overlay" }), /* @__PURE__ */ a(l.Content, {
29
+ ...m ? {} : { "aria-describedby": void 0 },
30
+ onOpenAutoFocus: (e) => {
31
+ y !== void 0 && (e.preventDefault(), j.current?.focus());
32
+ },
33
+ onEscapeKeyDown: (e) => D && e.preventDefault(),
34
+ className: e("kf-modal fixed inset-x-0 bottom-0 z-50 flex max-h-[92dvh] flex-col gap-5 overflow-y-auto rounded-t-xl bg-surface p-6 font-sans text-fg shadow-overlay", "pb-[max(1.5rem,env(safe-area-inset-bottom))] focus:outline-none", "sm:inset-0 sm:m-auto sm:h-fit sm:w-[calc(100%-2rem)] sm:max-w-md sm:rounded-xl sm:pb-6"),
35
+ children: [
36
+ /* @__PURE__ */ a("div", {
37
+ className: "flex items-start gap-4",
38
+ children: [g === "danger" && /* @__PURE__ */ i("span", {
39
+ className: "grid size-11 shrink-0 place-items-center rounded-full bg-danger-surface text-danger-icon",
40
+ children: /* @__PURE__ */ i(t, {
41
+ name: "warning",
42
+ size: 24
43
+ })
44
+ }), /* @__PURE__ */ a("div", {
45
+ className: "min-w-0 flex-1",
46
+ children: [/* @__PURE__ */ i(l.Title, {
47
+ className: "m-0 font-display text-xl font-bold tracking-tight text-balance",
48
+ children: p
49
+ }), m && /* @__PURE__ */ i(l.Description, {
50
+ className: "m-0 mt-1.5 text-[15px] text-fg-muted",
51
+ children: m
52
+ })]
53
+ })]
54
+ }),
55
+ h,
56
+ y !== void 0 && /* @__PURE__ */ a("div", {
57
+ className: "grid gap-1.5",
58
+ children: [/* @__PURE__ */ i("label", {
59
+ htmlFor: M,
60
+ className: "text-sm font-medium",
61
+ children: b.split("{text}").flatMap((e, t) => t === 0 ? [e] : [/* @__PURE__ */ i("code", {
62
+ className: "rounded-xs bg-surface-muted px-1.5 py-0.5 font-mono text-[13px]",
63
+ children: y
64
+ }, t), e])
65
+ }), /* @__PURE__ */ i("input", {
66
+ id: M,
67
+ ref: j,
68
+ value: T,
69
+ onChange: (e) => E(e.target.value),
70
+ autoComplete: "off",
71
+ autoCapitalize: "off",
72
+ spellCheck: !1,
73
+ disabled: D,
74
+ className: "h-11 rounded-sm border border-border bg-bg px-3 font-mono text-[15px] text-fg focus-visible:outline-3 focus-visible:outline-offset-0 focus-visible:outline-focus"
75
+ })]
76
+ }),
77
+ k && /* @__PURE__ */ i(r, {
78
+ variant: "danger",
79
+ title: k
80
+ }),
81
+ /* @__PURE__ */ a("div", {
82
+ className: "flex flex-col-reverse gap-2 *:w-full sm:flex-row sm:justify-end sm:*:w-auto",
83
+ children: [/* @__PURE__ */ i(l.Cancel, {
84
+ asChild: !0,
85
+ children: /* @__PURE__ */ i(n, {
86
+ variant: "secondary",
87
+ disabled: D,
88
+ onClick: S,
89
+ children: v
90
+ })
91
+ }), /* @__PURE__ */ i(n, {
92
+ variant: g === "danger" ? "danger" : "primary",
93
+ loading: D,
94
+ "aria-disabled": I || void 0,
95
+ onClick: () => !I && F(),
96
+ children: _
97
+ })]
98
+ })
99
+ ]
100
+ })] })]
101
+ });
102
+ }
103
+ //#endregion
104
+ export { u as ConfirmDialog };
105
+
106
+ //# sourceMappingURL=confirm-dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirm-dialog.js","names":["AlertDialog","ConfirmDialog","openProp","uncontrolled","setUncontrolled","useState","typed","setTyped","pending","setPending","error","setError","inputRef","useRef","inputId","useId","open","setOpen","next","onOpenChange","confirm","result","onConfirm","blocked","confirmText","trigger","description","cx","tone","Icon","title","children","confirmTextLabel","i","part","Alert","Button","onCancel","cancelLabel","confirmLabel"],"sources":["../../src/confirm-dialog/confirm-dialog.tsx"],"sourcesContent":["'use client';\n\nimport * as AlertDialog from '@radix-ui/react-alert-dialog';\nimport { useId, useRef, useState, type ReactElement, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\nimport { Button } from '../button/button';\nimport { Alert } from '../alert/alert';\nimport { Icon } from '../icon/icon';\n\nexport type ConfirmTone = 'default' | 'danger';\n\nexport interface ConfirmDialogProps {\n /** Element that opens the dialog (usually a Button). Omit when controlling `open`. */\n trigger?: ReactElement;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** State the action and its object: \"Delete “Invoice intake”?\" */\n title: ReactNode;\n /** Consequences: what is lost, what keeps working. */\n description?: ReactNode;\n /** Extra content between description and actions (e.g. a list of affected items). */\n children?: ReactNode;\n tone?: ConfirmTone;\n /** Verb that matches the title: \"Delete workflow\", not \"OK\". */\n confirmLabel: string;\n cancelLabel?: string;\n /**\n * Typed confirmation for irreversible, high-impact actions: the confirm button stays disabled\n * until the user types this exact text.\n */\n confirmText?: string;\n /** Label for the typed-confirmation field. `{text}` is replaced by `confirmText`. */\n confirmTextLabel?: string;\n /**\n * Runs on confirm. If it returns a promise, the dialog shows a loading state and stays open until\n * it settles; if it rejects, the error message is shown inside the dialog and it stays open.\n */\n onConfirm: () => void | Promise<unknown>;\n onCancel?: () => void;\n}\n\n/**\n * Confirmation for destructive or irreversible actions. Uses `role=\"alertdialog\"`: focus starts on\n * Cancel, clicking the backdrop does not close it, Escape cancels. For reversible actions prefer\n * acting immediately and offering Undo in a toast.\n */\nexport function ConfirmDialog({\n trigger,\n open: openProp,\n onOpenChange,\n title,\n description,\n children,\n tone = 'danger',\n confirmLabel,\n cancelLabel = 'Cancel',\n confirmText,\n confirmTextLabel = 'Type {text} to confirm',\n onConfirm,\n onCancel,\n}: ConfirmDialogProps) {\n const [uncontrolled, setUncontrolled] = useState(false);\n const [typed, setTyped] = useState('');\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const inputId = useId();\n const open = openProp ?? uncontrolled;\n\n const setOpen = (next: boolean) => {\n if (pending) return;\n if (!next) {\n setTyped('');\n setError(null);\n }\n if (openProp === undefined) setUncontrolled(next);\n onOpenChange?.(next);\n };\n\n const confirm = async () => {\n setError(null);\n try {\n const result = onConfirm();\n if (result instanceof Promise) {\n setPending(true);\n await result;\n }\n setPending(false);\n setTyped('');\n if (openProp === undefined) setUncontrolled(false);\n onOpenChange?.(false);\n } catch (e) {\n setPending(false);\n setError(e instanceof Error ? e.message : 'Something went wrong. Try again.');\n }\n };\n\n const blocked = confirmText !== undefined && typed.trim() !== confirmText;\n\n return (\n <AlertDialog.Root open={open} onOpenChange={setOpen}>\n {trigger && <AlertDialog.Trigger asChild>{trigger}</AlertDialog.Trigger>}\n <AlertDialog.Portal>\n <AlertDialog.Overlay className=\"kf-overlay fixed inset-0 z-50 bg-overlay\" />\n <AlertDialog.Content\n {...(description ? {} : { 'aria-describedby': undefined })}\n onOpenAutoFocus={(e) => {\n if (confirmText !== undefined) {\n e.preventDefault();\n inputRef.current?.focus();\n }\n }}\n onEscapeKeyDown={(e) => pending && e.preventDefault()}\n className={cx(\n 'kf-modal fixed inset-x-0 bottom-0 z-50 flex max-h-[92dvh] flex-col gap-5 overflow-y-auto rounded-t-xl bg-surface p-6 font-sans text-fg shadow-overlay',\n 'pb-[max(1.5rem,env(safe-area-inset-bottom))] focus:outline-none',\n 'sm:inset-0 sm:m-auto sm:h-fit sm:w-[calc(100%-2rem)] sm:max-w-md sm:rounded-xl sm:pb-6',\n )}\n >\n <div className=\"flex items-start gap-4\">\n {tone === 'danger' && (\n <span className=\"grid size-11 shrink-0 place-items-center rounded-full bg-danger-surface text-danger-icon\">\n <Icon name=\"warning\" size={24} />\n </span>\n )}\n <div className=\"min-w-0 flex-1\">\n <AlertDialog.Title className=\"m-0 font-display text-xl font-bold tracking-tight text-balance\">{title}</AlertDialog.Title>\n {description && <AlertDialog.Description className=\"m-0 mt-1.5 text-[15px] text-fg-muted\">{description}</AlertDialog.Description>}\n </div>\n </div>\n\n {children}\n\n {confirmText !== undefined && (\n <div className=\"grid gap-1.5\">\n <label htmlFor={inputId} className=\"text-sm font-medium\">\n {confirmTextLabel.split('{text}').flatMap((part, i) =>\n i === 0 ? [part] : [<code key={i} className=\"rounded-xs bg-surface-muted px-1.5 py-0.5 font-mono text-[13px]\">{confirmText}</code>, part],\n )}\n </label>\n <input\n id={inputId}\n ref={inputRef}\n value={typed}\n onChange={(e) => setTyped(e.target.value)}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n disabled={pending}\n className=\"h-11 rounded-sm border border-border bg-bg px-3 font-mono text-[15px] text-fg focus-visible:outline-3 focus-visible:outline-offset-0 focus-visible:outline-focus\"\n />\n </div>\n )}\n\n {error && <Alert variant=\"danger\" title={error} />}\n\n <div className=\"flex flex-col-reverse gap-2 *:w-full sm:flex-row sm:justify-end sm:*:w-auto\">\n <AlertDialog.Cancel asChild>\n <Button variant=\"secondary\" disabled={pending} onClick={onCancel}>\n {cancelLabel}\n </Button>\n </AlertDialog.Cancel>\n <Button\n variant={tone === 'danger' ? 'danger' : 'primary'}\n loading={pending}\n aria-disabled={blocked || undefined}\n onClick={() => !blocked && confirm()}\n >\n {confirmLabel}\n </Button>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { type ReactElement, type ReactNode } from 'react';
2
+ import { type IconName } from '../icon/icon';
3
+ /** Soft pills with ready-made prompts; picking one sends it (or fills the composer). */
4
+ export declare function PromptSuggestions({ suggestions, onPick, label, className, }: {
5
+ suggestions: string[];
6
+ onPick: (prompt: string) => void;
7
+ label?: string;
8
+ className?: string;
9
+ }): import("react").JSX.Element;
10
+ export interface ChatComposerProps {
11
+ onSend: (text: string) => void;
12
+ placeholder?: string;
13
+ /** While the assistant answers: sending is disabled. */
14
+ busy?: boolean;
15
+ /** Controlled text (to fill it from a suggestion). */
16
+ value?: string;
17
+ onValueChange?: (value: string) => void;
18
+ labels?: {
19
+ message?: string;
20
+ send?: string;
21
+ };
22
+ className?: string;
23
+ }
24
+ /** The message field and send button. Enter sends, Shift+Enter adds a line. */
25
+ export declare function ChatComposer({ onSend, placeholder, busy, value, onValueChange, labels, className, }: ChatComposerProps): import("react").JSX.Element;
26
+ export interface ChatMessage {
27
+ id: string;
28
+ role: 'user' | 'assistant';
29
+ content: ReactNode;
30
+ }
31
+ export interface ChatPanelProps {
32
+ /** Assistant name in the header ("Kudi"). */
33
+ title: string;
34
+ messages: ChatMessage[];
35
+ onSend: (text: string) => void;
36
+ /** Shows the typing indicator and disables sending. */
37
+ busy?: boolean;
38
+ suggestions?: string[];
39
+ /** One highlighted suggestion above the composer ("Summarize this week"). */
40
+ pinned?: string;
41
+ onMinimize?: () => void;
42
+ /** The assistant's avatar or mark in the header. */
43
+ mark?: ReactNode;
44
+ labels?: {
45
+ ai?: string;
46
+ minimize?: string;
47
+ typing?: string;
48
+ log?: string;
49
+ };
50
+ className?: string;
51
+ }
52
+ /**
53
+ * The assistant window: brand header with an "AI" badge and minimize, the message log, suggestion pills, a pinned
54
+ * suggestion and the composer. Wire `onSend` to your AI endpoint; new messages are announced politely.
55
+ */
56
+ export declare function ChatPanel({ title, messages, onSend, busy, suggestions, pinned, onMinimize, mark, labels, className, }: ChatPanelProps): import("react").JSX.Element;
57
+ export interface QuickPanelProps {
58
+ /** The element that opens it, usually a `FloatingActions` secondary button or any button. */
59
+ trigger: ReactElement;
60
+ /** Product mark in the header. */
61
+ mark?: ReactNode;
62
+ workspace: string;
63
+ user: {
64
+ name: string;
65
+ avatarSrc?: string;
66
+ };
67
+ stats?: {
68
+ label: string;
69
+ value: ReactNode;
70
+ }[];
71
+ actions?: {
72
+ label: string;
73
+ icon: IconName;
74
+ onClick: () => void;
75
+ }[];
76
+ links?: {
77
+ label: string;
78
+ href: string;
79
+ }[];
80
+ label?: string;
81
+ }
82
+ /**
83
+ * Quick actions in a popover from the floating button: brand header (mark, workspace, avatar), a stats strip,
84
+ * primary actions and footer links.
85
+ */
86
+ export declare function QuickPanel({ trigger, mark, workspace, user, stats, actions, links, label, }: QuickPanelProps): import("react").JSX.Element;
@@ -0,0 +1,213 @@
1
+ "use client";
2
+ import { cx as e } from "../lib/cx.js";
3
+ import { Icon as t } from "../icon/icon.js";
4
+ import { IconButton as n } from "../button/button.js";
5
+ import { floatingSurface as r } from "../popover/popover.js";
6
+ import { Glyph as i } from "../lib/glyphs.js";
7
+ import { Avatar as a } from "../data-display/avatar.js";
8
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
9
+ import { useEffect as c, useId as l, useRef as u, useState as d } from "react";
10
+ import * as f from "@radix-ui/react-popover";
11
+ //#region src/content/assistant.tsx
12
+ function p({ suggestions: t, onPick: n, label: r = "Suggestions", className: i }) {
13
+ return /* @__PURE__ */ o("ul", {
14
+ "aria-label": r,
15
+ className: e("m-0 flex list-none flex-wrap gap-2 p-0 font-sans", i),
16
+ children: t.map((e) => /* @__PURE__ */ o("li", { children: /* @__PURE__ */ o("button", {
17
+ type: "button",
18
+ onClick: () => n(e),
19
+ className: "cursor-pointer rounded-full border border-accent/40 bg-accent/10 px-3 py-1.5 text-left text-sm font-medium text-fg hover:bg-accent/20 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus",
20
+ children: e
21
+ }) }, e))
22
+ });
23
+ }
24
+ function m({ onSend: t, placeholder: r = "Ask anything…", busy: i, value: a, onValueChange: c, labels: l = {}, className: u }) {
25
+ let [f, p] = d(""), m = a ?? f, h = (e) => c ? c(e) : p(e), g = (e) => {
26
+ e?.preventDefault();
27
+ let n = m.trim();
28
+ n && !i && (t(n), h(""));
29
+ };
30
+ return /* @__PURE__ */ s("form", {
31
+ onSubmit: g,
32
+ className: e("flex items-end gap-2 rounded-lg border border-border bg-bg p-1.5 pl-3 focus-within:border-primary", u),
33
+ children: [/* @__PURE__ */ o("textarea", {
34
+ "aria-label": l.message ?? "Message",
35
+ rows: 1,
36
+ value: m,
37
+ placeholder: r,
38
+ onChange: (e) => h(e.target.value),
39
+ onKeyDown: (e) => {
40
+ e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), g());
41
+ },
42
+ className: "max-h-32 min-h-9 flex-1 resize-none border-0 bg-transparent py-2 font-sans text-base text-fg outline-none [field-sizing:content] placeholder:text-fg-muted/80 sm:text-[15px]"
43
+ }), /* @__PURE__ */ o(n, {
44
+ type: "submit",
45
+ icon: "arrow-right",
46
+ label: l.send ?? "Send",
47
+ variant: "primary",
48
+ disabled: i || !m.trim()
49
+ })]
50
+ });
51
+ }
52
+ function h({ title: n, messages: r, onSend: a, busy: f, suggestions: h = [], pinned: g, onMinimize: _, mark: v, labels: y = {}, className: b }) {
53
+ let x = u(null), S = l(), [C, w] = d("");
54
+ return c(() => {
55
+ x.current?.scrollTo({ top: x.current.scrollHeight });
56
+ }, [r.length, f]), /* @__PURE__ */ s("section", {
57
+ "aria-labelledby": S,
58
+ className: e("flex h-[min(36rem,calc(100dvh-6rem))] w-full max-w-sm flex-col overflow-hidden rounded-xl border border-border bg-surface font-sans shadow-overlay", b),
59
+ children: [
60
+ /* @__PURE__ */ s("div", {
61
+ "data-theme": "dark",
62
+ className: "flex items-center gap-3 bg-primary-strong px-4 py-3 text-fg",
63
+ children: [
64
+ v ?? /* @__PURE__ */ o("span", {
65
+ "aria-hidden": "true",
66
+ className: "grid size-8 place-items-center rounded-full bg-white/12",
67
+ children: /* @__PURE__ */ o(t, {
68
+ name: "ai",
69
+ size: 18
70
+ })
71
+ }),
72
+ /* @__PURE__ */ s("h2", {
73
+ id: S,
74
+ className: "m-0 flex-1 text-[15px] font-semibold",
75
+ children: [n, /* @__PURE__ */ o("span", {
76
+ className: "ml-2 rounded-full bg-accent px-1.5 py-0.5 align-middle text-[10px] font-bold text-on-accent",
77
+ children: y.ai ?? "AI"
78
+ })]
79
+ }),
80
+ _ && /* @__PURE__ */ o("button", {
81
+ type: "button",
82
+ "aria-label": y.minimize ?? "Minimize",
83
+ onClick: _,
84
+ className: "grid size-8 cursor-pointer place-items-center rounded-full border-0 bg-transparent text-white hover:bg-white/15 focus-visible:outline-3 focus-visible:outline-white",
85
+ children: /* @__PURE__ */ o(i, {
86
+ name: "minus",
87
+ size: 18
88
+ })
89
+ })
90
+ ]
91
+ }),
92
+ /* @__PURE__ */ s("div", {
93
+ ref: x,
94
+ role: "log",
95
+ "aria-label": y.log ?? "Conversation",
96
+ "aria-live": "polite",
97
+ className: "grid flex-1 content-start gap-3 overflow-y-auto p-4",
98
+ children: [r.map((t) => /* @__PURE__ */ o("div", {
99
+ className: e("max-w-[85%] rounded-2xl px-3.5 py-2.5 text-sm", t.role === "user" ? "justify-self-end rounded-br-sm bg-primary text-on-primary" : "justify-self-start rounded-bl-sm bg-surface-muted text-fg"),
100
+ children: t.content
101
+ }, t.id)), f && /* @__PURE__ */ o("div", {
102
+ className: "flex w-fit items-center gap-1 rounded-2xl rounded-bl-sm bg-surface-muted px-3.5 py-3",
103
+ role: "status",
104
+ "aria-label": y.typing ?? `${n} is typing`,
105
+ children: [
106
+ 0,
107
+ 1,
108
+ 2
109
+ ].map((e) => /* @__PURE__ */ o("span", {
110
+ "aria-hidden": "true",
111
+ className: "size-1.5 animate-pulse rounded-full bg-fg-muted motion-reduce:animate-none",
112
+ style: { animationDelay: `${e * 150}ms` }
113
+ }, e))
114
+ })]
115
+ }),
116
+ /* @__PURE__ */ s("div", {
117
+ className: "grid gap-3 border-t border-border p-3",
118
+ children: [
119
+ h.length > 0 && r.length === 0 && /* @__PURE__ */ o(p, {
120
+ suggestions: h,
121
+ onPick: (e) => !f && a(e)
122
+ }),
123
+ g && /* @__PURE__ */ s("button", {
124
+ type: "button",
125
+ disabled: f,
126
+ onClick: () => a(g),
127
+ className: "flex cursor-pointer items-center gap-2 rounded-md border-0 bg-info-surface px-3 py-2 text-left text-sm font-medium text-info-fg hover:bg-info-surface/70 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus",
128
+ children: [/* @__PURE__ */ o(t, {
129
+ name: "zap",
130
+ size: 16,
131
+ className: "shrink-0"
132
+ }), g]
133
+ }),
134
+ /* @__PURE__ */ o(m, {
135
+ onSend: a,
136
+ busy: f,
137
+ value: C,
138
+ onValueChange: w
139
+ })
140
+ ]
141
+ })
142
+ ]
143
+ });
144
+ }
145
+ function g({ trigger: n, mark: i, workspace: c, user: l, stats: u = [], actions: d = [], links: p = [], label: m = "Quick actions" }) {
146
+ return /* @__PURE__ */ s(f.Root, { children: [/* @__PURE__ */ o(f.Trigger, {
147
+ asChild: !0,
148
+ children: n
149
+ }), /* @__PURE__ */ o(f.Portal, { children: /* @__PURE__ */ s(f.Content, {
150
+ "aria-label": m,
151
+ side: "top",
152
+ align: "end",
153
+ sideOffset: 10,
154
+ collisionPadding: 16,
155
+ className: e("kf-popover w-80 overflow-hidden text-sm", r),
156
+ children: [
157
+ /* @__PURE__ */ s("div", {
158
+ "data-theme": "dark",
159
+ className: "flex items-center gap-3 bg-primary-strong px-4 py-3 text-fg",
160
+ children: [
161
+ i,
162
+ /* @__PURE__ */ o("span", {
163
+ className: "min-w-0 flex-1 truncate font-semibold",
164
+ children: c
165
+ }),
166
+ /* @__PURE__ */ o(a, {
167
+ name: l.name,
168
+ src: l.avatarSrc,
169
+ size: "sm"
170
+ })
171
+ ]
172
+ }),
173
+ u.length > 0 && /* @__PURE__ */ o("dl", {
174
+ className: "m-0 grid grid-flow-col divide-x divide-border border-b border-border",
175
+ children: u.map((e) => /* @__PURE__ */ s("div", {
176
+ className: "grid gap-0.5 px-3 py-2.5 text-center",
177
+ children: [/* @__PURE__ */ o("dt", {
178
+ className: "text-[11px] text-fg-muted",
179
+ children: e.label
180
+ }), /* @__PURE__ */ o("dd", {
181
+ className: "m-0 font-display text-lg font-bold text-fg tabular-nums",
182
+ children: e.value
183
+ })]
184
+ }, e.label))
185
+ }),
186
+ d.length > 0 && /* @__PURE__ */ o("div", {
187
+ className: "grid grid-cols-2 gap-2 p-3",
188
+ children: d.map((e) => /* @__PURE__ */ s("button", {
189
+ type: "button",
190
+ onClick: e.onClick,
191
+ className: "grid cursor-pointer justify-items-center gap-1.5 rounded-md border border-border bg-surface px-2 py-3 text-xs font-semibold text-fg hover:border-primary hover:bg-surface-muted focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-focus",
192
+ children: [/* @__PURE__ */ o(t, {
193
+ name: e.icon,
194
+ size: 22,
195
+ className: "text-primary"
196
+ }), e.label]
197
+ }, e.label))
198
+ }),
199
+ p.length > 0 && /* @__PURE__ */ o("div", {
200
+ className: "flex flex-wrap gap-x-4 gap-y-1 border-t border-border px-4 py-2.5 text-xs",
201
+ children: p.map((e) => /* @__PURE__ */ o("a", {
202
+ href: e.href,
203
+ className: "text-fg-muted no-underline hover:text-fg hover:underline",
204
+ children: e.label
205
+ }, e.href))
206
+ })
207
+ ]
208
+ }) })] });
209
+ }
210
+ //#endregion
211
+ export { m as ChatComposer, h as ChatPanel, p as PromptSuggestions, g as QuickPanel };
212
+
213
+ //# sourceMappingURL=assistant.js.map