@blotch/dolan 22.2.2 → 22.2.4

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 (259) hide show
  1. package/dist/commands/add.d.ts +6 -2
  2. package/dist/commands/add.js +41 -11
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/add.test.js +162 -9
  5. package/dist/commands/add.test.js.map +1 -1
  6. package/dist/commands/diff.d.ts +2 -1
  7. package/dist/commands/diff.js +38 -25
  8. package/dist/commands/diff.js.map +1 -1
  9. package/dist/commands/diff.test.js +72 -11
  10. package/dist/commands/diff.test.js.map +1 -1
  11. package/dist/commands/doctor.js +228 -34
  12. package/dist/commands/doctor.js.map +1 -1
  13. package/dist/commands/doctor.test.js +367 -10
  14. package/dist/commands/doctor.test.js.map +1 -1
  15. package/dist/commands/eject.js +7 -0
  16. package/dist/commands/eject.js.map +1 -1
  17. package/dist/commands/eject.test.js +39 -0
  18. package/dist/commands/eject.test.js.map +1 -1
  19. package/dist/commands/info.js +3 -2
  20. package/dist/commands/info.js.map +1 -1
  21. package/dist/commands/init.d.ts +37 -1
  22. package/dist/commands/init.js +169 -40
  23. package/dist/commands/init.js.map +1 -1
  24. package/dist/commands/init.test.js +392 -27
  25. package/dist/commands/init.test.js.map +1 -1
  26. package/dist/commands/install-packages.d.ts +6 -0
  27. package/dist/commands/install-packages.js +20 -0
  28. package/dist/commands/install-packages.js.map +1 -0
  29. package/dist/commands/install-packages.test.d.ts +1 -0
  30. package/dist/commands/install-packages.test.js +55 -0
  31. package/dist/commands/install-packages.test.js.map +1 -0
  32. package/dist/commands/list.js +21 -14
  33. package/dist/commands/list.js.map +1 -1
  34. package/dist/commands/list.test.js +62 -5
  35. package/dist/commands/list.test.js.map +1 -1
  36. package/dist/commands/outdated.js +11 -10
  37. package/dist/commands/outdated.js.map +1 -1
  38. package/dist/commands/outdated.test.js +20 -5
  39. package/dist/commands/outdated.test.js.map +1 -1
  40. package/dist/commands/remove.d.ts +4 -0
  41. package/dist/commands/remove.js +17 -4
  42. package/dist/commands/remove.js.map +1 -1
  43. package/dist/commands/remove.test.js +53 -2
  44. package/dist/commands/remove.test.js.map +1 -1
  45. package/dist/commands/theme.js +1 -1
  46. package/dist/commands/theme.js.map +1 -1
  47. package/dist/commands/update.d.ts +11 -0
  48. package/dist/commands/update.js +174 -58
  49. package/dist/commands/update.js.map +1 -1
  50. package/dist/commands/update.test.js +587 -33
  51. package/dist/commands/update.test.js.map +1 -1
  52. package/dist/index.js +7 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/lockfile.d.ts +7 -0
  55. package/dist/lockfile.js +36 -0
  56. package/dist/lockfile.js.map +1 -1
  57. package/dist/lockfile.test.d.ts +1 -0
  58. package/dist/lockfile.test.js +25 -0
  59. package/dist/lockfile.test.js.map +1 -0
  60. package/dist/registry.d.ts +14 -0
  61. package/dist/registry.js +78 -24
  62. package/dist/registry.js.map +1 -1
  63. package/dist/registry.test.js +119 -38
  64. package/dist/registry.test.js.map +1 -1
  65. package/dist/test-utils.d.ts +5 -0
  66. package/dist/test-utils.js +6 -1
  67. package/dist/test-utils.js.map +1 -1
  68. package/dist/testing/fire-lynx-event.d.ts +14 -0
  69. package/dist/testing/fire-lynx-event.js +19 -0
  70. package/dist/testing/fire-lynx-event.js.map +1 -0
  71. package/dist/testing/fire-lynx-event.test.d.ts +1 -0
  72. package/dist/testing/fire-lynx-event.test.js +44 -0
  73. package/dist/testing/fire-lynx-event.test.js.map +1 -0
  74. package/dist/testing/lynx-main-thread.d.ts +22 -0
  75. package/dist/testing/lynx-main-thread.js +11 -0
  76. package/dist/testing/lynx-main-thread.js.map +1 -0
  77. package/dist/testing/lynx-main-thread.test.d.ts +1 -0
  78. package/dist/testing/lynx-main-thread.test.js +24 -0
  79. package/dist/testing/lynx-main-thread.test.js.map +1 -0
  80. package/dist/testing/set-input-signal.d.ts +14 -0
  81. package/dist/testing/set-input-signal.js +21 -0
  82. package/dist/testing/set-input-signal.js.map +1 -0
  83. package/dist/testing/set-input-signal.test.d.ts +1 -0
  84. package/dist/testing/set-input-signal.test.js +20 -0
  85. package/dist/testing/set-input-signal.test.js.map +1 -0
  86. package/dist/ui/components/accordion/accordion.test.ts +158 -144
  87. package/dist/ui/components/accordion/accordion.ts +19 -14
  88. package/dist/ui/components/action-sheet/action-sheet.test.ts +283 -151
  89. package/dist/ui/components/action-sheet/action-sheet.ts +77 -43
  90. package/dist/ui/components/alert/alert.test.ts +67 -19
  91. package/dist/ui/components/alert/alert.ts +14 -16
  92. package/dist/ui/components/alert-dialog/alert-dialog.test.ts +208 -94
  93. package/dist/ui/components/alert-dialog/alert-dialog.ts +75 -38
  94. package/dist/ui/components/area-chart/area-chart.test.ts +134 -119
  95. package/dist/ui/components/area-chart/area-chart.ts +100 -315
  96. package/dist/ui/components/area-chart/index.ts +2 -3
  97. package/dist/ui/components/avatar/avatar.test.ts +89 -45
  98. package/dist/ui/components/badge/badge.test.ts +57 -23
  99. package/dist/ui/components/badge/badge.ts +12 -14
  100. package/dist/ui/components/bar-chart/bar-chart.test.ts +172 -45
  101. package/dist/ui/components/bar-chart/bar-chart.ts +140 -294
  102. package/dist/ui/components/bar-chart/index.ts +3 -3
  103. package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +386 -128
  104. package/dist/ui/components/bottom-sheet/bottom-sheet.ts +170 -53
  105. package/dist/ui/components/button/button.test.ts +611 -2
  106. package/dist/ui/components/button/button.ts +434 -49
  107. package/dist/ui/components/button/index.ts +2 -0
  108. package/dist/ui/components/button-group/button-group.test.ts +484 -2
  109. package/dist/ui/components/button-group/button-group.ts +380 -68
  110. package/dist/ui/components/button-group/index.ts +3 -0
  111. package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +183 -58
  112. package/dist/ui/components/candlestick-chart/candlestick-chart.ts +150 -323
  113. package/dist/ui/components/candlestick-chart/index.ts +3 -4
  114. package/dist/ui/components/card/card.test.ts +82 -62
  115. package/dist/ui/components/chart/chart-focus.test.ts +132 -0
  116. package/dist/ui/components/chart/chart-focus.ts +115 -0
  117. package/dist/ui/components/chart/chart-presets.test.ts +335 -0
  118. package/dist/ui/components/chart/chart-presets.ts +278 -0
  119. package/dist/ui/components/chart/chart-scene.test.ts +589 -0
  120. package/dist/ui/components/chart/chart-scene.ts +483 -0
  121. package/dist/ui/components/chart/chart-theme.test.ts +85 -0
  122. package/dist/ui/components/chart/chart-theme.ts +210 -0
  123. package/dist/ui/components/chart/chart-zoom.test.ts +159 -0
  124. package/dist/ui/components/chart/chart-zoom.ts +162 -0
  125. package/dist/ui/components/chart/chart.test.ts +1017 -0
  126. package/dist/ui/components/chart/chart.ts +934 -0
  127. package/dist/ui/components/chart/index.ts +24 -0
  128. package/dist/ui/components/checkbox/checkbox.test.ts +124 -42
  129. package/dist/ui/components/checkbox/checkbox.ts +23 -23
  130. package/dist/ui/components/collapsible/collapsible.test.ts +158 -81
  131. package/dist/ui/components/collapsible/collapsible.ts +19 -14
  132. package/dist/ui/components/context-menu/context-menu.test.ts +224 -0
  133. package/dist/ui/components/context-menu/context-menu.ts +110 -0
  134. package/dist/ui/components/context-menu/index.ts +1 -0
  135. package/dist/ui/components/dialog/dialog.test.ts +213 -108
  136. package/dist/ui/components/dialog/dialog.ts +72 -35
  137. package/dist/ui/components/dock/dock-scroll.test.ts +130 -0
  138. package/dist/ui/components/dock/dock-scroll.ts +133 -0
  139. package/dist/ui/components/dock/dock.test.ts +749 -0
  140. package/dist/ui/components/dock/dock.ts +960 -0
  141. package/dist/ui/components/dock/index.ts +2 -0
  142. package/dist/ui/components/empty-state/empty-state.test.ts +28 -39
  143. package/dist/ui/components/glass/concentric-radius.test.ts +13 -0
  144. package/dist/ui/components/glass/concentric-radius.ts +17 -0
  145. package/dist/ui/components/glass/glass-design.test.ts +78 -0
  146. package/dist/ui/components/glass/glass-design.ts +119 -0
  147. package/dist/ui/components/glass/glass.test.ts +338 -0
  148. package/dist/ui/components/glass/glass.ts +360 -0
  149. package/dist/ui/components/glass/index.ts +18 -0
  150. package/dist/ui/components/icon/icon-theme.test.ts +169 -0
  151. package/dist/ui/components/icon/icon-theme.ts +227 -0
  152. package/dist/ui/components/icon/icon.test.ts +85 -25
  153. package/dist/ui/components/icon/icon.ts +38 -21
  154. package/dist/ui/components/input/input.test.ts +178 -101
  155. package/dist/ui/components/input/input.ts +15 -12
  156. package/dist/ui/components/label/label.test.ts +11 -24
  157. package/dist/ui/components/line-chart/index.ts +2 -3
  158. package/dist/ui/components/line-chart/line-chart.test.ts +149 -56
  159. package/dist/ui/components/line-chart/line-chart.ts +83 -241
  160. package/dist/ui/components/list/list.test.ts +119 -21
  161. package/dist/ui/components/list/list.ts +21 -15
  162. package/dist/ui/components/menu/index.ts +25 -0
  163. package/dist/ui/components/menu/menu-placement.test.ts +153 -0
  164. package/dist/ui/components/menu/menu-placement.ts +159 -0
  165. package/dist/ui/components/menu/menu-popup.test.ts +632 -0
  166. package/dist/ui/components/menu/menu-popup.ts +544 -0
  167. package/dist/ui/components/menu/menu.test.ts +429 -0
  168. package/dist/ui/components/menu/menu.ts +415 -0
  169. package/dist/ui/components/nav-drawer/nav-drawer.test.ts +435 -191
  170. package/dist/ui/components/nav-drawer/nav-drawer.ts +127 -56
  171. package/dist/ui/components/pagination/pagination.test.ts +177 -65
  172. package/dist/ui/components/pagination/pagination.ts +55 -8
  173. package/dist/ui/components/progress/progress.test.ts +102 -46
  174. package/dist/ui/components/progress/progress.ts +52 -54
  175. package/dist/ui/components/radio-group/radio-group.test.ts +128 -83
  176. package/dist/ui/components/radio-group/radio-group.ts +24 -24
  177. package/dist/ui/components/scatter-chart/index.ts +2 -3
  178. package/dist/ui/components/scatter-chart/scatter-chart.test.ts +131 -26
  179. package/dist/ui/components/scatter-chart/scatter-chart.ts +104 -250
  180. package/dist/ui/components/scroll-area/scroll-area.test.ts +95 -24
  181. package/dist/ui/components/scroll-area/scroll-area.ts +8 -8
  182. package/dist/ui/components/select/select.test.ts +138 -78
  183. package/dist/ui/components/select/select.ts +17 -11
  184. package/dist/ui/components/separator/separator.test.ts +18 -17
  185. package/dist/ui/components/sheet/sheet.test.ts +64 -11
  186. package/dist/ui/components/sheet/sheet.ts +9 -1
  187. package/dist/ui/components/skeleton/skeleton.test.ts +24 -7
  188. package/dist/ui/components/skeleton/skeleton.ts +10 -16
  189. package/dist/ui/components/spinner/spinner.test.ts +67 -22
  190. package/dist/ui/components/spinner/spinner.ts +48 -41
  191. package/dist/ui/components/switch/switch.test.ts +116 -46
  192. package/dist/ui/components/switch/switch.ts +8 -13
  193. package/dist/ui/components/tab-bar/index.ts +1 -0
  194. package/dist/ui/components/tab-bar/tab-bar.test.ts +280 -0
  195. package/dist/ui/components/tab-bar/tab-bar.ts +230 -0
  196. package/dist/ui/components/tabs/tabs.test.ts +215 -157
  197. package/dist/ui/components/tabs/tabs.ts +110 -118
  198. package/dist/ui/components/textarea/textarea.test.ts +206 -100
  199. package/dist/ui/components/textarea/textarea.ts +14 -12
  200. package/dist/ui/components/toast/toast.test.ts +436 -315
  201. package/dist/ui/components/toast/toast.ts +62 -55
  202. package/dist/ui/components/toggle/toggle.test.ts +247 -140
  203. package/dist/ui/theme/chart-colors.test.ts +35 -0
  204. package/dist/ui/theme/dark.css +46 -2
  205. package/dist/ui/theme/default.css +63 -7
  206. package/dist/ui/theme/icon-colors.test.ts +35 -0
  207. package/dist/ui/theme/rgb-channels.test.ts +84 -0
  208. package/dist/ui/theme/tailwind-build.test.ts +114 -0
  209. package/dist/ui/theme/tailwind-css.test.ts +83 -0
  210. package/dist/ui/theme/tailwind-plugin.test.ts +42 -2
  211. package/dist/ui/theme/tailwind-plugin.ts +98 -25
  212. package/dist/ui/theme/tailwind.css +113 -0
  213. package/dist/ui/utils/animate.test.ts +13 -1
  214. package/dist/utils/analyze.d.ts +14 -0
  215. package/dist/utils/analyze.js +15 -0
  216. package/dist/utils/analyze.js.map +1 -1
  217. package/dist/utils/analyze.test.js +14 -1
  218. package/dist/utils/analyze.test.js.map +1 -1
  219. package/dist/utils/installed.d.ts +29 -0
  220. package/dist/utils/installed.js +43 -0
  221. package/dist/utils/installed.js.map +1 -0
  222. package/dist/utils/installed.test.d.ts +1 -0
  223. package/dist/utils/installed.test.js +57 -0
  224. package/dist/utils/installed.test.js.map +1 -0
  225. package/dist/utils/interactive.d.ts +9 -0
  226. package/dist/utils/interactive.js +10 -0
  227. package/dist/utils/interactive.js.map +1 -0
  228. package/dist/utils/interactive.test.d.ts +1 -0
  229. package/dist/utils/interactive.test.js +24 -0
  230. package/dist/utils/interactive.test.js.map +1 -0
  231. package/dist/utils/packages.d.ts +36 -0
  232. package/dist/utils/packages.js +70 -0
  233. package/dist/utils/packages.js.map +1 -0
  234. package/dist/utils/packages.test.d.ts +1 -0
  235. package/dist/utils/packages.test.js +89 -0
  236. package/dist/utils/packages.test.js.map +1 -0
  237. package/dist/utils/resolve-paths.d.ts +17 -1
  238. package/dist/utils/resolve-paths.js +21 -3
  239. package/dist/utils/resolve-paths.js.map +1 -1
  240. package/dist/utils/resolve-paths.test.js +38 -2
  241. package/dist/utils/resolve-paths.test.js.map +1 -1
  242. package/dist/utils/tailwind.d.ts +25 -0
  243. package/dist/utils/tailwind.js +51 -0
  244. package/dist/utils/tailwind.js.map +1 -0
  245. package/dist/utils/tailwind.test.d.ts +1 -0
  246. package/dist/utils/tailwind.test.js +71 -0
  247. package/dist/utils/tailwind.test.js.map +1 -0
  248. package/package.json +13 -1
  249. package/dist/ui/components/area-chart/area-chart-render.test.ts +0 -121
  250. package/dist/ui/components/bar-chart/bar-chart-render.test.ts +0 -174
  251. package/dist/ui/components/button/button-render.test.ts +0 -113
  252. package/dist/ui/components/button-group/button-group-render.test.ts +0 -146
  253. package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +0 -174
  254. package/dist/ui/components/cartesian-chart/cartesian-chart-render.test.ts +0 -188
  255. package/dist/ui/components/cartesian-chart/cartesian-chart.test.ts +0 -525
  256. package/dist/ui/components/cartesian-chart/cartesian-chart.ts +0 -1140
  257. package/dist/ui/components/cartesian-chart/index.ts +0 -18
  258. package/dist/ui/components/line-chart/line-chart-render.test.ts +0 -121
  259. package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +0 -157
