@adea-ai/ui 0.61.0 → 0.61.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 (248) hide show
  1. package/dist/r/accordion.json +3 -1
  2. package/dist/r/account-menu.json +2 -1
  3. package/dist/r/alert-dialog.json +3 -1
  4. package/dist/r/alert.json +3 -1
  5. package/dist/r/app-shell.json +3 -1
  6. package/dist/r/aspect-ratio.json +3 -1
  7. package/dist/r/avatar.json +3 -1
  8. package/dist/r/badge.json +3 -1
  9. package/dist/r/board.json +3 -1
  10. package/dist/r/breadcrumb.json +3 -1
  11. package/dist/r/button-group.json +2 -1
  12. package/dist/r/button.json +3 -1
  13. package/dist/r/calendar.json +2 -1
  14. package/dist/r/card.json +3 -1
  15. package/dist/r/carousel.json +2 -1
  16. package/dist/r/chart.json +3 -1
  17. package/dist/r/checkbox.json +3 -1
  18. package/dist/r/code-block.json +2 -1
  19. package/dist/r/collapsible.json +3 -1
  20. package/dist/r/combobox.json +3 -1
  21. package/dist/r/command.json +3 -1
  22. package/dist/r/context-menu.json +3 -1
  23. package/dist/r/conversation.json +2 -1
  24. package/dist/r/detail-panel.json +2 -1
  25. package/dist/r/dialog.json +3 -1
  26. package/dist/r/diff-block.json +3 -1
  27. package/dist/r/drawer.json +3 -1
  28. package/dist/r/dropdown-menu.json +3 -1
  29. package/dist/r/empty.json +3 -1
  30. package/dist/r/entity-icon.json +3 -1
  31. package/dist/r/field.json +3 -1
  32. package/dist/r/hover-card.json +3 -1
  33. package/dist/r/input-group.json +3 -1
  34. package/dist/r/input-otp.json +3 -1
  35. package/dist/r/input.json +3 -1
  36. package/dist/r/item.json +3 -1
  37. package/dist/r/kbd.json +3 -1
  38. package/dist/r/label.json +3 -1
  39. package/dist/r/lib.json +50 -0
  40. package/dist/r/list-row.json +3 -1
  41. package/dist/r/menubar.json +3 -1
  42. package/dist/r/modal-dialog.json +2 -1
  43. package/dist/r/motion.json +22 -0
  44. package/dist/r/navigation-menu.json +3 -1
  45. package/dist/r/page.json +3 -1
  46. package/dist/r/pagination.json +3 -1
  47. package/dist/r/panel.json +3 -1
  48. package/dist/r/popover.json +3 -1
  49. package/dist/r/progress.json +3 -1
  50. package/dist/r/radio-group.json +3 -1
  51. package/dist/r/registry.json +320 -73
  52. package/dist/r/resizable.json +3 -1
  53. package/dist/r/scroll-area.json +3 -1
  54. package/dist/r/select.json +3 -1
  55. package/dist/r/separator.json +3 -1
  56. package/dist/r/settings.json +3 -1
  57. package/dist/r/sheet.json +2 -1
  58. package/dist/r/side-rail.json +3 -1
  59. package/dist/r/sidebar-nav.json +3 -1
  60. package/dist/r/skeleton.json +3 -1
  61. package/dist/r/slider.json +3 -1
  62. package/dist/r/spinner.json +3 -1
  63. package/dist/r/src/components/composites/account-menu/account-menu.tsx +150 -0
  64. package/dist/r/src/components/composites/account-menu/index.ts +1 -0
  65. package/dist/r/src/components/composites/list-row/index.ts +1 -0
  66. package/dist/r/src/components/composites/list-row/list-row.tsx +116 -0
  67. package/dist/r/src/components/composites/settings/index.ts +1 -0
  68. package/dist/r/src/components/composites/settings/settings.tsx +142 -0
  69. package/dist/r/src/components/composites/stat/index.ts +9 -0
  70. package/dist/r/src/components/composites/stat/stat.tsx +155 -0
  71. package/dist/r/src/components/composites/update-dialog/index.ts +7 -0
  72. package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +529 -0
  73. package/dist/r/src/components/composites/workspace-mark/index.ts +1 -0
  74. package/dist/r/src/components/composites/workspace-mark/workspace-mark.tsx +72 -0
  75. package/dist/r/src/components/conversation/conversation-avatar.tsx +60 -0
  76. package/dist/r/src/components/conversation/conversation-surface.tsx +107 -0
  77. package/dist/r/src/components/conversation/index.ts +25 -0
  78. package/dist/r/src/components/conversation/message-composer.tsx +239 -0
  79. package/dist/r/src/components/conversation/message-row.tsx +387 -0
  80. package/dist/r/src/components/conversation/thread-panel.tsx +141 -0
  81. package/dist/r/src/components/layout/app-shell/app-shell.tsx +92 -0
  82. package/dist/r/src/components/layout/app-shell/index.ts +1 -0
  83. package/dist/r/src/components/layout/page/index.ts +9 -0
  84. package/dist/r/src/components/layout/page/page.tsx +122 -0
  85. package/dist/r/src/components/layout/panel/index.ts +12 -0
  86. package/dist/r/src/components/layout/panel/panel.tsx +166 -0
  87. package/dist/r/src/components/layout/side-rail/index.ts +12 -0
  88. package/dist/r/src/components/layout/side-rail/side-rail-context.ts +42 -0
  89. package/dist/r/src/components/layout/side-rail/side-rail.tsx +405 -0
  90. package/dist/r/src/components/layout/sidebar-nav/index.ts +14 -0
  91. package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +244 -0
  92. package/dist/r/src/components/layout/status-bar/index.ts +1 -0
  93. package/dist/r/src/components/layout/status-bar/status-bar.tsx +73 -0
  94. package/dist/r/src/components/layout/top-bar/index.ts +10 -0
  95. package/dist/r/src/components/layout/top-bar/top-bar.tsx +166 -0
  96. package/dist/r/src/components/motion/index.ts +2 -0
  97. package/dist/r/src/components/motion/presence.tsx +32 -0
  98. package/dist/r/src/components/theme/appearance-panel.tsx +179 -0
  99. package/dist/r/src/components/theme/index.ts +22 -0
  100. package/dist/r/src/components/theme/theme-picker.tsx +174 -0
  101. package/dist/r/src/components/theme/theme-provider.tsx +309 -0
  102. package/dist/r/src/components/theme/theme-toggle.tsx +64 -0
  103. package/dist/r/src/components/ui/accordion/accordion.tsx +66 -0
  104. package/dist/r/src/components/ui/accordion/index.ts +1 -0
  105. package/dist/r/src/components/ui/alert/alert.tsx +95 -0
  106. package/dist/r/src/components/ui/alert/index.ts +1 -0
  107. package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +176 -0
  108. package/dist/r/src/components/ui/alert-dialog/index.ts +13 -0
  109. package/dist/r/src/components/ui/aspect-ratio/aspect-ratio.tsx +38 -0
  110. package/dist/r/src/components/ui/aspect-ratio/index.ts +1 -0
  111. package/dist/r/src/components/ui/avatar/avatar.tsx +114 -0
  112. package/dist/r/src/components/ui/avatar/index.ts +9 -0
  113. package/dist/r/src/components/ui/badge/badge.tsx +59 -0
  114. package/dist/r/src/components/ui/badge/index.ts +1 -0
  115. package/dist/r/src/components/ui/board/board.tsx +254 -0
  116. package/dist/r/src/components/ui/board/index.ts +10 -0
  117. package/dist/r/src/components/ui/breadcrumb/breadcrumb.tsx +117 -0
  118. package/dist/r/src/components/ui/breadcrumb/index.ts +9 -0
  119. package/dist/r/src/components/ui/button/button.tsx +89 -0
  120. package/dist/r/src/components/ui/button/index.ts +1 -0
  121. package/dist/r/src/components/ui/button-group/button-group.tsx +92 -0
  122. package/dist/r/src/components/ui/button-group/index.ts +6 -0
  123. package/dist/r/src/components/ui/calendar/calendar.tsx +277 -0
  124. package/dist/r/src/components/ui/calendar/index.ts +1 -0
  125. package/dist/r/src/components/ui/card/card.tsx +82 -0
  126. package/dist/r/src/components/ui/card/index.ts +10 -0
  127. package/dist/r/src/components/ui/carousel/carousel.tsx +209 -0
  128. package/dist/r/src/components/ui/carousel/index.ts +1 -0
  129. package/dist/r/src/components/ui/chart/chart.tsx +413 -0
  130. package/dist/r/src/components/ui/chart/index.ts +17 -0
  131. package/dist/r/src/components/ui/checkbox/checkbox.tsx +99 -0
  132. package/dist/r/src/components/ui/checkbox/index.ts +1 -0
  133. package/dist/r/src/components/ui/code-block/code-block.tsx +238 -0
  134. package/dist/r/src/components/ui/code-block/index.ts +1 -0
  135. package/dist/r/src/components/ui/collapsible/collapsible.tsx +54 -0
  136. package/dist/r/src/components/ui/collapsible/index.ts +1 -0
  137. package/dist/r/src/components/ui/combobox/combobox.tsx +142 -0
  138. package/dist/r/src/components/ui/combobox/index.ts +10 -0
  139. package/dist/r/src/components/ui/command/command.tsx +214 -0
  140. package/dist/r/src/components/ui/command/index.ts +12 -0
  141. package/dist/r/src/components/ui/context-menu/context-menu.tsx +163 -0
  142. package/dist/r/src/components/ui/context-menu/index.ts +15 -0
  143. package/dist/r/src/components/ui/detail-panel/detail-panel.tsx +161 -0
  144. package/dist/r/src/components/ui/detail-panel/index.ts +9 -0
  145. package/dist/r/src/components/ui/dialog/dialog.tsx +138 -0
  146. package/dist/r/src/components/ui/dialog/index.ts +14 -0
  147. package/dist/r/src/components/ui/diff-block/diff-block.tsx +286 -0
  148. package/dist/r/src/components/ui/diff-block/index.ts +11 -0
  149. package/dist/r/src/components/ui/drawer/drawer.tsx +144 -0
  150. package/dist/r/src/components/ui/drawer/index.ts +13 -0
  151. package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +203 -0
  152. package/dist/r/src/components/ui/dropdown-menu/index.ts +18 -0
  153. package/dist/r/src/components/ui/empty/empty.tsx +104 -0
  154. package/dist/r/src/components/ui/empty/index.ts +10 -0
  155. package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +154 -0
  156. package/dist/r/src/components/ui/entity-icon/index.ts +1 -0
  157. package/dist/r/src/components/ui/field/field.tsx +131 -0
  158. package/dist/r/src/components/ui/field/index.ts +11 -0
  159. package/dist/r/src/components/ui/hover-card/hover-card.tsx +48 -0
  160. package/dist/r/src/components/ui/hover-card/index.ts +1 -0
  161. package/dist/r/src/components/ui/input/index.ts +1 -0
  162. package/dist/r/src/components/ui/input/input.tsx +41 -0
  163. package/dist/r/src/components/ui/input-group/index.ts +8 -0
  164. package/dist/r/src/components/ui/input-group/input-group.tsx +111 -0
  165. package/dist/r/src/components/ui/input-otp/index.ts +1 -0
  166. package/dist/r/src/components/ui/input-otp/input-otp.tsx +108 -0
  167. package/dist/r/src/components/ui/item/index.ts +10 -0
  168. package/dist/r/src/components/ui/item/item.tsx +146 -0
  169. package/dist/r/src/components/ui/kbd/index.ts +1 -0
  170. package/dist/r/src/components/ui/kbd/kbd.tsx +42 -0
  171. package/dist/r/src/components/ui/label/index.ts +1 -0
  172. package/dist/r/src/components/ui/label/label.tsx +36 -0
  173. package/dist/r/src/components/ui/menubar/index.ts +16 -0
  174. package/dist/r/src/components/ui/menubar/menubar.tsx +190 -0
  175. package/dist/r/src/components/ui/modal-dialog/index.ts +1 -0
  176. package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +95 -0
  177. package/dist/r/src/components/ui/navigation-menu/index.ts +13 -0
  178. package/dist/r/src/components/ui/navigation-menu/navigation-menu.tsx +229 -0
  179. package/dist/r/src/components/ui/pagination/index.ts +8 -0
  180. package/dist/r/src/components/ui/pagination/pagination.tsx +144 -0
  181. package/dist/r/src/components/ui/popover/index.ts +10 -0
  182. package/dist/r/src/components/ui/popover/popover.tsx +81 -0
  183. package/dist/r/src/components/ui/progress/index.ts +1 -0
  184. package/dist/r/src/components/ui/progress/progress.tsx +67 -0
  185. package/dist/r/src/components/ui/radio-group/index.ts +1 -0
  186. package/dist/r/src/components/ui/radio-group/radio-group.tsx +78 -0
  187. package/dist/r/src/components/ui/resizable/index.ts +6 -0
  188. package/dist/r/src/components/ui/resizable/resizable.tsx +74 -0
  189. package/dist/r/src/components/ui/scroll-area/index.ts +1 -0
  190. package/dist/r/src/components/ui/scroll-area/scroll-area.tsx +66 -0
  191. package/dist/r/src/components/ui/select/index.ts +11 -0
  192. package/dist/r/src/components/ui/select/select.tsx +188 -0
  193. package/dist/r/src/components/ui/separator/index.ts +1 -0
  194. package/dist/r/src/components/ui/separator/separator.tsx +40 -0
  195. package/dist/r/src/components/ui/sheet/index.ts +13 -0
  196. package/dist/r/src/components/ui/sheet/sheet.tsx +132 -0
  197. package/dist/r/src/components/ui/skeleton/index.ts +1 -0
  198. package/dist/r/src/components/ui/skeleton/skeleton.tsx +28 -0
  199. package/dist/r/src/components/ui/slider/index.ts +1 -0
  200. package/dist/r/src/components/ui/slider/slider.tsx +81 -0
  201. package/dist/r/src/components/ui/spinner/index.ts +1 -0
  202. package/dist/r/src/components/ui/spinner/spinner.tsx +58 -0
  203. package/dist/r/src/components/ui/status-chip/index.ts +8 -0
  204. package/dist/r/src/components/ui/status-chip/status-chip.tsx +142 -0
  205. package/dist/r/src/components/ui/switch/index.ts +1 -0
  206. package/dist/r/src/components/ui/switch/switch.tsx +100 -0
  207. package/dist/r/src/components/ui/table/index.ts +11 -0
  208. package/dist/r/src/components/ui/table/table.tsx +125 -0
  209. package/dist/r/src/components/ui/tabs/index.ts +8 -0
  210. package/dist/r/src/components/ui/tabs/tabs.tsx +77 -0
  211. package/dist/r/src/components/ui/textarea/index.ts +1 -0
  212. package/dist/r/src/components/ui/textarea/textarea.tsx +36 -0
  213. package/dist/r/src/components/ui/toast/index.ts +1 -0
  214. package/dist/r/src/components/ui/toast/toast.tsx +220 -0
  215. package/dist/r/src/components/ui/toggle/index.ts +1 -0
  216. package/dist/r/src/components/ui/toggle/toggle.tsx +60 -0
  217. package/dist/r/src/components/ui/toggle-group/index.ts +6 -0
  218. package/dist/r/src/components/ui/toggle-group/toggle-group.tsx +66 -0
  219. package/dist/r/src/components/ui/tooltip/index.ts +9 -0
  220. package/dist/r/src/components/ui/tooltip/tooltip.tsx +102 -0
  221. package/dist/r/src/lib/keyed-rows.ts +68 -0
  222. package/dist/r/src/lib/overlay.ts +70 -0
  223. package/dist/r/src/lib/themes.ts +490 -0
  224. package/dist/r/src/lib/tokens.ts +688 -0
  225. package/dist/r/src/lib/utils.ts +76 -0
  226. package/dist/r/src/lib/variants.ts +62 -0
  227. package/dist/r/src/lib/version-notes.ts +65 -0
  228. package/dist/r/src/styles/base.css +644 -0
  229. package/dist/r/src/styles/fonts.css +26 -0
  230. package/dist/r/src/styles/globals.css +18 -0
  231. package/dist/r/src/styles/theme.css +864 -0
  232. package/dist/r/stat.json +3 -1
  233. package/dist/r/status-bar.json +3 -1
  234. package/dist/r/status-chip.json +2 -1
  235. package/dist/r/switch.json +3 -1
  236. package/dist/r/table.json +3 -1
  237. package/dist/r/tabs.json +3 -1
  238. package/dist/r/textarea.json +3 -1
  239. package/dist/r/theming.json +42 -0
  240. package/dist/r/toast.json +3 -1
  241. package/dist/r/toggle-group.json +2 -1
  242. package/dist/r/toggle.json +3 -1
  243. package/dist/r/tooltip.json +3 -1
  244. package/dist/r/top-bar.json +3 -1
  245. package/dist/r/update-dialog.json +2 -1
  246. package/dist/r/workspace-mark.json +2 -1
  247. package/package.json +1 -1
  248. package/registry.json +320 -73
