@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,29 @@
1
+ import { type ReactElement, type ReactNode } from 'react';
2
+ export type FloatingSide = 'top' | 'right' | 'bottom' | 'left';
3
+ export interface TooltipProviderProps {
4
+ children: ReactNode;
5
+ /** Wait before the first tooltip opens (ms). Moving to another trigger right after opens it instantly. */
6
+ delayDuration?: number;
7
+ }
8
+ /** Shares timing between tooltips. Mount once near the app root (each `Tooltip` also works without it). */
9
+ export declare function TooltipProvider({ children, delayDuration }: TooltipProviderProps): import("react").JSX.Element;
10
+ export interface TooltipProps {
11
+ /** Short text label. No links or buttons inside: use `Popover` for interactive content. */
12
+ content: ReactNode;
13
+ /** A single focusable element (Button, icon button, link). */
14
+ children: ReactElement;
15
+ side?: FloatingSide;
16
+ align?: 'start' | 'center' | 'end';
17
+ /** Keyboard shortcut shown after the label, e.g. `⌘K`. */
18
+ shortcut?: string;
19
+ open?: boolean;
20
+ defaultOpen?: boolean;
21
+ onOpenChange?: (open: boolean) => void;
22
+ delayDuration?: number;
23
+ className?: string;
24
+ }
25
+ /**
26
+ * Short label that appears on hover and keyboard focus. It supplements, never replaces, an
27
+ * accessible name: icon buttons still need `aria-label`. Touch screens do not show tooltips.
28
+ */
29
+ export declare function Tooltip({ content, children, side, align, shortcut, open, defaultOpen, onOpenChange, delayDuration, className, }: TooltipProps): import("react").JSX.Element;
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { cx as e } from "../lib/cx.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ import { createContext as r, useContext as i } from "react";
5
+ import * as a from "@radix-ui/react-tooltip";
6
+ //#region src/tooltip/tooltip.tsx
7
+ var o = r(!1);
8
+ function s({ children: e, delayDuration: n = 400 }) {
9
+ return /* @__PURE__ */ t(a.Provider, {
10
+ delayDuration: n,
11
+ children: /* @__PURE__ */ t(o.Provider, {
12
+ value: !0,
13
+ children: e
14
+ })
15
+ });
16
+ }
17
+ function c({ content: r, children: s, side: c = "top", align: l = "center", shortcut: u, open: d, defaultOpen: f, onOpenChange: p, delayDuration: m, className: h }) {
18
+ let g = i(o), _ = /* @__PURE__ */ n(a.Root, {
19
+ open: d,
20
+ defaultOpen: f,
21
+ onOpenChange: p,
22
+ delayDuration: m,
23
+ children: [/* @__PURE__ */ t(a.Trigger, {
24
+ asChild: !0,
25
+ children: s
26
+ }), /* @__PURE__ */ t(a.Portal, { children: /* @__PURE__ */ n(a.Content, {
27
+ side: c,
28
+ align: l,
29
+ sideOffset: 6,
30
+ collisionPadding: 8,
31
+ className: e("kf-tooltip z-[70] flex max-w-[16rem] items-center gap-2 rounded-xs bg-fg px-2.5 py-1.5 font-sans text-[13px] leading-snug font-medium text-bg shadow-overlay", h),
32
+ children: [
33
+ r,
34
+ u && /* @__PURE__ */ t("kbd", {
35
+ className: "rounded-[4px] bg-bg/15 px-1.5 py-px font-mono text-[11px] opacity-80",
36
+ children: u
37
+ }),
38
+ /* @__PURE__ */ t(a.Arrow, {
39
+ width: 10,
40
+ height: 5,
41
+ className: "fill-fg"
42
+ })
43
+ ]
44
+ }) })]
45
+ });
46
+ return g ? _ : /* @__PURE__ */ t(a.Provider, {
47
+ delayDuration: m ?? 400,
48
+ children: _
49
+ });
50
+ }
51
+ //#endregion
52
+ export { c as Tooltip, s as TooltipProvider };
53
+
54
+ //# sourceMappingURL=tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.js","names":["RadixTooltip","HasProvider","createContext","TooltipProvider","Tooltip","shared","useContext","tooltip","cx","className","content","shortcut","delayDuration"],"sources":["../../src/tooltip/tooltip.tsx"],"sourcesContent":["'use client';\n\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { createContext, useContext, type ReactElement, type ReactNode } from 'react';\nimport { cx } from '../lib/cx';\n\nexport type FloatingSide = 'top' | 'right' | 'bottom' | 'left';\n\nconst HasProvider = createContext(false);\n\nexport interface TooltipProviderProps {\n children: ReactNode;\n /** Wait before the first tooltip opens (ms). Moving to another trigger right after opens it instantly. */\n delayDuration?: number;\n}\n\n/** Shares timing between tooltips. Mount once near the app root (each `Tooltip` also works without it). */\nexport function TooltipProvider({ children, delayDuration = 400 }: TooltipProviderProps) {\n return (\n <RadixTooltip.Provider delayDuration={delayDuration}>\n <HasProvider.Provider value={true}>{children}</HasProvider.Provider>\n </RadixTooltip.Provider>\n );\n}\n\nexport interface TooltipProps {\n /** Short text label. No links or buttons inside: use `Popover` for interactive content. */\n content: ReactNode;\n /** A single focusable element (Button, icon button, link). */\n children: ReactElement;\n side?: FloatingSide;\n align?: 'start' | 'center' | 'end';\n /** Keyboard shortcut shown after the label, e.g. `⌘K`. */\n shortcut?: string;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n delayDuration?: number;\n className?: string;\n}\n\n/**\n * Short label that appears on hover and keyboard focus. It supplements, never replaces, an\n * accessible name: icon buttons still need `aria-label`. Touch screens do not show tooltips.\n */\nexport function Tooltip({\n content,\n children,\n side = 'top',\n align = 'center',\n shortcut,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration,\n className,\n}: TooltipProps) {\n const shared = useContext(HasProvider);\n const tooltip = (\n <RadixTooltip.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange} delayDuration={delayDuration}>\n <RadixTooltip.Trigger asChild>{children}</RadixTooltip.Trigger>\n <RadixTooltip.Portal>\n <RadixTooltip.Content\n side={side}\n align={align}\n sideOffset={6}\n collisionPadding={8}\n className={cx(\n // Inverse surface: dark in light theme, light in dark theme.\n 'kf-tooltip z-[70] flex max-w-[16rem] items-center gap-2 rounded-xs bg-fg px-2.5 py-1.5 font-sans text-[13px] leading-snug font-medium text-bg shadow-overlay',\n className,\n )}\n >\n {content}\n {shortcut && (\n <kbd className=\"rounded-[4px] bg-bg/15 px-1.5 py-px font-mono text-[11px] opacity-80\">{shortcut}</kbd>\n )}\n <RadixTooltip.Arrow width={10} height={5} className=\"fill-fg\" />\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n return shared ? (\n tooltip\n ) : (\n <RadixTooltip.Provider delayDuration={delayDuration ?? 400}>{tooltip}</RadixTooltip.Provider>\n );\n}\n"],"mappings":";;;;;;AAQA,IAAMC,IAAcC,EAAc,EAAK;AASvC,SAAgBC,EAAgB,EAAE,aAAU,mBAAgB,OAA6B;CACvF,OACE,kBAACH,EAAa,UAAd;EAAsC;EACpC,UAAA,kBAACC,EAAY,UAAb;GAAsB,OAAO;GAAO;EAA+B,CAAA;CAC9C,CAAA;AAE3B;AAsBA,SAAgBG,EAAQ,EACtB,YACA,aACA,UAAO,OACP,WAAQ,UACR,aACA,SACA,gBACA,iBACA,kBACA,gBACe;CACf,IAAMC,IAASC,EAAWL,CAAW,GAC/BM,IACJ,kBAACP,EAAa,MAAd;EAAyB;EAAmB;EAA2B;EAA6B;EAApG,UAAA,CACE,kBAACA,EAAa,SAAd;GAAsB,SAAA;GAAS;EAA+B,CAAA,GAC9D,kBAACA,EAAa,QAAd,EAAA,UACE,kBAACA,EAAa,SAAd;GACQ;GACC;GACP,YAAY;GACZ,kBAAkB;GAClB,WAAWQ,EAET,gKACAC,CACF;GATF,UAAA;IAWGC;IACAC,KACC,kBAAC,OAAD;KAAK,WAAU;KAAwE,UAAAA;IAAc,CAAA;IAEvG,kBAACX,EAAa,OAAd;KAAoB,OAAO;KAAI,QAAQ;KAAG,WAAU;IAAW,CAAA;GAC3C;EACH,CAAA,EAAA,CAAA,CACJ;;CAErB,OAAOK,IACLE,IAEA,kBAACP,EAAa,UAAd;EAAuB,eAAeY,KAAiB;EAAM,UAAAL;CAA+B,CAAA;AAEhG"}
package/package.json CHANGED
@@ -1,6 +1,91 @@
1
1
  {
2
2
  "name": "@kodffe/ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.10.1",
4
+ "description": "Kodffe React components (React 19 + Tailwind v4), documented in Storybook.",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/kodffe/kodffe-web.git",
10
+ "directory": "packages/ui"
11
+ },
12
+ "sideEffects": [
13
+ "*.css"
14
+ ],
15
+ "files": [
16
+ "dist",
17
+ "styles.css"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ },
24
+ "./styles.css": "./styles.css"
25
+ },
26
+ "dependencies": {
27
+ "@kodffe/tokens": "0.7.0",
28
+ "@radix-ui/react-accordion": "1.3.1",
29
+ "@radix-ui/react-alert-dialog": "1.2.1",
30
+ "@radix-ui/react-checkbox": "1.4.1",
31
+ "@radix-ui/react-collapsible": "1.2.1",
32
+ "@radix-ui/react-context-menu": "2.4.1",
33
+ "@radix-ui/react-dialog": "1.3.1",
34
+ "@radix-ui/react-dropdown-menu": "2.2.1",
35
+ "@radix-ui/react-hover-card": "1.2.1",
36
+ "@radix-ui/react-menubar": "1.2.1",
37
+ "@radix-ui/react-popover": "1.3.1",
38
+ "@radix-ui/react-radio-group": "1.5.1",
39
+ "@radix-ui/react-select": "2.4.1",
40
+ "@radix-ui/react-slider": "1.6.1",
41
+ "@radix-ui/react-switch": "1.4.1",
42
+ "@radix-ui/react-tabs": "1.2.1",
43
+ "@radix-ui/react-toast": "1.3.1",
44
+ "@radix-ui/react-tooltip": "1.4.1",
45
+ "@tanstack/react-table": "9.3.1",
46
+ "@tanstack/react-virtual": "3.14.21",
47
+ "date-fns": "4.4.0",
48
+ "react-day-picker": "10.0.2",
49
+ "recharts": "3.10.1"
50
+ },
51
+ "peerDependencies": {
52
+ "react": "^19.0.0",
53
+ "react-dom": "^19.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@kodffe/config": "0.0.0",
57
+ "@storybook/addon-a11y": "10.6.2",
58
+ "@storybook/addon-docs": "10.6.2",
59
+ "@storybook/addon-themes": "10.6.2",
60
+ "@storybook/addon-vitest": "10.6.2",
61
+ "@storybook/react-vite": "10.6.2",
62
+ "@tailwindcss/vite": "4.3.3",
63
+ "@types/react": "19.3.0",
64
+ "@types/react-dom": "19.3.0",
65
+ "@vitejs/plugin-react": "6.1.2",
66
+ "@vitest/browser": "5.0.5",
67
+ "@vitest/browser-playwright": "5.0.5",
68
+ "@vitest/coverage-v8": "5.0.5",
69
+ "playwright": "1.64.1",
70
+ "react": "19.3.1",
71
+ "react-dom": "19.3.1",
72
+ "remark-gfm": "4.0.1",
73
+ "storybook": "10.6.2",
74
+ "tailwindcss": "4.3.3",
75
+ "typescript": "6.0.3",
76
+ "vite": "8.3.4",
77
+ "vitest": "5.0.5"
78
+ },
79
+ "publishConfig": {
80
+ "access": "public",
81
+ "registry": "https://registry.npmjs.org"
82
+ },
83
+ "scripts": {
84
+ "icons": "node scripts/generate-icons.mjs",
85
+ "build": "vite build -c vite.lib.config.ts && tsc -p tsconfig.build.json",
86
+ "typecheck": "tsc --noEmit",
87
+ "storybook": "storybook dev -p 6006",
88
+ "build-storybook": "storybook build",
89
+ "test": "vitest run"
90
+ }
6
91
  }