@@ -16,7 +16,7 @@ const SAFE_AREA_SIDES = {
16
16
  * Registers safe-area-aware padding utilities driven by CSS `env(safe-area-inset-*)`.
17
17
  *
18
18
  * Why `env()` works on Lynx: the native CSS engine parses `env(safe-area-inset-*)`
19
- * as a length (see references/lynx .../css_style_utils.cc `GetEnvValue`), and its
19
+ * as a length (see lynx-family/lynx's css_style_utils.cc `GetEnvValue`), and its
20
20
  * calc parser accepts `env()` *inside* `calc()` too — so `calc(1rem + env(...))`
21
21
  * is valid on device. The inset values default to `0` until the native host app
22
22
  * populates them, so every utility here degrades gracefully to plain padding
@@ -69,6 +69,51 @@ export const addSafeAreaUtilities = ({
69
69
  }
70
70
  };
71
71
 
72
+ /**
73
+ * What Tailwind passes a color it was given as a function:
74
+ * - an opacity modifier sets only `opacityValue` (`bg-primary/50` → `0.5`);
75
+ * - a plain class whose utility has an opacity variable sets
76
+ * `opacityVariable` too, and `opacityValue` is `var(--tw-bg-opacity, 1)`
77
+ * (`bg-primary`);
78
+ * - other plain classes pass neither (`caret-primary`);
79
+ * - `theme('colors.primary')` in a stylesheet passes an `opacityValue` of 1.
80
+ */
81
+ type ColorOptions = {
82
+ opacityValue?: string | number;
83
+ opacityVariable?: string;
84
+ };
85
+
86
+ /**
87
+ * A theme color that takes Tailwind's opacity modifiers on Lynx.
88
+ *
89
+ * A plain class reads the complete color, as it always has:
90
+ * `bg-primary` → `background-color: var(--primary)`. A modifier reads the
91
+ * color's channels from its `-rgb` twin:
92
+ * `bg-primary/50` → `background-color: rgba(var(--primary-rgb), 0.5)`.
93
+ *
94
+ * Lynx substitutes `var()` as text before it parses the value, so with
95
+ * `--primary-rgb: 24, 24, 27` its color parser sees `rgba(24, 24, 27, 0.5)`
96
+ * (`CSSValue::Substitution` in lynx-family/lynx). The channels are
97
+ * comma-separated because every Lynx color parser takes `rgba()` in that
98
+ * form. Lynx takes `hsl()` only with commas, which is why the shadcn/ui form,
99
+ * `hsl(var(--x) / 0.5)`, draws nothing.
100
+ *
101
+ * Plain classes stay on `var(--x)` so they don't need the channels: with a
102
+ * theme copied before the `-rgb` variables existed, every plain class still
103
+ * draws, and only modifiers don't. Tailwind's `<alpha-value>` placeholder
104
+ * can't do that, as it puts the channels in plain classes too. An alpha of 1
105
+ * is the plain color, so `bg-primary/100` and `theme('colors.primary')` read
106
+ * `var(--primary)` as well.
107
+ */
108
+ export const themeColor =
109
+ (name: string) =>
110
+ ({ opacityValue, opacityVariable }: ColorOptions = {}): string =>
111
+ opacityValue === undefined ||
112
+ opacityVariable !== undefined ||
113
+ String(opacityValue) === '1'
114
+ ? `var(--${name})`
115
+ : `rgba(var(--${name}-rgb), ${opacityValue})`;
116
+
72
117
  /**
73
118
  * Tailwind plugin that maps @blotch/ui CSS variables to semantic color utilities
74
119
  * and registers safe-area-aware padding utilities.
@@ -86,10 +131,9 @@ export const addSafeAreaUtilities = ({
86
131
  * referencing them directly avoids color-function parsing entirely. This matches
87
132
  * the official React Lynx Tailwind example.
88
133
  *
89
- * Tradeoff: Tailwind opacity modifiers on semantic colors (bg-primary/50) don't
90
- * work — the value is opaque with no separable channels. For the rare
91
- * translucent-semantic need, add a dedicated rgba() variable (see
92
- * `--destructive-subtle` → `destructive.subtle`) or use `opacity-*` on the element.
134
+ * Opacity modifiers (`bg-primary/50`, `text-foreground/70`,
135
+ * `border-border/60`) read each color's `--x-rgb` channels instead; see
136
+ * `themeColor`.
93
137
  *
94
138
  * Safe area: see `addSafeAreaUtilities` for the `*-safe` / `*-safe-<n>` padding
95
139
  * utilities that keep content clear of notches and home indicators.
@@ -106,40 +150,69 @@ export const blotchPlugin = plugin(
106
150
  {
107
151
  theme: {
108
152
  extend: {
153
+ // Tailwind's types only allow strings here, but it also takes a
154
+ // function, which it calls with the modifier's alpha: that's how it
155
+ // applies `<alpha-value>` itself. Every color but destructive.subtle
156
+ // and glass.dim, which are translucent already, has an `--x-rgb` twin
157
+ // in the theme, so takes opacity modifiers.
109
158
  colors: {
110
- background: 'var(--background)',
111
- foreground: 'var(--foreground)',
159
+ background: themeColor('background'),
160
+ foreground: themeColor('foreground'),
112
161
  primary: {
113
- DEFAULT: 'var(--primary)',
114
- foreground: 'var(--primary-foreground)',
162
+ DEFAULT: themeColor('primary'),
163
+ foreground: themeColor('primary-foreground'),
115
164
  },
116
165
  secondary: {
117
- DEFAULT: 'var(--secondary)',
118
- foreground: 'var(--secondary-foreground)',
166
+ DEFAULT: themeColor('secondary'),
167
+ foreground: themeColor('secondary-foreground'),
119
168
  },
120
169
  muted: {
121
- DEFAULT: 'var(--muted)',
122
- foreground: 'var(--muted-foreground)',
170
+ DEFAULT: themeColor('muted'),
171
+ foreground: themeColor('muted-foreground'),
123
172
  },
124
173
  accent: {
125
- DEFAULT: 'var(--accent)',
126
- foreground: 'var(--accent-foreground)',
174
+ DEFAULT: themeColor('accent'),
175
+ foreground: themeColor('accent-foreground'),
127
176
  },
128
177
  destructive: {
129
- DEFAULT: 'var(--destructive)',
130
- foreground: 'var(--destructive-foreground)',
131
- // Pre-composed translucent red for subtle destructive backgrounds,
132
- // since bg-destructive/10 (opacity modifier) can't work here.
178
+ DEFAULT: themeColor('destructive'),
179
+ foreground: themeColor('destructive-foreground'),
180
+ // Red at 10%, the destructive alert's background. It's
181
+ // translucent already, so it has no channels and takes no
182
+ // modifier. It predates modifiers and stays for the apps that
183
+ // use it: bg-destructive/10 draws the same color, but only in a
184
+ // theme that has --destructive-rgb.
133
185
  subtle: 'var(--destructive-subtle)',
134
186
  },
135
- border: 'var(--border)',
136
- input: 'var(--input)',
137
- ring: 'var(--ring)',
187
+ border: themeColor('border'),
188
+ input: themeColor('input'),
189
+ ring: themeColor('ring'),
138
190
  card: {
139
- DEFAULT: 'var(--card)',
140
- foreground: 'var(--card-foreground)',
191
+ DEFAULT: themeColor('card'),
192
+ foreground: themeColor('card-foreground'),
141
193
  },
142
- },
194
+ // Chart series colors, e.g. bg-chart-1 for a legend swatch that
195
+ // matches the first series.
196
+ chart: {
197
+ 1: themeColor('chart-1'),
198
+ 2: themeColor('chart-2'),
199
+ 3: themeColor('chart-3'),
200
+ 4: themeColor('chart-4'),
201
+ 5: themeColor('chart-5'),
202
+ },
203
+ // What sits on Liquid Glass, and its tint: text-glass-foreground,
204
+ // bg-glass-tint, bg-glass-dim (see the glass component).
205
+ glass: {
206
+ tint: {
207
+ DEFAULT: themeColor('glass-tint'),
208
+ foreground: themeColor('glass-tint-foreground'),
209
+ },
210
+ foreground: themeColor('glass-foreground'),
211
+ 'muted-foreground': themeColor('glass-muted-foreground'),
212
+ 'clear-foreground': themeColor('glass-clear-foreground'),
213
+ dim: 'var(--glass-dim)',
214
+ },
215
+ } as unknown as Record<string, string>,
143
216
  borderRadius: {
144
217
  lg: 'var(--radius)',
145
218
  md: 'calc(var(--radius) - 2px)',
@@ -0,0 +1,113 @@
1
+ /*
2
+ * @blotch/ui theme for Tailwind CSS 4: what tailwind-plugin.ts does for
3
+ * Tailwind 3, written the CSS-first way. Import it after Tailwind, with
4
+ * default.css (and dark.css) for the colors themselves:
5
+ *
6
+ * @import './styles/default.css';
7
+ * @import './styles/tailwind.css';
8
+ *
9
+ * The semantic colors (bg-primary, text-muted-foreground, border-border)
10
+ * read the theme's variables directly, `inline` so the utilities write
11
+ * `var(--primary)` rather than a Tailwind variable that points at it. That
12
+ * keeps them switching with dark.css. An opacity modifier (bg-primary/50) is
13
+ * a color-mix() of that variable, which Lynx can't read; the build writes it
14
+ * as rgba(var(--primary-rgb), 0.5), from the channels default.css sets beside
15
+ * each color, as the Tailwind 3 plugin's themeColor() does.
16
+ */
17
+ @theme inline {
18
+ --color-background: var(--background);
19
+ --color-foreground: var(--foreground);
20
+ --color-card: var(--card);
21
+ --color-card-foreground: var(--card-foreground);
22
+ --color-primary: var(--primary);
23
+ --color-primary-foreground: var(--primary-foreground);
24
+ --color-secondary: var(--secondary);
25
+ --color-secondary-foreground: var(--secondary-foreground);
26
+ --color-muted: var(--muted);
27
+ --color-muted-foreground: var(--muted-foreground);
28
+ --color-accent: var(--accent);
29
+ --color-accent-foreground: var(--accent-foreground);
30
+ --color-destructive: var(--destructive);
31
+ --color-destructive-foreground: var(--destructive-foreground);
32
+ /* Pre-composed translucent red for subtle destructive backgrounds. */
33
+ --color-destructive-subtle: var(--destructive-subtle);
34
+ --color-border: var(--border);
35
+ --color-input: var(--input);
36
+ --color-ring: var(--ring);
37
+ /* Chart series colors, e.g. bg-chart-1 for a legend swatch that matches
38
+ the first series. */
39
+ --color-chart-1: var(--chart-1);
40
+ --color-chart-2: var(--chart-2);
41
+ --color-chart-3: var(--chart-3);
42
+ --color-chart-4: var(--chart-4);
43
+ --color-chart-5: var(--chart-5);
44
+ /* What sits on Liquid Glass, and its tint (see the glass component).
45
+ glass-dim is translucent already, so it takes no opacity modifier. */
46
+ --color-glass-tint: var(--glass-tint);
47
+ --color-glass-tint-foreground: var(--glass-tint-foreground);
48
+ --color-glass-foreground: var(--glass-foreground);
49
+ --color-glass-muted-foreground: var(--glass-muted-foreground);
50
+ --color-glass-clear-foreground: var(--glass-clear-foreground);
51
+ --color-glass-dim: var(--glass-dim);
52
+
53
+ --radius-lg: var(--radius);
54
+ --radius-md: calc(var(--radius) - 2px);
55
+ --radius-sm: calc(var(--radius) - 4px);
56
+ }
57
+
58
+ @layer base {
59
+ * {
60
+ border-color: var(--border);
61
+ }
62
+ }
63
+
64
+ /*
65
+ * Safe-area padding, driven by env(safe-area-inset-*), which Lynx parses as
66
+ * a length, inside calc() too. The insets are 0 until the host app sets
67
+ * them, so each utility falls back to plain padding (or none).
68
+ *
69
+ * Bare (pb-safe, px-safe, p-safe): padding equal to the inset.
70
+ * Offset (pb-safe-4, pt-safe-2): a spacing-scale value plus the inset, for an
71
+ * element that wants its own padding and must also clear the notch or the
72
+ * home indicator.
73
+ */
74
+ @utility pt-safe {
75
+ padding-top: env(safe-area-inset-top);
76
+ }
77
+ @utility pr-safe {
78
+ padding-right: env(safe-area-inset-right);
79
+ }
80
+ @utility pb-safe {
81
+ padding-bottom: env(safe-area-inset-bottom);
82
+ }
83
+ @utility pl-safe {
84
+ padding-left: env(safe-area-inset-left);
85
+ }
86
+ @utility px-safe {
87
+ padding-left: env(safe-area-inset-left);
88
+ padding-right: env(safe-area-inset-right);
89
+ }
90
+ @utility py-safe {
91
+ padding-top: env(safe-area-inset-top);
92
+ padding-bottom: env(safe-area-inset-bottom);
93
+ }
94
+ @utility p-safe {
95
+ padding-top: env(safe-area-inset-top);
96
+ padding-right: env(safe-area-inset-right);
97
+ padding-bottom: env(safe-area-inset-bottom);
98
+ padding-left: env(safe-area-inset-left);
99
+ }
100
+ @utility pt-safe-* {
101
+ padding-top: calc(--spacing(--value(number)) + env(safe-area-inset-top));
102
+ }
103
+ @utility pr-safe-* {
104
+ padding-right: calc(--spacing(--value(number)) + env(safe-area-inset-right));
105
+ }
106
+ @utility pb-safe-* {
107
+ padding-bottom: calc(
108
+ --spacing(--value(number)) + env(safe-area-inset-bottom)
109
+ );
110
+ }
111
+ @utility pl-safe-* {
112
+ padding-left: calc(--spacing(--value(number)) + env(safe-area-inset-left));
113
+ }
@@ -28,8 +28,20 @@ import {
28
28
  springTranslateX,
29
29
  } from './animate';
30
30
 
31
+ // The keyframes and options the helpers hand `animate()`, typed with the
32
+ // fields the assertions read: the mock's calls are typed from its parameters.
33
+ type Keyframe = { transform?: string; opacity?: number };
34
+ type AnimateOptions = {
35
+ duration?: number;
36
+ easing?: string;
37
+ fill?: string;
38
+ iterations?: number;
39
+ };
40
+
31
41
  const makeEl = () => ({
32
- animate: vi.fn(() => ({ cancel: vi.fn() })),
42
+ animate: vi.fn((_keyframes: Keyframe[], _options: AnimateOptions) => ({
43
+ cancel: vi.fn(),
44
+ })),
33
45
  setStyle: vi.fn(),
34
46
  });
35
47
 
@@ -5,6 +5,11 @@ export type FileAnalysis = {
5
5
  status: FileStatus;
6
6
  currentContent: string;
7
7
  newContent: string;
8
+ /**
9
+ * Upstream stopped shipping the file, so taking upstream's version deletes
10
+ * it (see analyzeRemovedFile). Its `newContent` is empty.
11
+ */
12
+ removed?: boolean;
8
13
  };
9
14
  export type ComponentAnalysis = {
10
15
  name: string;
@@ -24,6 +29,15 @@ export declare const STATUS_LABELS: Record<FileStatus, string>;
24
29
  * so any difference is flagged as a conflict to be safe.
25
30
  */
26
31
  export declare const analyzeFile: (currentContent: string | null, newContent: string, storedHash: string | null, hashContent: (content: string) => string) => FileStatus;
32
+ /**
33
+ * The status of a file dolan tracks but upstream no longer ships, such as the
34
+ * `*-render.test.ts` files that 22.2.3 stopped copying. Upstream's version of
35
+ * it is "no file", so the same three-way rules apply as for a changed file:
36
+ * - gone from disk too → up-to-date (only its lockfile entry is left)
37
+ * - current == base → auto-update (nobody edited it: delete it)
38
+ * - current != base → conflict (git's modify/delete: ask before deleting)
39
+ */
40
+ export declare const analyzeRemovedFile: (currentContent: string | null, storedHash: string, hashContent: (content: string) => string) => FileStatus;
27
41
  export declare const formatDiff: (currentContent: string, newContent: string) => string;
28
42
  export declare const summarizeComponent: (analysis: ComponentAnalysis) => FileStatus;
29
43
  export { type Hunk } from 'diff';
@@ -46,6 +46,21 @@ export const analyzeFile = (currentContent, newContent, storedHash, hashContent)
46
46
  return 'user-modified';
47
47
  return 'conflict';
48
48
  };
49
+ /**
50
+ * The status of a file dolan tracks but upstream no longer ships, such as the
51
+ * `*-render.test.ts` files that 22.2.3 stopped copying. Upstream's version of
52
+ * it is "no file", so the same three-way rules apply as for a changed file:
53
+ * - gone from disk too → up-to-date (only its lockfile entry is left)
54
+ * - current == base → auto-update (nobody edited it: delete it)
55
+ * - current != base → conflict (git's modify/delete: ask before deleting)
56
+ */
57
+ export const analyzeRemovedFile = (currentContent, storedHash, hashContent) => {
58
+ if (currentContent === null)
59
+ return 'up-to-date';
60
+ return hashContent(currentContent) === storedHash
61
+ ? 'auto-update'
62
+ : 'conflict';
63
+ };
49
64
  export const formatDiff = (currentContent, newContent) => {
50
65
  const changes = diffLines(currentContent, newContent);
51
66
  const lines = [];
@@ -1 +1 @@
1
- {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/utils/analyze.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/utils/analyze.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { createHash } from 'node:crypto';
3
- import { analyzeFile, formatDiff, summarizeComponent } from './analyze';
3
+ import { analyzeFile, analyzeRemovedFile, formatDiff, summarizeComponent, } from './analyze';
4
4
  const hash = (content) => createHash('sha256').update(content).digest('hex').slice(0, 16);
5
5
  describe('analyzeFile', () => {
6
6
  it('returns new-upstream when current content is null', () => {
@@ -33,6 +33,19 @@ describe('analyzeFile', () => {
33
33
  expect(analyzeFile('user-edit', 'upstream-edit', stored, hash)).toBe('conflict');
34
34
  });
35
35
  });
36
+ // A file dolan tracks that upstream no longer ships: upstream's version is
37
+ // "no file".
38
+ describe('analyzeRemovedFile', () => {
39
+ it('returns up-to-date when the file is gone from disk too', () => {
40
+ expect(analyzeRemovedFile(null, hash('copied'), hash)).toBe('up-to-date');
41
+ });
42
+ it('returns auto-update when nobody edited it, so it can just go', () => {
43
+ expect(analyzeRemovedFile('copied', hash('copied'), hash)).toBe('auto-update');
44
+ });
45
+ it('returns conflict when it was edited, so deleting it needs a yes', () => {
46
+ expect(analyzeRemovedFile('edited', hash('copied'), hash)).toBe('conflict');
47
+ });
48
+ });
36
49
  describe('summarizeComponent', () => {
37
50
  it('returns up-to-date when all files are up-to-date', () => {
38
51
  const result = summarizeComponent({
@@ -1 +1 @@
1
- {"version":3,"file":"analyze.test.js","sourceRoot":"","sources":["../../src/utils/analyze.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyze.test.js","sourceRoot":"","sources":["../../src/utils/analyze.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Lockfile } from '../lockfile.js';
2
+ /**
3
+ * The registry components with a folder in the components directory. Other
4
+ * folders (the app's own code next to the components) aren't dolan's.
5
+ */
6
+ export declare const componentsOnDisk: (componentsDir: string) => string[];
7
+ /**
8
+ * The installed components dolan tracks: on disk and in the lockfile. `add`
9
+ * records every component it copies, and `eject` removes the record to hand
10
+ * the component over to the app, so a folder without one is the app's own
11
+ * code. `update`, `list`, `diff` and `outdated` leave it alone: before, they
12
+ * scanned the folders, so an ejected component showed as a conflict,
13
+ * `update --force` overwrote it and `update` tracked it again.
14
+ */
15
+ export declare const trackedComponents: (componentsDir: string, lockfile: Lockfile) => string[];
16
+ /** The components on disk that dolan doesn't track (see trackedComponents). */
17
+ export declare const untrackedComponents: (componentsDir: string, lockfile: Lockfile) => string[];
18
+ /**
19
+ * The files dolan tracks for a component that upstream no longer ships, such
20
+ * as the `*-render.test.ts` files that 22.2.3 stopped copying. `update` and
21
+ * `add` used to keep their lockfile entries and leave them on disk, where a
22
+ * stale spec importing a helper dolan doesn't copy broke the app's `ng test`.
23
+ *
24
+ * Shipped means shipped with tests: a project without the testing library
25
+ * doesn't get the components' `<name>.test.ts`, but upstream still ships it,
26
+ * so a copy from before dolan checked for the library isn't deleted here
27
+ * (`doctor` warns about those instead).
28
+ */
29
+ export declare const droppedFiles: (name: string, lockfile: Lockfile) => string[];
@@ -0,0 +1,43 @@
1
+ import { existsSync, readdirSync } from 'node:fs';
2
+ import { getComponentNames } from '../registry.js';
3
+ import { getComponentFiles } from './resolve-paths.js';
4
+ /**
5
+ * The registry components with a folder in the components directory. Other
6
+ * folders (the app's own code next to the components) aren't dolan's.
7
+ */
8
+ export const componentsOnDisk = (componentsDir) => {
9
+ if (!existsSync(componentsDir))
10
+ return [];
11
+ const known = new Set(getComponentNames());
12
+ return readdirSync(componentsDir, { withFileTypes: true })
13
+ .filter((entry) => entry.isDirectory() && known.has(entry.name))
14
+ .map((entry) => entry.name)
15
+ .sort();
16
+ };
17
+ /**
18
+ * The installed components dolan tracks: on disk and in the lockfile. `add`
19
+ * records every component it copies, and `eject` removes the record to hand
20
+ * the component over to the app, so a folder without one is the app's own
21
+ * code. `update`, `list`, `diff` and `outdated` leave it alone: before, they
22
+ * scanned the folders, so an ejected component showed as a conflict,
23
+ * `update --force` overwrote it and `update` tracked it again.
24
+ */
25
+ export const trackedComponents = (componentsDir, lockfile) => componentsOnDisk(componentsDir).filter((name) => lockfile.components[name]);
26
+ /** The components on disk that dolan doesn't track (see trackedComponents). */
27
+ export const untrackedComponents = (componentsDir, lockfile) => componentsOnDisk(componentsDir).filter((name) => !lockfile.components[name]);
28
+ /**
29
+ * The files dolan tracks for a component that upstream no longer ships, such
30
+ * as the `*-render.test.ts` files that 22.2.3 stopped copying. `update` and
31
+ * `add` used to keep their lockfile entries and leave them on disk, where a
32
+ * stale spec importing a helper dolan doesn't copy broke the app's `ng test`.
33
+ *
34
+ * Shipped means shipped with tests: a project without the testing library
35
+ * doesn't get the components' `<name>.test.ts`, but upstream still ships it,
36
+ * so a copy from before dolan checked for the library isn't deleted here
37
+ * (`doctor` warns about those instead).
38
+ */
39
+ export const droppedFiles = (name, lockfile) => {
40
+ const shipped = new Set(getComponentFiles(name, { tests: true }));
41
+ return Object.keys(lockfile.components[name] ?? {}).filter((file) => !shipped.has(file));
42
+ };
43
+ //# sourceMappingURL=installed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed.js","sourceRoot":"","sources":["../../src/utils/installed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,aAAqB,EAAY,EAAE;IAClE,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC3C,OAAO,WAAW,CAAC,aAAa,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACvD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAC/D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,aAAqB,EACrB,QAAkB,EACR,EAAE,CACZ,gBAAgB,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAE9E,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,aAAqB,EACrB,QAAkB,EACR,EAAE,CACZ,gBAAgB,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,QAAkB,EAAY,EAAE;IACzE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CACxD,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAC7B,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { createEmptyLockfile } from '../lockfile';
6
+ import { componentsOnDisk, droppedFiles, trackedComponents, untrackedComponents, } from './installed';
7
+ let root;
8
+ const componentsDir = (...folders) => {
9
+ root = mkdtempSync(join(tmpdir(), 'dolan-installed-'));
10
+ for (const folder of folders)
11
+ mkdirSync(join(root, folder));
12
+ // A file isn't a component, whatever its name.
13
+ writeFileSync(join(root, 'badge'), '');
14
+ return root;
15
+ };
16
+ afterEach(() => {
17
+ if (root)
18
+ rmSync(root, { recursive: true, force: true });
19
+ });
20
+ describe('componentsOnDisk', () => {
21
+ it('lists the registry components with a folder, sorted', () => {
22
+ const dir = componentsDir('spinner', 'card', 'my-own-thing');
23
+ expect(componentsOnDisk(dir)).toEqual(['card', 'spinner']);
24
+ });
25
+ it('is empty when the directory is missing', () => {
26
+ expect(componentsOnDisk(join(tmpdir(), 'dolan-missing-dir'))).toEqual([]);
27
+ });
28
+ });
29
+ describe('trackedComponents / untrackedComponents', () => {
30
+ it('splits the components on disk by their lockfile entry', () => {
31
+ const dir = componentsDir('card', 'spinner', 'button');
32
+ const lockfile = createEmptyLockfile();
33
+ lockfile.components['card'] = {};
34
+ lockfile.components['button'] = {};
35
+ // In the lockfile but not on disk: removed by hand, so neither.
36
+ lockfile.components['dialog'] = {};
37
+ expect(trackedComponents(dir, lockfile)).toEqual(['button', 'card']);
38
+ expect(untrackedComponents(dir, lockfile)).toEqual(['spinner']);
39
+ });
40
+ });
41
+ // Reads the real registry source that the test config copies into dist/ui.
42
+ describe('droppedFiles', () => {
43
+ it("lists the tracked files that upstream doesn't ship", () => {
44
+ const lockfile = createEmptyLockfile();
45
+ lockfile.components['button'] = {
46
+ 'button.ts': { hash: 'a' },
47
+ 'button-old.ts': { hash: 'b' },
48
+ // Shipped, though only a project with the testing library gets it.
49
+ 'button.test.ts': { hash: 'c' },
50
+ };
51
+ expect(droppedFiles('button', lockfile)).toEqual(['button-old.ts']);
52
+ });
53
+ it('is empty for a component the lockfile has no entry for', () => {
54
+ expect(droppedFiles('button', createEmptyLockfile())).toEqual([]);
55
+ });
56
+ });
57
+ //# sourceMappingURL=installed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed.test.js","sourceRoot":"","sources":["../../src/utils/installed.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Whether anyone can answer a question: stdin is a terminal. In CI, a script
3
+ * or an AI agent it isn't, and clack's prompts wait for input that never
4
+ * comes. The commands used to hang there until stdin closed, then exit 0
5
+ * having done nothing. Without a terminal, each command asks nothing and takes
6
+ * each question's default instead, or exits 1 and names the option to pass
7
+ * when that default would cancel the run.
8
+ */
9
+ export declare const isInteractive: () => boolean;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Whether anyone can answer a question: stdin is a terminal. In CI, a script
3
+ * or an AI agent it isn't, and clack's prompts wait for input that never
4
+ * comes. The commands used to hang there until stdin closed, then exit 0
5
+ * having done nothing. Without a terminal, each command asks nothing and takes
6
+ * each question's default instead, or exits 1 and names the option to pass
7
+ * when that default would cancel the run.
8
+ */
9
+ export const isInteractive = () => process.stdin.isTTY === true;
10
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/utils/interactive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import { isInteractive } from './interactive';
3
+ const isTTY = Object.getOwnPropertyDescriptor(process.stdin, 'isTTY');
4
+ const setIsTTY = (value) => Object.defineProperty(process.stdin, 'isTTY', { value, configurable: true });
5
+ afterEach(() => {
6
+ if (isTTY)
7
+ Object.defineProperty(process.stdin, 'isTTY', isTTY);
8
+ else
9
+ delete process.stdin.isTTY;
10
+ });
11
+ describe('isInteractive', () => {
12
+ it('is true when stdin is a terminal', () => {
13
+ setIsTTY(true);
14
+ expect(isInteractive()).toBe(true);
15
+ });
16
+ it('is false when stdin is a pipe or a file', () => {
17
+ // Node leaves `isTTY` undefined on anything but a terminal.
18
+ setIsTTY(undefined);
19
+ expect(isInteractive()).toBe(false);
20
+ setIsTTY(false);
21
+ expect(isInteractive()).toBe(false);
22
+ });
23
+ });
24
+ //# sourceMappingURL=interactive.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.test.js","sourceRoot":"","sources":["../../src/utils/interactive.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,KAAK,GAAG,MAAM,CAAC,wBAAwB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACtE,MAAM,QAAQ,GAAG,CAAC,KAA0B,EAAE,EAAE,CAC9C,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AAE/E,SAAS,CAAC,GAAG,EAAE;IACb,IAAI,KAAK;QAAE,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;;QAC3D,OAAQ,OAAO,CAAC,KAA6B,CAAC,KAAK,CAAC;AAC3D,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,4DAA4D;QAC5D,QAAQ,CAAC,SAAS,CAAC,CAAC;QACpB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}