@timbal-ai/timbal-react 0.6.1 → 0.7.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 (47) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +35 -5
  3. package/dist/app.cjs +2291 -741
  4. package/dist/app.d.cts +5 -2
  5. package/dist/app.d.ts +5 -2
  6. package/dist/app.esm.js +58 -5
  7. package/dist/button-CIKzUrJI.d.cts +18 -0
  8. package/dist/button-CIKzUrJI.d.ts +18 -0
  9. package/dist/chart-artifact-C2m891nx.d.cts +756 -0
  10. package/dist/chart-artifact-CqqhdSR9.d.ts +756 -0
  11. package/dist/{chat-CWtQWDtJ.d.cts → chat-Bed4FQSl.d.cts} +10 -0
  12. package/dist/{chat-CWtQWDtJ.d.ts → chat-Bed4FQSl.d.ts} +10 -0
  13. package/dist/chat.cjs +876 -562
  14. package/dist/chat.d.cts +3 -3
  15. package/dist/chat.d.ts +3 -3
  16. package/dist/chat.esm.js +3 -3
  17. package/dist/{chunk-4TCJQSIX.esm.js → chunk-2XZ3S4OP.esm.js} +14 -3
  18. package/dist/{chunk-WLTW56MC.esm.js → chunk-3WCG6ZRL.esm.js} +2 -2
  19. package/dist/chunk-7U2N6XZA.esm.js +2296 -0
  20. package/dist/{chunk-OVHR7J3J.esm.js → chunk-EQC5JEDZ.esm.js} +38 -11
  21. package/dist/{chunk-YJQLLFKP.esm.js → chunk-RY3LB3JN.esm.js} +817 -507
  22. package/dist/{chunk-IYENDIRY.esm.js → chunk-TDIJHV4I.esm.js} +1 -1
  23. package/dist/{chunk-OFHLFNJH.esm.js → chunk-Z27GBSOT.esm.js} +3 -1
  24. package/dist/index.cjs +2596 -1019
  25. package/dist/index.d.cts +8 -7
  26. package/dist/index.d.ts +8 -7
  27. package/dist/index.esm.js +57 -7
  28. package/dist/{layout-CQWngNQ7.d.ts → layout-BTJyU8wd.d.ts} +1 -1
  29. package/dist/{layout-B9VayJhZ.d.cts → layout-C2G-FcER.d.cts} +1 -1
  30. package/dist/studio.cjs +1131 -788
  31. package/dist/studio.d.cts +2 -2
  32. package/dist/studio.d.ts +2 -2
  33. package/dist/studio.esm.js +6 -6
  34. package/dist/styles.css +8 -4
  35. package/dist/{timbal-v2-button-F4-z7m33.d.ts → timbal-v2-button-CNfdwGq4.d.cts} +1 -1
  36. package/dist/{timbal-v2-button-F4-z7m33.d.cts → timbal-v2-button-CNfdwGq4.d.ts} +1 -1
  37. package/dist/ui.cjs +12 -3
  38. package/dist/ui.d.cts +5 -16
  39. package/dist/ui.d.ts +5 -16
  40. package/dist/ui.esm.js +2 -2
  41. package/dist/{welcome--80i_O0p.d.cts → welcome-COOb05a5.d.cts} +5 -4
  42. package/dist/{welcome-BOizSp5h.d.ts → welcome-DE08m9ca.d.ts} +5 -4
  43. package/package.json +2 -1
  44. package/vite/local-dev.mjs +45 -3
  45. package/dist/chart-artifact-C71dk4xI.d.ts +0 -329
  46. package/dist/chart-artifact-CPEpOmtV.d.cts +0 -329
  47. package/dist/chunk-M4V6Q6XO.esm.js +0 -1082