@@ -0,0 +1,76 @@
1
+ import { type ClassValue, clsx } from 'clsx'
2
+ import { extendTailwindMerge } from 'tailwind-merge'
3
+
4
+ /**
5
+ * `twMerge` needs to be told about the utilities this design system adds.
6
+ *
7
+ * Every token-derived utility (`h-control-md`, `w-rail`, `p-control-lg`, …)
8
+ * is an unknown name to a default `tailwind-merge` instance. Left
9
+ * unregistered, `cn('h-control-md', 'h-control-sm')` keeps both classes and
10
+ * the winner is decided by stylesheet order rather than by the caller — a bug
11
+ * that only shows up as a control that ignores its `size` prop, long after the
12
+ * line that caused it was written.
13
+ *
14
+ * Registering the families here is what makes "the last class wins" true for
15
+ * the whole system, including for consumers overriding a component's default.
16
+ */
17
+ export const twMergeConfig = extendTailwindMerge<'ds-height' | 'ds-width' | 'ds-size'>({
18
+ extend: {
19
+ classGroups: {
20
+ 'ds-height': [
21
+ {
22
+ h: [
23
+ 'control-2xs',
24
+ 'control-xs',
25
+ 'control-sm',
26
+ 'control-md',
27
+ 'control-lg',
28
+ 'control-xl',
29
+ 'row-sm',
30
+ 'row-md',
31
+ 'row-lg',
32
+ 'rail-item',
33
+ 'topbar',
34
+ 'statusbar',
35
+ ],
36
+ },
37
+ ],
38
+ 'ds-width': [
39
+ {
40
+ w: ['rail', 'rail-expanded', 'sidebar', 'sidebar-compact'],
41
+ },
42
+ ],
43
+ // `size-*` is a real Tailwind group, but the token-derived values are
44
+ // not, so they need the same treatment as height and width.
45
+ 'ds-size': [
46
+ {
47
+ size: [
48
+ 'control-2xs',
49
+ 'control-xs',
50
+ 'control-sm',
51
+ 'control-md',
52
+ 'control-lg',
53
+ 'control-xl',
54
+ 'rail-item',
55
+ ],
56
+ },
57
+ ],
58
+ },
59
+ },
60
+ })
61
+
62
+ /**
63
+ * Merge conditional class values, letting the last conflicting utility win.
64
+ *
65
+ * Accepts an object whose keys are classes and whose values enable them, which
66
+ * is the form the design-system linter can read statically:
67
+ *
68
+ * cn('base', { 'is-open': open(), 'is-disabled': disabled() })
69
+ *
70
+ * A template literal (`cn(`base--${value}`)`) is invisible to the linter and
71
+ * will be reported, because a class the linter cannot read is a class it
72
+ * cannot check against the theme.
73
+ */
74
+ export function cn(...inputs: ClassValue[]): string {
75
+ return twMergeConfig(clsx(inputs))
76
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The component variant vocabulary.
3
+ *
4
+ * Every component's appearance is declared with `cva`, and `@shadcn/lint`
5
+ * reads those definitions: it is how the linter can tell a caller "use the
6
+ * `destructive` variant" instead of only "this class is not allowed here".
7
+ * That is the whole reason variants live in the open rather than in a
8
+ * component's head.
9
+ *
10
+ * Three axes recur across the system, and components must reuse these names
11
+ * rather than inventing synonyms:
12
+ *
13
+ * variant what the control *is for* — primary, secondary, destructive, …
14
+ * size how much room it takes — 2xs, xs, sm, md, lg, xl
15
+ * tone what it *communicates* — neutral, success, warning, …
16
+ *
17
+ * A component that needs a fourth axis is usually two components.
18
+ */
19
+ export { cva, type VariantProps } from 'class-variance-authority'
20
+
21
+ /**
22
+ * The shared control-size ladder, in Tailwind height utilities.
23
+ *
24
+ * Spread into a `size` axis so every interactive control in the system steps
25
+ * through the same heights. A button and a select at `size="sm"` are both 28px
26
+ * because they read the same token, not because two authors agreed.
27
+ */
28
+ export const controlSize = {
29
+ '2xs': 'h-control-2xs px-control-2xs text-2xs gap-1',
30
+ xs: 'h-control-xs px-control-xs text-xs gap-1',
31
+ sm: 'h-control-sm px-control-sm text-xs gap-1.5',
32
+ md: 'h-control-md px-control-md text-sm gap-2',
33
+ lg: 'h-control-lg px-control-lg text-sm gap-2',
34
+ xl: 'h-control-xl px-control-xl text-base gap-2.5',
35
+ } as const
36
+
37
+ /** Square counterparts for icon-only controls: the height, with equal width. */
38
+ export const controlSizeIcon = {
39
+ '2xs': 'size-control-2xs p-0',
40
+ xs: 'size-control-xs p-0',
41
+ sm: 'size-control-sm p-0',
42
+ md: 'size-control-md p-0',
43
+ lg: 'size-control-lg p-0',
44
+ xl: 'size-control-xl p-0',
45
+ } as const
46
+
47
+ export const controlSizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl'] as const
48
+ export type ControlSize = (typeof controlSizes)[number]
49
+
50
+ /**
51
+ * The tactile half of every interactive control.
52
+ *
53
+ * Kept in one place so hover, active, focus and disabled read identically on a
54
+ * button, a toggle, a menu row and a tab. The `active:` step is only one
55
+ * lightness rung below hover — enough to feel pressed, not enough to look like
56
+ * a different state.
57
+ */
58
+ export const controlInteractive =
59
+ 'transition-colors ease-out outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50'
60
+
61
+ /** The shared focus treatment for surfaces that are not focusable controls. */
62
+ export const surfaceInteractive = 'transition-colors ease-out outline-none'
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Version notes, as text.
3
+ *
4
+ * A release changelog arrives as markdown and is shown to a reader who wants to
5
+ * know what changed, not to a renderer. Rendering it would mean a markdown
6
+ * dependency, a sanitiser, and a typographic result that competes with the
7
+ * dialog's own type scale — so the markup is stripped to its words instead.
8
+ *
9
+ * The order matters: images and links are unwrapped to their alt text and label
10
+ * *before* the emphasis rules run, because `[a](b)` contains brackets and
11
+ * parentheses that the later patterns would otherwise trip on.
12
+ */
13
+ export function plainTextFromMarkdown(markdown: string): string {
14
+ return markdown
15
+ .replace(/\r\n/g, '\n')
16
+ .replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
17
+ .replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
18
+ .replace(/^[ \t]*#{1,6}[ \t]*/gm, '')
19
+ .replace(/^[ \t]*>[ \t]?/gm, '')
20
+ .replace(/^[ \t]*---+[ \t]*$/gm, '')
21
+ .replace(/^[ \t]*[-*+][ \t]+/gm, '• ')
22
+ .replace(/^[ \t]*\d+\.[ \t]+/gm, '')
23
+ .replace(/```[^\n]*\n?/g, '')
24
+ .replace(/`([^`]+)`/g, '$1')
25
+ .replace(/\*\*([^*]+)\*\*/g, '$1')
26
+ .replace(/__([^_]+)__/g, '$1')
27
+ .replace(/\*([^*]+)\*/g, '$1')
28
+ .replace(/_([^_]+)_/g, '$1')
29
+ .replace(/\n{3,}/g, '\n\n')
30
+ .trim()
31
+ }
32
+
33
+ /**
34
+ * A release date, formatted for a reader. Returns the input when it cannot be
35
+ * parsed — a date a build tool wrote in an unusual format is still better shown
36
+ * verbatim than dropped.
37
+ */
38
+ export function formatReleaseDate(value: string | null): string | null {
39
+ if (!value) return null
40
+ const date = new Date(value)
41
+ if (Number.isNaN(date.getTime())) return value
42
+ return new Intl.DateTimeFormat(undefined, {
43
+ day: 'numeric',
44
+ month: 'short',
45
+ year: 'numeric',
46
+ }).format(date)
47
+ }
48
+
49
+ /**
50
+ * Bytes as a reader-facing size. Used by the update dialog's progress readout,
51
+ * where the number is reassurance rather than data — "12.4 MB of 48.1 MB" says
52
+ * the download is moving, which a percentage alone does not.
53
+ */
54
+ export function formatBytes(bytes: number): string {
55
+ if (!Number.isFinite(bytes) || bytes < 0) return '—'
56
+ if (bytes < 1024) return `${bytes} B`
57
+ const units = ['kB', 'MB', 'GB']
58
+ let value = bytes / 1024
59
+ let unit = 0
60
+ while (value >= 1024 && unit < units.length - 1) {
61
+ value /= 1024
62
+ unit += 1
63
+ }
64
+ return `${value.toFixed(value >= 10 ? 0 : 1)} ${units[unit]}`
65
+ }