package/styles.css ADDED
@@ -0,0 +1,521 @@
1
+ /*
2
+ * @kodffe/ui styles. In a product:
3
+ * @import "tailwindcss";
4
+ * @import "@kodffe/tokens/tokens.css";
5
+ * @import "@kodffe/ui/styles.css";
6
+ */
7
+ @source "./dist";
8
+
9
+ /*
10
+ * Logo, option B "Open D" (docs/adr/0012-open-d-logo.md): K | slot with the mark (eye + open D) | F F E,
11
+ * 1 em = 50 units (geometry: docs/design/logo/generate.py). Collapsible logos (headers) fade the letters and
12
+ * slide the mark into the K's place; only transform and opacity animate, so nothing reflows and the hover
13
+ * area stays put. One symmetric ease-in-out, no bounce or pause; instant with reduced motion.
14
+ */
15
+ .kf-logo {
16
+ --kf-logo-motion: 320ms cubic-bezier(0.65, 0, 0.35, 1);
17
+ display: inline-flex;
18
+ align-items: flex-start;
19
+ height: 1em;
20
+ line-height: 1;
21
+ vertical-align: -0.14em;
22
+ }
23
+ .kf-logo > svg {
24
+ display: block;
25
+ flex: none;
26
+ height: 1em;
27
+ overflow: visible;
28
+ }
29
+ .kf-logo__k {
30
+ width: 0.6484em;
31
+ }
32
+ .kf-logo__slot {
33
+ width: 1.3276em;
34
+ }
35
+ .kf-logo__ffe {
36
+ width: 1.7304em;
37
+ }
38
+ .kf-logo--mark .kf-logo__mark {
39
+ width: 1.44em;
40
+ }
41
+ .kf-logo--collapsible > svg {
42
+ transition:
43
+ transform var(--kf-logo-motion),
44
+ opacity var(--kf-logo-motion);
45
+ }
46
+ /* Collapsed: the mark moves to where the K starts; the letters fade (F F E with a short slide). */
47
+ .kf-logo.is-collapsed .kf-logo__k {
48
+ opacity: 0;
49
+ }
50
+ .kf-logo.is-collapsed .kf-logo__slot {
51
+ transform: translateX(-0.7004em);
52
+ }
53
+ .kf-logo.is-collapsed .kf-logo__ffe {
54
+ opacity: 0;
55
+ transform: translateX(-0.5em);
56
+ }
57
+ /* Hover or keyboard focus on the logo's link shows the full name again. */
58
+ .kf-logo--collapsible.is-collapsed:hover > svg,
59
+ :focus-visible > .kf-logo--collapsible.is-collapsed > svg {
60
+ opacity: 1;
61
+ transform: none;
62
+ }
63
+ @media (prefers-reduced-motion: reduce) {
64
+ .kf-logo--collapsible > svg {
65
+ transition: none;
66
+ }
67
+ }
68
+
69
+ /* Mascot (ADR-0015): each SVG carries its own scoped animation; `animated={false}` stops it. */
70
+ .kf-mascot {
71
+ overflow: visible;
72
+ }
73
+ .kf-mascot--still,
74
+ .kf-mascot--still * {
75
+ animation: none !important;
76
+ }
77
+
78
+ /* Spinner: the eye's pupil goes round. With reduced motion it keeps turning, slowly, because it reports progress. */
79
+ .kf-spinner__pupil {
80
+ transform-box: view-box;
81
+ transform-origin: 50px 34px;
82
+ animation: kf-spinner 0.9s linear infinite;
83
+ }
84
+ @keyframes kf-spinner {
85
+ to {
86
+ transform: rotate(360deg);
87
+ }
88
+ }
89
+
90
+ /* Overlays (Modal, Drawer). Exit keyframes only define their end state, so a swiped panel
91
+ leaves from where the finger released it. */
92
+ .kf-overlay[data-state='open'] {
93
+ animation: kf-fade-in 200ms var(--ease-standard);
94
+ }
95
+ .kf-overlay[data-state='closed'] {
96
+ animation: kf-fade-out 160ms var(--ease-standard) forwards;
97
+ }
98
+ .kf-modal[data-state='open'],
99
+ .kf-drawer--bottom[data-state='open'] {
100
+ animation: kf-in-bottom 300ms var(--ease-standard);
101
+ }
102
+ .kf-modal[data-state='closed'],
103
+ .kf-drawer--bottom[data-state='closed'] {
104
+ animation: kf-out-bottom 200ms var(--ease-standard) forwards;
105
+ }
106
+ .kf-drawer--right[data-state='open'] {
107
+ animation: kf-in-right 300ms var(--ease-standard);
108
+ }
109
+ .kf-drawer--right[data-state='closed'] {
110
+ animation: kf-out-right 200ms var(--ease-standard) forwards;
111
+ }
112
+ .kf-drawer--left[data-state='open'] {
113
+ animation: kf-in-left 300ms var(--ease-standard);
114
+ }
115
+ .kf-drawer--left[data-state='closed'] {
116
+ animation: kf-out-left 200ms var(--ease-standard) forwards;
117
+ }
118
+ @media (min-width: 40rem) {
119
+ .kf-modal[data-state='open'] {
120
+ animation: kf-pop-in 220ms var(--ease-standard);
121
+ }
122
+ .kf-modal[data-state='closed'] {
123
+ animation: kf-pop-out 150ms var(--ease-standard) forwards;
124
+ }
125
+ }
126
+
127
+ @keyframes kf-fade-in {
128
+ from {
129
+ opacity: 0;
130
+ }
131
+ }
132
+ @keyframes kf-fade-out {
133
+ to {
134
+ opacity: 0;
135
+ }
136
+ }
137
+ @keyframes kf-in-bottom {
138
+ from {
139
+ transform: translateY(100%);
140
+ }
141
+ }
142
+ @keyframes kf-out-bottom {
143
+ to {
144
+ transform: translateY(100%);
145
+ }
146
+ }
147
+ @keyframes kf-in-right {
148
+ from {
149
+ transform: translateX(100%);
150
+ }
151
+ }
152
+ @keyframes kf-out-right {
153
+ to {
154
+ transform: translateX(100%);
155
+ }
156
+ }
157
+ @keyframes kf-in-left {
158
+ from {
159
+ transform: translateX(-100%);
160
+ }
161
+ }
162
+ @keyframes kf-out-left {
163
+ to {
164
+ transform: translateX(-100%);
165
+ }
166
+ }
167
+ @keyframes kf-pop-in {
168
+ from {
169
+ opacity: 0;
170
+ transform: translateY(8px) scale(0.97);
171
+ }
172
+ }
173
+ @keyframes kf-pop-out {
174
+ to {
175
+ opacity: 0;
176
+ transform: scale(0.97);
177
+ }
178
+ }
179
+
180
+ /* Toasts (Radix Toast). Mobile: enter from the bottom; desktop: from the right. Swipe follows the finger. */
181
+ .kf-toast[data-state='open'] {
182
+ animation: kf-in-bottom 280ms var(--ease-standard);
183
+ }
184
+ .kf-toast[data-state='closed'] {
185
+ animation: kf-fade-out 160ms var(--ease-standard) forwards;
186
+ }
187
+ .kf-toast[data-swipe='move'] {
188
+ transform: translate(var(--radix-toast-swipe-move-x), var(--radix-toast-swipe-move-y));
189
+ }
190
+ .kf-toast[data-swipe='cancel'] {
191
+ transform: translate(0, 0);
192
+ transition: transform 200ms var(--ease-standard);
193
+ }
194
+ .kf-toast[data-swipe='end'] {
195
+ animation: kf-toast-swipe-out 160ms var(--ease-standard) forwards;
196
+ }
197
+ @media (min-width: 40rem) {
198
+ .kf-toast[data-state='open'] {
199
+ animation: kf-in-right 280ms var(--ease-standard);
200
+ }
201
+ }
202
+ @keyframes kf-toast-swipe-out {
203
+ from {
204
+ transform: translate(var(--radix-toast-swipe-end-x), var(--radix-toast-swipe-end-y));
205
+ }
206
+ to {
207
+ transform: translate(var(--radix-toast-swipe-end-x), var(--radix-toast-swipe-end-y));
208
+ opacity: 0;
209
+ }
210
+ }
211
+
212
+ /* Floating content: Popover, HoverCard, Tooltip (and NotificationCenter). */
213
+ .kf-popover {
214
+ transform-origin: var(--radix-popover-content-transform-origin);
215
+ }
216
+ .kf-hovercard {
217
+ transform-origin: var(--radix-hover-card-content-transform-origin);
218
+ }
219
+ .kf-tooltip {
220
+ transform-origin: var(--radix-tooltip-content-transform-origin);
221
+ }
222
+ .kf-popover[data-state='open'],
223
+ .kf-hovercard[data-state='open'] {
224
+ animation: kf-pop-in 160ms var(--ease-standard);
225
+ }
226
+ .kf-tooltip[data-state='delayed-open'] {
227
+ animation: kf-fade-in 120ms var(--ease-standard);
228
+ }
229
+ .kf-popover[data-state='closed'],
230
+ .kf-hovercard[data-state='closed'],
231
+ .kf-tooltip[data-state='closed'] {
232
+ animation: kf-fade-out 100ms var(--ease-standard) forwards;
233
+ }
234
+
235
+ /* Progress: indeterminate bar */
236
+ .kf-progress-indeterminate {
237
+ animation: kf-indeterminate 1.4s var(--ease-standard) infinite;
238
+ }
239
+ @keyframes kf-indeterminate {
240
+ 0% {
241
+ transform: translateX(-100%) scaleX(0.4);
242
+ }
243
+ 60% {
244
+ transform: translateX(60%) scaleX(0.6);
245
+ }
246
+ 100% {
247
+ transform: translateX(160%) scaleX(0.4);
248
+ }
249
+ }
250
+
251
+ /* Skeleton shimmer */
252
+ .kf-skeleton {
253
+ background: linear-gradient(
254
+ 90deg,
255
+ var(--kf-surface-muted) 0%,
256
+ color-mix(in oklab, var(--kf-surface-muted), var(--kf-fg) 6%) 50%,
257
+ var(--kf-surface-muted) 100%
258
+ )
259
+ 0 0 / 200% 100%;
260
+ animation: kf-shimmer 1.6s linear infinite;
261
+ }
262
+ @keyframes kf-shimmer {
263
+ to {
264
+ background-position: -200% 0;
265
+ }
266
+ }
267
+
268
+ /* Menus (DropdownMenu, ContextMenu, Menubar) */
269
+ .kf-menu[data-state='open'] {
270
+ animation: kf-pop-in 140ms var(--ease-standard);
271
+ }
272
+ .kf-menu[data-state='closed'] {
273
+ animation: kf-fade-out 100ms var(--ease-standard) forwards;
274
+ }
275
+
276
+ /* Collapsible / Accordion height animation */
277
+ .kf-collapse[data-state='open'] {
278
+ animation: kf-expand 220ms var(--ease-standard);
279
+ }
280
+ .kf-collapse[data-state='closed'] {
281
+ animation: kf-collapse 180ms var(--ease-standard);
282
+ }
283
+ @keyframes kf-expand {
284
+ from {
285
+ height: 0;
286
+ }
287
+ to {
288
+ height: var(--radix-collapsible-content-height, var(--radix-accordion-content-height));
289
+ }
290
+ }
291
+ @keyframes kf-collapse {
292
+ from {
293
+ height: var(--radix-collapsible-content-height, var(--radix-accordion-content-height));
294
+ }
295
+ to {
296
+ height: 0;
297
+ }
298
+ }
299
+
300
+ /* Command palette: drops in on desktop, slides up on mobile */
301
+ .kf-palette[data-state='open'] {
302
+ animation: kf-in-bottom 260ms var(--ease-standard);
303
+ }
304
+ @media (min-width: 40rem) {
305
+ .kf-palette[data-state='open'] {
306
+ animation: kf-pop-in 180ms var(--ease-standard);
307
+ }
308
+ }
309
+ .kf-palette[data-state='closed'] {
310
+ animation: kf-fade-out 120ms var(--ease-standard) forwards;
311
+ }
312
+
313
+ /*
314
+ * Calendar (react-day-picker, ADR-0004). Cell size grows on touch screens (`--kf-cal-size`) but never
315
+ * past a seventh of the viewport minus the gutters, so a week fits on 320px phones.
316
+ */
317
+ .kf-cal {
318
+ --kf-cal-size: 2.25rem;
319
+ --kf-cal-cell: min(var(--kf-cal-size), calc((100vw - 2rem) / 7));
320
+ font-family: var(--font-sans);
321
+ color: var(--kf-fg);
322
+ position: relative;
323
+ }
324
+ @media (pointer: coarse) {
325
+ .kf-cal {
326
+ --kf-cal-size: 2.75rem;
327
+ }
328
+ }
329
+ .kf-cal-months {
330
+ display: flex;
331
+ flex-wrap: wrap;
332
+ gap: 1.5rem;
333
+ }
334
+ .kf-cal-month {
335
+ display: grid;
336
+ gap: 0.5rem;
337
+ }
338
+ .kf-cal-caption {
339
+ display: flex;
340
+ align-items: center;
341
+ height: 2.25rem;
342
+ padding-inline: 0.25rem;
343
+ }
344
+ .kf-cal-caption-label {
345
+ font-weight: 700;
346
+ font-size: 0.9375rem;
347
+ display: inline-flex;
348
+ align-items: center;
349
+ gap: 0.25rem;
350
+ }
351
+ .kf-cal-nav {
352
+ position: absolute;
353
+ top: 0;
354
+ right: 0;
355
+ display: flex;
356
+ gap: 0.25rem;
357
+ z-index: 1;
358
+ }
359
+ .kf-cal-nav-btn {
360
+ display: grid;
361
+ place-items: center;
362
+ width: 2.25rem;
363
+ height: 2.25rem;
364
+ border: 0;
365
+ border-radius: 9999px;
366
+ background: transparent;
367
+ color: var(--kf-fg);
368
+ cursor: pointer;
369
+ }
370
+ .kf-cal-nav-btn:hover {
371
+ background: var(--kf-surface-muted);
372
+ }
373
+ .kf-cal-nav-btn:disabled {
374
+ opacity: 0.35;
375
+ cursor: default;
376
+ }
377
+ .kf-cal-grid {
378
+ border-collapse: separate;
379
+ border-spacing: 0 2px;
380
+ }
381
+ .kf-cal-weekday {
382
+ width: var(--kf-cal-cell);
383
+ height: 2rem;
384
+ font-size: 0.75rem;
385
+ font-weight: 600;
386
+ color: var(--kf-fg-muted);
387
+ text-transform: uppercase;
388
+ }
389
+ .kf-cal-day {
390
+ width: var(--kf-cal-cell);
391
+ height: var(--kf-cal-cell);
392
+ padding: 0;
393
+ text-align: center;
394
+ }
395
+ .kf-cal-day-btn {
396
+ width: var(--kf-cal-cell);
397
+ height: var(--kf-cal-cell);
398
+ border: 0;
399
+ border-radius: 9999px;
400
+ background: transparent;
401
+ color: inherit;
402
+ font: inherit;
403
+ font-size: 0.875rem;
404
+ font-variant-numeric: tabular-nums;
405
+ cursor: pointer;
406
+ transition: background-color 120ms var(--ease-standard);
407
+ }
408
+ .kf-cal-day-btn:hover {
409
+ background: var(--kf-surface-muted);
410
+ }
411
+ .kf-cal-day-btn:focus-visible {
412
+ outline: 3px solid var(--kf-focus);
413
+ outline-offset: 1px;
414
+ }
415
+ .kf-cal-day.is-today .kf-cal-day-btn {
416
+ font-weight: 800;
417
+ color: var(--kf-link);
418
+ box-shadow: inset 0 0 0 1.5px currentColor;
419
+ }
420
+ .kf-cal-day.is-outside {
421
+ /* Muted text, not opacity: --kf-fg-muted stays AA on the surface in both themes. */
422
+ color: var(--kf-fg-muted);
423
+ font-weight: 400;
424
+ }
425
+ .kf-cal-day.is-disabled .kf-cal-day-btn {
426
+ opacity: 0.35;
427
+ text-decoration: line-through;
428
+ cursor: not-allowed;
429
+ background: transparent;
430
+ }
431
+ .kf-cal-day.is-hidden {
432
+ visibility: hidden;
433
+ }
434
+ .kf-cal-day.is-selected .kf-cal-day-btn {
435
+ background: var(--kf-primary);
436
+ color: var(--kf-on-primary);
437
+ font-weight: 700;
438
+ box-shadow: none;
439
+ }
440
+ .kf-cal-day.is-range-middle {
441
+ background: var(--kf-info-surface);
442
+ }
443
+ .kf-cal-day.is-range-middle .kf-cal-day-btn {
444
+ background: transparent;
445
+ color: var(--kf-fg);
446
+ font-weight: 500;
447
+ }
448
+ .kf-cal-day.is-range-start:not(.is-range-end) {
449
+ background: linear-gradient(to right, transparent 50%, var(--kf-info-surface) 50%);
450
+ }
451
+ .kf-cal-day.is-range-end:not(.is-range-start) {
452
+ background: linear-gradient(to left, transparent 50%, var(--kf-info-surface) 50%);
453
+ }
454
+ .kf-cal-dropdowns {
455
+ display: inline-flex;
456
+ gap: 0.5rem;
457
+ align-items: center;
458
+ }
459
+ .kf-cal-dropdown-root {
460
+ position: relative;
461
+ display: inline-flex;
462
+ align-items: center;
463
+ gap: 0.25rem;
464
+ font-weight: 700;
465
+ }
466
+ .kf-cal-dropdown {
467
+ position: absolute;
468
+ inset: 0;
469
+ opacity: 0;
470
+ cursor: pointer;
471
+ }
472
+ .kf-cal-dropdown-root:has(:focus-visible) {
473
+ outline: 3px solid var(--kf-focus);
474
+ outline-offset: 2px;
475
+ border-radius: 6px;
476
+ }
477
+
478
+ @media (prefers-reduced-motion: reduce) {
479
+ .kf-spinner__pupil {
480
+ animation-duration: 3s;
481
+ }
482
+ .kf-overlay,
483
+ .kf-modal,
484
+ .kf-drawer,
485
+ .kf-toast,
486
+ .kf-popover,
487
+ .kf-hovercard,
488
+ .kf-tooltip,
489
+ .kf-menu,
490
+ .kf-collapse,
491
+ .kf-palette {
492
+ animation-duration: 1ms !important;
493
+ }
494
+ .kf-skeleton,
495
+ .kf-progress-indeterminate {
496
+ animation: none;
497
+ }
498
+ }
499
+
500
+ /*
501
+ * Scroll reveal for marketing sections: a short rise as content enters the viewport. Restrained on
502
+ * purpose: transform only (no opacity, so contrast checks and readers never meet half-visible text),
503
+ * scroll-driven (no JavaScript), only where supported and only without reduced motion.
504
+ */
505
+ @media (prefers-reduced-motion: no-preference) {
506
+ @supports (animation-timeline: view()) {
507
+ .kf-reveal {
508
+ animation: kf-rise linear both;
509
+ animation-timeline: view();
510
+ animation-range: entry 0% entry 60%;
511
+ }
512
+ }
513
+ }
514
+ @keyframes kf-rise {
515
+ from {
516
+ transform: translateY(24px);
517
+ }
518
+ to {
519
+ transform: none;
520
+ }
521
+ }