package/dist/studio.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- export { M as ModeToggle, a as ModeToggleProps, b as ModeToggleTheme, S as STUDIO_NAV_MODE, c as StudioModeSwitch, d as StudioModeSwitchProps, e as StudioNavMode, f as StudioSidebar, g as StudioSidebarProps, h as StudioWelcome, i as StudioWelcomeProps, T as TimbalChatShell, j as TimbalChatShellProps, k as TimbalMark, l as TimbalMarkProps, m as TimbalStudioShell, n as TimbalStudioShellProps } from './welcome--80i_O0p.cjs';
1
+ export { M as ModeToggle, a as ModeToggleProps, b as ModeToggleTheme, S as STUDIO_NAV_MODE, c as StudioModeSwitch, d as StudioModeSwitchProps, e as StudioNavMode, f as StudioSidebar, g as StudioSidebarProps, h as StudioWelcome, i as StudioWelcomeProps, T as TimbalChatShell, j as TimbalChatShellProps, k as TimbalMark, l as TimbalMarkProps, m as TimbalStudioShell, n as TimbalStudioShellProps } from './welcome-COOb05a5.cjs';
2
2
  import { FC } from 'react';
3
- import './chat-CWtQWDtJ.cjs';
3
+ import './chat-Bed4FQSl.cjs';
4
4
  import 'react/jsx-runtime';
5
5
  import '@assistant-ui/react';
6
6
  import '@timbal-ai/timbal-sdk';
package/dist/studio.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { M as ModeToggle, a as ModeToggleProps, b as ModeToggleTheme, S as STUDIO_NAV_MODE, c as StudioModeSwitch, d as StudioModeSwitchProps, e as StudioNavMode, f as StudioSidebar, g as StudioSidebarProps, h as StudioWelcome, i as StudioWelcomeProps, T as TimbalChatShell, j as TimbalChatShellProps, k as TimbalMark, l as TimbalMarkProps, m as TimbalStudioShell, n as TimbalStudioShellProps } from './welcome-BOizSp5h.js';
1
+ export { M as ModeToggle, a as ModeToggleProps, b as ModeToggleTheme, S as STUDIO_NAV_MODE, c as StudioModeSwitch, d as StudioModeSwitchProps, e as StudioNavMode, f as StudioSidebar, g as StudioSidebarProps, h as StudioWelcome, i as StudioWelcomeProps, T as TimbalChatShell, j as TimbalChatShellProps, k as TimbalMark, l as TimbalMarkProps, m as TimbalStudioShell, n as TimbalStudioShellProps } from './welcome-DE08m9ca.js';
2
2
  import { FC } from 'react';
3
- import './chat-CWtQWDtJ.js';
3
+ import './chat-Bed4FQSl.js';
4
4
  import 'react/jsx-runtime';
5
5
  import '@assistant-ui/react';
6
6
  import '@timbal-ai/timbal-sdk';
@@ -8,12 +8,12 @@ import {
8
8
  TimbalChatShell,
9
9
  TimbalMark,
10
10
  TimbalStudioShell
11
- } from "./chunk-OVHR7J3J.esm.js";
12
- import "./chunk-OFHLFNJH.esm.js";
13
- import "./chunk-WLTW56MC.esm.js";
14
- import "./chunk-YJQLLFKP.esm.js";
15
- import "./chunk-IYENDIRY.esm.js";
16
- import "./chunk-4TCJQSIX.esm.js";
11
+ } from "./chunk-EQC5JEDZ.esm.js";
12
+ import "./chunk-Z27GBSOT.esm.js";
13
+ import "./chunk-3WCG6ZRL.esm.js";
14
+ import "./chunk-RY3LB3JN.esm.js";
15
+ import "./chunk-TDIJHV4I.esm.js";
16
+ import "./chunk-2XZ3S4OP.esm.js";
17
17
  export {
18
18
  ModeToggle,
19
19
  STUDIO_NAV_MODE,
package/dist/styles.css CHANGED
@@ -58,9 +58,11 @@
58
58
 
59
59
  /* Timbal extension tokens — keep light + dark in sync below */
60
60
 
61
- /* Elevated surface gradient (cards, sidebar panel, secondary chrome). */
61
+ /* Elevated surface gradient (cards, sidebar panel, secondary chrome).
62
+ Opaque stops — keeps the signature vertical gradient with no alpha
63
+ bleed-through, so whatever sits behind the surface never shows through. */
62
64
  --elevated-from: oklch(1 0 0);
63
- --elevated-to: oklch(0.985 0.002 260 / 0.7);
65
+ --elevated-to: oklch(0.985 0.002 260);
64
66
 
65
67
  /* Opaque modal/dialog gradient — same hue as elevated, no alpha bleed-through. */
66
68
  --modal-from: oklch(1 0 0);
@@ -181,8 +183,10 @@
181
183
  --sidebar-border: oklch(1 0 0 / 0.10);
182
184
  --sidebar-ring: oklch(0.55 0.01 260);
183
185
 
184
- --elevated-from: oklch(1 0 0 / 0.05);
185
- --elevated-to: oklch(1 0 0 / 0.025);
186
+ /* Opaque equivalents of the translucent white wash — preserves the elevated
187
+ gradient look while keeping the surface fully opaque (no bleed-through). */
188
+ --elevated-from: oklch(0.205 0.004 260);
189
+ --elevated-to: oklch(0.185 0.004 260);
186
190
 
187
191
  --modal-from: oklch(0.22 0.005 260);
188
192
  --modal-to: oklch(0.19 0.005 260);
@@ -22,7 +22,7 @@ interface TimbalV2ButtonProps extends React.ComponentProps<"button"> {
22
22
  isIconOnly?: boolean;
23
23
  isLoading?: boolean;
24
24
  fullWidth?: boolean;
25
- /** `pill` (default)full rounding; `rect` `rounded-md` for shadcn-style buttons. */
25
+ /** Kept for API compatibility all shapes render fully rounded (`rounded-full`). */
26
26
  shape?: "pill" | "rect";
27
27
  /**
28
28
  * When true, merges props onto the single child element (Radix Slot).
@@ -22,7 +22,7 @@ interface TimbalV2ButtonProps extends React.ComponentProps<"button"> {
22
22
  isIconOnly?: boolean;
23
23
  isLoading?: boolean;
24
24
  fullWidth?: boolean;
25
- /** `pill` (default)full rounding; `rect` `rounded-md` for shadcn-style buttons. */
25
+ /** Kept for API compatibility all shapes render fully rounded (`rounded-full`). */
26
26
  shape?: "pill" | "rect";
27
27
  /**
28
28
  * When true, merges props onto the single child element (Radix Slot).
package/dist/ui.cjs CHANGED
@@ -156,6 +156,10 @@ var TIMBAL_V2_SWITCH_THUMB = cn(
156
156
  TIMBAL_V2_ELEVATED_GRADIENT,
157
157
  "border border-border/80 shadow-sm"
158
158
  );
159
+ var TIMBAL_V2_ELEVATED_SURFACE = cn(
160
+ TIMBAL_V2_ELEVATED_GRADIENT,
161
+ "border border-border shadow-card"
162
+ );
159
163
  var TIMBAL_V2_SECONDARY_CHROME = [
160
164
  TIMBAL_V2_ELEVATED_GRADIENT,
161
165
  "border border-border shadow-card",
@@ -163,6 +167,11 @@ var TIMBAL_V2_SECONDARY_CHROME = [
163
167
  "hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
164
168
  "active:from-secondary-fill-active-from active:to-secondary-fill-active-to"
165
169
  ].join(" ");
170
+ var TIMBAL_V2_LOGO_TILE = cn(
171
+ "bg-gradient-to-b from-white to-neutral-100",
172
+ "border border-neutral-200",
173
+ "shadow-[0_1px_2px_-0.5px_rgba(0,0,0,0.08)]"
174
+ );
166
175
 
167
176
  // src/ui/timbal-v2-button.tsx
168
177
  var React = __toESM(require("react"), 1);
@@ -207,7 +216,7 @@ var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
207
216
  isIconOnly = false,
208
217
  isLoading = false,
209
218
  fullWidth = false,
210
- shape = "pill",
219
+ shape: _shape = "pill",
211
220
  asChild = false,
212
221
  className,
213
222
  disabled,
@@ -217,7 +226,7 @@ var TimbalV2Button = React.forwardRef(function TimbalV2Button2({
217
226
  }, ref) {
218
227
  const isDisabled = disabled || isLoading;
219
228
  const sizeClass = isIconOnly ? TIMBAL_V2_SIZE_ICON[size] : TIMBAL_V2_SIZE_HEIGHT[size];
220
- const radiusClass = variant === "link" || variant === "ghost" ? "rounded-md" : shape === "rect" ? "rounded-md" : "rounded-full";
229
+ const radiusClass = "rounded-full";
221
230
  const sharedRootClass = cn(
222
231
  "relative box-border inline-flex items-center justify-center gap-2 whitespace-nowrap border-0 text-sm font-normal shadow-none transition duration-200 ease-in-out",
223
232
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
@@ -347,7 +356,7 @@ function Button({
347
356
  "data-size": size,
348
357
  variant: v2Variant,
349
358
  size: v2Size,
350
- shape: "rect",
359
+ shape: "pill",
351
360
  isIconOnly,
352
361
  asChild,
353
362
  className: cn(buttonVariants({ variant, size, className })),
package/dist/ui.d.cts CHANGED
@@ -1,22 +1,11 @@
1
+ export { B as Button } from './button-CIKzUrJI.cjs';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as class_variance_authority_types from 'class-variance-authority/types';
3
3
  import * as React from 'react';
4
4
  import { ElementType, ReactNode, FC } from 'react';
5
- import { VariantProps } from 'class-variance-authority';
6
5
  import { Tooltip as Tooltip$1, Avatar as Avatar$1, Dialog as Dialog$1 } from 'radix-ui';
7
- export { a as TimbalV2Button } from './timbal-v2-button-F4-z7m33.cjs';
8
-
9
- /**
10
- * Layout-only variants for consumers that compose `buttonVariants` directly.
11
- * Fill / border / shadow come from `button-tokens` via `TimbalV2Button`.
12
- */
13
- declare const buttonVariants: (props?: ({
14
- variant?: "secondary" | "ghost" | "destructive" | "link" | "default" | "outline" | null | undefined;
15
- size?: "xs" | "sm" | "lg" | "default" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
16
- } & class_variance_authority_types.ClassProp) | undefined) => string;
17
- declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
18
- asChild?: boolean;
19
- }): react_jsx_runtime.JSX.Element;
6
+ export { a as TimbalV2Button } from './timbal-v2-button-CNfdwGq4.cjs';
7
+ import 'class-variance-authority/types';
8
+ import 'class-variance-authority';
20
9
 
21
10
  declare function TooltipProvider({ delayDuration, ...props }: React.ComponentProps<typeof Tooltip$1.Provider>): react_jsx_runtime.JSX.Element;
22
11
  declare function Tooltip({ ...props }: React.ComponentProps<typeof Tooltip$1.Root>): react_jsx_runtime.JSX.Element;
@@ -71,4 +60,4 @@ interface PillSegmentedTabsProps {
71
60
  declare const PillSegmentedTabs: FC<PillSegmentedTabsProps>;
72
61
  declare const MemoPillSegmentedTabs: React.NamedExoticComponent<PillSegmentedTabsProps>;
73
62
 
74
- export { Avatar, AvatarFallback, AvatarImage, Button, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MemoPillSegmentedTabs, type PillSegmentedTab, PillSegmentedTabs, type PillSegmentedTabsProps, Shimmer, type TextShimmerProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
63
+ export { Avatar, AvatarFallback, AvatarImage, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MemoPillSegmentedTabs, type PillSegmentedTab, PillSegmentedTabs, type PillSegmentedTabsProps, Shimmer, type TextShimmerProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
package/dist/ui.d.ts CHANGED
@@ -1,22 +1,11 @@
1
+ export { B as Button } from './button-CIKzUrJI.js';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as class_variance_authority_types from 'class-variance-authority/types';
3
3
  import * as React from 'react';
4
4
  import { ElementType, ReactNode, FC } from 'react';
5
- import { VariantProps } from 'class-variance-authority';
6
5
  import { Tooltip as Tooltip$1, Avatar as Avatar$1, Dialog as Dialog$1 } from 'radix-ui';
7
- export { a as TimbalV2Button } from './timbal-v2-button-F4-z7m33.js';
8
-
9
- /**
10
- * Layout-only variants for consumers that compose `buttonVariants` directly.
11
- * Fill / border / shadow come from `button-tokens` via `TimbalV2Button`.
12
- */
13
- declare const buttonVariants: (props?: ({
14
- variant?: "secondary" | "ghost" | "destructive" | "link" | "default" | "outline" | null | undefined;
15
- size?: "xs" | "sm" | "lg" | "default" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
16
- } & class_variance_authority_types.ClassProp) | undefined) => string;
17
- declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
18
- asChild?: boolean;
19
- }): react_jsx_runtime.JSX.Element;
6
+ export { a as TimbalV2Button } from './timbal-v2-button-CNfdwGq4.js';
7
+ import 'class-variance-authority/types';
8
+ import 'class-variance-authority';
20
9
 
21
10
  declare function TooltipProvider({ delayDuration, ...props }: React.ComponentProps<typeof Tooltip$1.Provider>): react_jsx_runtime.JSX.Element;
22
11
  declare function Tooltip({ ...props }: React.ComponentProps<typeof Tooltip$1.Root>): react_jsx_runtime.JSX.Element;
@@ -71,4 +60,4 @@ interface PillSegmentedTabsProps {
71
60
  declare const PillSegmentedTabs: FC<PillSegmentedTabsProps>;
72
61
  declare const MemoPillSegmentedTabs: React.NamedExoticComponent<PillSegmentedTabsProps>;
73
62
 
74
- export { Avatar, AvatarFallback, AvatarImage, Button, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MemoPillSegmentedTabs, type PillSegmentedTab, PillSegmentedTabs, type PillSegmentedTabsProps, Shimmer, type TextShimmerProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
63
+ export { Avatar, AvatarFallback, AvatarImage, Dialog, DialogClose, DialogContent, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, MemoPillSegmentedTabs, type PillSegmentedTab, PillSegmentedTabs, type PillSegmentedTabsProps, Shimmer, type TextShimmerProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
package/dist/ui.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MemoPillSegmentedTabs,
3
3
  PillSegmentedTabs
4
- } from "./chunk-IYENDIRY.esm.js";
4
+ } from "./chunk-TDIJHV4I.esm.js";
5
5
  import {
6
6
  Avatar,
7
7
  AvatarFallback,
@@ -20,7 +20,7 @@ import {
20
20
  TooltipContent,
21
21
  TooltipProvider,
22
22
  TooltipTrigger
23
- } from "./chunk-4TCJQSIX.esm.js";
23
+ } from "./chunk-2XZ3S4OP.esm.js";
24
24
  export {
25
25
  Avatar,
26
26
  AvatarFallback,
@@ -1,5 +1,5 @@
1
1
  import { FC, ReactNode } from 'react';
2
- import { b as TimbalChatProps, u as ThreadWelcomeProps } from './chat-CWtQWDtJ.cjs';
2
+ import { b as TimbalChatProps, u as ThreadWelcomeProps } from './chat-Bed4FQSl.cjs';
3
3
  import { WorkforceItem } from '@timbal-ai/timbal-sdk';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
 
@@ -151,9 +151,10 @@ interface ModeToggleProps {
151
151
  *
152
152
  * 1. Pass `theme` + `setTheme` (e.g. from `next-themes`'s `useTheme`).
153
153
  * The component is then fully controlled.
154
- * 2. Omit both. The toggle reads the current state from `.dark` on
155
- * `<html>` and flips it on click. Good enough for prototypes and
156
- * cases where there is no theme manager.
154
+ * 2. Omit both. The toggle reads/writes `.dark` on `<html>` and persists
155
+ * the choice to `localStorage` under `STORAGE_KEYS.theme`. For SSR or
156
+ * zero flash on first paint, mirror that key in a blocking `<script>` in
157
+ * `index.html` before your bundle loads.
157
158
  */
158
159
  declare const ModeToggle: FC<ModeToggleProps>;
159
160
 
@@ -1,5 +1,5 @@
1
1
  import { FC, ReactNode } from 'react';
2
- import { b as TimbalChatProps, u as ThreadWelcomeProps } from './chat-CWtQWDtJ.js';
2
+ import { b as TimbalChatProps, u as ThreadWelcomeProps } from './chat-Bed4FQSl.js';
3
3
  import { WorkforceItem } from '@timbal-ai/timbal-sdk';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
 
@@ -151,9 +151,10 @@ interface ModeToggleProps {
151
151
  *
152
152
  * 1. Pass `theme` + `setTheme` (e.g. from `next-themes`'s `useTheme`).
153
153
  * The component is then fully controlled.
154
- * 2. Omit both. The toggle reads the current state from `.dark` on
155
- * `<html>` and flips it on click. Good enough for prototypes and
156
- * cases where there is no theme manager.
154
+ * 2. Omit both. The toggle reads/writes `.dark` on `<html>` and persists
155
+ * the choice to `localStorage` under `STORAGE_KEYS.theme`. For SSR or
156
+ * zero flash on first paint, mirror that key in a blocking `<script>` in
157
+ * `index.html` before your bundle loads.
157
158
  */
158
159
  declare const ModeToggle: FC<ModeToggleProps>;
159
160
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timbal-ai/timbal-react",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "React components and runtime for building Timbal chat and studio apps",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -43,6 +43,7 @@
43
43
  "vite",
44
44
  "scripts/dev-linked.mjs",
45
45
  "README.md",
46
+ "CHANGELOG.md",
46
47
  "LICENSE"
47
48
  ],
48
49
  "scripts": {
@@ -23,6 +23,24 @@ const TIMBAL_REACT_EXPORTS = [
23
23
  "@timbal-ai/timbal-react/app",
24
24
  ];
25
25
 
26
+ /** Subpath → source entry (used when `dist/*.esm.js` is missing). */
27
+ const SOURCE_ENTRIES = {
28
+ "@timbal-ai/timbal-react": "src/index.ts",
29
+ "@timbal-ai/timbal-react/chat": "src/chat.ts",
30
+ "@timbal-ai/timbal-react/studio": "src/studio.ts",
31
+ "@timbal-ai/timbal-react/ui": "src/ui.ts",
32
+ "@timbal-ai/timbal-react/app": "src/app.ts",
33
+ "@timbal-ai/timbal-react/styles.css": "src/styles.css",
34
+ };
35
+
36
+ function distIsBuilt(distDir) {
37
+ try {
38
+ return fs.statSync(path.join(distDir, "index.esm.js")).isFile();
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+
26
44
  /**
27
45
  * CJS-only transitive deps that must be pre-bundled even when the package itself
28
46
  * is excluded, so their `useSyncExternalStore` named imports resolve as ESM.
@@ -82,22 +100,46 @@ export function timbalReactLocalDev() {
82
100
  if (!pkgRoot) return {};
83
101
 
84
102
  distDir = path.join(pkgRoot, "dist");
85
- const distGlob = `${distDir.replace(/\\/g, "/")}/**`;
103
+ const built = distIsBuilt(distDir);
104
+ const srcDir = path.join(pkgRoot, "src");
105
+ const watchGlob = built
106
+ ? `${distDir.replace(/\\/g, "/")}/**`
107
+ : `${srcDir.replace(/\\/g, "/")}/**`;
108
+
109
+ if (!built) {
110
+ console.warn(
111
+ "[timbal-react] dist/ is missing (404 on *.esm.js) — aliasing to src/. " +
112
+ "Run `bun run build` in timbal-react for production-like dev, or `bun run example:app` from the repo root.",
113
+ );
114
+ }
115
+
116
+ /** @type {Record<string, string>} */
117
+ const alias = {};
118
+ if (!built) {
119
+ for (const [pkg, rel] of Object.entries(SOURCE_ENTRIES)) {
120
+ alias[pkg] = path.join(pkgRoot, rel);
121
+ }
122
+ }
86
123
 
87
124
  return {
125
+ resolve: Object.keys(alias).length ? { alias } : undefined,
88
126
  optimizeDeps: {
89
127
  exclude: TIMBAL_REACT_EXPORTS,
90
128
  include: CJS_INTEROP_DEPS,
91
129
  },
92
130
  server: {
93
131
  watch: {
94
- ignored: ["**/.git/**", "**/node_modules/**", `!${distGlob}`],
132
+ ignored: ["**/.git/**", "**/node_modules/**", `!${watchGlob}`],
95
133
  },
96
134
  },
97
135
  };
98
136
  },
99
137
  handleHotUpdate({ file, server }) {
100
- if (!distDir || !file.startsWith(distDir)) return;
138
+ if (!distDir) return;
139
+ const srcDir = path.join(path.dirname(distDir), "src");
140
+ const isDist = file.startsWith(distDir);
141
+ const isSrc = file.startsWith(srcDir);
142
+ if (!isDist && !isSrc) return;
101
143
 
102
144
  for (const mod of server.moduleGraph.idToModuleMap.values()) {
103
145
  if (