@btst/stack 4.0.0 → 4.1.0

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 (92) hide show
  1. package/README.md +2 -2
  2. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +112 -103
  3. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +112 -103
  4. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +5 -2
  5. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +5 -2
  6. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +99 -88
  7. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +99 -88
  8. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.cjs +12 -3
  9. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-message.mjs +12 -3
  10. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +6 -2
  11. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +6 -2
  12. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.cjs +3 -2
  13. package/dist/packages/stack/src/plugins/blog/client/components/shared/page-wrapper.mjs +3 -2
  14. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.cjs +81 -52
  15. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-card.mjs +82 -53
  16. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.cjs +3 -2
  17. package/dist/packages/stack/src/plugins/blog/client/components/shared/posts-list.mjs +3 -2
  18. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.cjs +95 -75
  19. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-list-page.internal.mjs +95 -75
  20. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.cjs +16 -3
  21. package/dist/packages/stack/src/plugins/cms/client/components/pages/dashboard-page.internal.mjs +16 -3
  22. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.cjs +3 -2
  23. package/dist/packages/stack/src/plugins/cms/client/components/shared/page-wrapper.mjs +3 -2
  24. package/dist/packages/stack/src/plugins/cms/utils.cjs +6 -2
  25. package/dist/packages/stack/src/plugins/cms/utils.mjs +6 -3
  26. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.cjs +14 -8
  27. package/dist/packages/stack/src/plugins/form-builder/client/components/forms/form-renderer.mjs +14 -8
  28. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.cjs +94 -87
  29. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.mjs +94 -87
  30. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +81 -74
  31. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +81 -74
  32. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.cjs +3 -2
  33. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/page-wrapper.mjs +3 -2
  34. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/pagination.cjs +25 -16
  35. package/dist/packages/stack/src/plugins/form-builder/client/components/shared/pagination.mjs +25 -16
  36. package/dist/packages/stack/src/plugins/form-builder/utils.cjs +6 -2
  37. package/dist/packages/stack/src/plugins/form-builder/utils.mjs +6 -3
  38. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  39. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  40. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  41. package/dist/plugins/ai-chat/client/index.d.cts +2 -2
  42. package/dist/plugins/ai-chat/client/index.d.mts +2 -2
  43. package/dist/plugins/ai-chat/client/index.d.ts +2 -2
  44. package/dist/plugins/blog/client/index.d.cts +18 -0
  45. package/dist/plugins/blog/client/index.d.mts +18 -0
  46. package/dist/plugins/blog/client/index.d.ts +18 -0
  47. package/dist/plugins/cms/client/index.d.cts +18 -0
  48. package/dist/plugins/cms/client/index.d.mts +18 -0
  49. package/dist/plugins/cms/client/index.d.ts +18 -0
  50. package/dist/plugins/form-builder/api/index.d.cts +1 -1
  51. package/dist/plugins/form-builder/api/index.d.mts +1 -1
  52. package/dist/plugins/form-builder/api/index.d.ts +1 -1
  53. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  54. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  55. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  56. package/dist/plugins/form-builder/client/index.d.cts +16 -0
  57. package/dist/plugins/form-builder/client/index.d.mts +16 -0
  58. package/dist/plugins/form-builder/client/index.d.ts +16 -0
  59. package/dist/plugins/form-builder/query-keys.d.cts +1 -1
  60. package/dist/plugins/form-builder/query-keys.d.mts +1 -1
  61. package/dist/plugins/form-builder/query-keys.d.ts +1 -1
  62. package/dist/shared/{stack.5_zzCejP.d.cts → stack.rVF0f509.d.cts} +20 -0
  63. package/dist/shared/{stack.5_zzCejP.d.mts → stack.rVF0f509.d.mts} +20 -0
  64. package/dist/shared/{stack.5_zzCejP.d.ts → stack.rVF0f509.d.ts} +20 -0
  65. package/package.json +1 -1
  66. package/src/plugins/ai-chat/__tests__/classnames-overrides.test.tsx +248 -0
  67. package/src/plugins/ai-chat/client/components/chat-input.tsx +6 -1
  68. package/src/plugins/ai-chat/client/components/chat-interface.tsx +3 -0
  69. package/src/plugins/ai-chat/client/components/chat-layout.tsx +9 -2
  70. package/src/plugins/ai-chat/client/components/chat-message.tsx +13 -5
  71. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +6 -2
  72. package/src/plugins/ai-chat/client/overrides.ts +21 -0
  73. package/src/plugins/blog/__tests__/classnames-overrides.test.tsx +206 -0
  74. package/src/plugins/blog/client/components/shared/page-wrapper.tsx +3 -2
  75. package/src/plugins/blog/client/components/shared/post-card.tsx +32 -12
  76. package/src/plugins/blog/client/components/shared/posts-list.tsx +3 -2
  77. package/src/plugins/blog/client/overrides.ts +18 -0
  78. package/src/plugins/cms/__tests__/classnames-overrides.test.tsx +200 -0
  79. package/src/plugins/cms/client/components/pages/content-list-page.internal.tsx +17 -4
  80. package/src/plugins/cms/client/components/pages/dashboard-page.internal.tsx +14 -3
  81. package/src/plugins/cms/client/components/shared/page-wrapper.tsx +3 -2
  82. package/src/plugins/cms/client/overrides.ts +19 -0
  83. package/src/plugins/form-builder/__tests__/classnames-overrides.test.tsx +312 -0
  84. package/src/plugins/form-builder/client/components/forms/form-renderer.tsx +14 -9
  85. package/src/plugins/form-builder/client/components/pages/form-list-page.internal.tsx +9 -5
  86. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +9 -5
  87. package/src/plugins/form-builder/client/components/shared/page-wrapper.tsx +3 -2
  88. package/src/plugins/form-builder/client/components/shared/pagination.tsx +7 -1
  89. package/src/plugins/form-builder/client/overrides.ts +17 -0
  90. package/dist/shared/{stack.BuxUQqL8.d.ts → stack.CGmh-Lpe.d.ts} +12 -12
  91. package/dist/shared/{stack.Egr3RWhA.d.mts → stack.Doy2_wgl.d.mts} +12 -12
  92. package/dist/shared/{stack.CX83YNuS.d.cts → stack.zch70Loj.d.cts} +12 -12
@@ -25,7 +25,7 @@ function ChatLayout(props) {
25
25
  onMessagesChange,
26
26
  onClear
27
27
  } = props;
28
- const { localization } = context.usePluginOverrides("aiChat", {});
28
+ const { localization, classNames } = context.usePluginOverrides("aiChat", {});
29
29
  const { plugins } = context.useStack();
30
30
  const resolvedMode = overrides.resolveAiChatMode(plugins?.aiChat?.config);
31
31
  const showSidebar = requestedShowSidebar && resolvedMode !== "public";
@@ -47,102 +47,113 @@ function ChatLayout(props) {
47
47
  }
48
48
  }, [conversationId]);
49
49
  if (layout === "widget") {
50
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex flex-col items-end gap-3", className), children: [
51
- /* @__PURE__ */ jsxRuntime.jsxs(
52
- "div",
53
- {
54
- className: utils.cn(
55
- "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
56
- widgetOpen ? "flex" : "hidden"
57
- ),
58
- style: { height: widgetHeight, width: widgetWidth },
59
- children: [
60
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
61
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
62
- pageAIContext ? /* @__PURE__ */ jsxRuntime.jsx(
63
- badge.Badge,
64
- {
65
- variant: "secondary",
66
- className: "text-xs",
67
- "data-testid": "page-context-badge",
68
- children: pageAIContext.routeName
69
- }
70
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground font-medium", children: tr("A11Y_CHAT_TITLE", "aiChat.a11y.title", "AI Chat") }),
71
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
72
- /* @__PURE__ */ jsxRuntime.jsx(
73
- button.Button,
74
- {
75
- variant: "ghost",
76
- size: "icon",
77
- className: "h-5 w-5",
78
- onClick: () => {
79
- onClear?.();
80
- setWidgetResetKey((prev) => prev + 1);
81
- },
82
- "aria-label": tr(
83
- "A11Y_CLEAR_CHAT",
84
- "aiChat.a11y.clearChat",
85
- "Clear chat"
86
- ),
87
- title: tr(
88
- "A11Y_CLEAR_CHAT",
89
- "aiChat.a11y.clearChat",
90
- "Clear chat"
91
- ),
92
- children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Trash2, { className: "h-3.5 w-3.5" })
93
- }
50
+ return /* @__PURE__ */ jsxRuntime.jsxs(
51
+ "div",
52
+ {
53
+ className: utils.cn(
54
+ "flex flex-col items-end gap-3",
55
+ className,
56
+ classNames?.container
57
+ ),
58
+ children: [
59
+ /* @__PURE__ */ jsxRuntime.jsxs(
60
+ "div",
61
+ {
62
+ className: utils.cn(
63
+ "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
64
+ widgetOpen ? "flex" : "hidden"
94
65
  ),
95
- /* @__PURE__ */ jsxRuntime.jsx(
96
- button.Button,
97
- {
98
- variant: "ghost",
99
- size: "icon",
100
- className: "h-5 w-5",
101
- onClick: () => setWidgetOpen(false),
102
- "aria-label": tr(
103
- "A11Y_CLOSE_CHAT",
104
- "aiChat.a11y.closeChat",
105
- "Close chat"
66
+ style: { height: widgetHeight, width: widgetWidth },
67
+ children: [
68
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
69
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
70
+ pageAIContext ? /* @__PURE__ */ jsxRuntime.jsx(
71
+ badge.Badge,
72
+ {
73
+ variant: "secondary",
74
+ className: "text-xs",
75
+ "data-testid": "page-context-badge",
76
+ children: pageAIContext.routeName
77
+ }
78
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground font-medium", children: tr("A11Y_CHAT_TITLE", "aiChat.a11y.title", "AI Chat") }),
79
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
80
+ /* @__PURE__ */ jsxRuntime.jsx(
81
+ button.Button,
82
+ {
83
+ variant: "ghost",
84
+ size: "icon",
85
+ className: "h-5 w-5",
86
+ onClick: () => {
87
+ onClear?.();
88
+ setWidgetResetKey((prev) => prev + 1);
89
+ },
90
+ "aria-label": tr(
91
+ "A11Y_CLEAR_CHAT",
92
+ "aiChat.a11y.clearChat",
93
+ "Clear chat"
94
+ ),
95
+ title: tr(
96
+ "A11Y_CLEAR_CHAT",
97
+ "aiChat.a11y.clearChat",
98
+ "Clear chat"
99
+ ),
100
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Trash2, { className: "h-3.5 w-3.5" })
101
+ }
106
102
  ),
107
- children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-3.5 w-3.5" })
108
- }
109
- )
110
- ] }),
111
- widgetEverOpened && /* @__PURE__ */ jsxRuntime.jsx(
112
- chatInterface.ChatInterface,
113
- {
114
- id: conversationId,
115
- variant: "widget",
116
- initialMessages,
117
- onMessagesChange
103
+ /* @__PURE__ */ jsxRuntime.jsx(
104
+ button.Button,
105
+ {
106
+ variant: "ghost",
107
+ size: "icon",
108
+ className: "h-5 w-5",
109
+ onClick: () => setWidgetOpen(false),
110
+ "aria-label": tr(
111
+ "A11Y_CLOSE_CHAT",
112
+ "aiChat.a11y.closeChat",
113
+ "Close chat"
114
+ ),
115
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-3.5 w-3.5" })
116
+ }
117
+ )
118
+ ] }),
119
+ widgetEverOpened && /* @__PURE__ */ jsxRuntime.jsx(
120
+ chatInterface.ChatInterface,
121
+ {
122
+ id: conversationId,
123
+ variant: "widget",
124
+ initialMessages,
125
+ onMessagesChange
126
+ },
127
+ `widget-${conversationId ?? "new"}-${widgetResetKey}`
128
+ )
129
+ ]
130
+ }
131
+ ),
132
+ showTrigger && /* @__PURE__ */ jsxRuntime.jsx(
133
+ button.Button,
134
+ {
135
+ size: "icon",
136
+ className: "h-12 w-12 rounded-full shadow-lg",
137
+ onClick: () => {
138
+ setWidgetOpen((prev) => !prev);
139
+ setWidgetEverOpened(true);
118
140
  },
119
- `widget-${conversationId ?? "new"}-${widgetResetKey}`
120
- )
121
- ]
122
- }
123
- ),
124
- showTrigger && /* @__PURE__ */ jsxRuntime.jsx(
125
- button.Button,
126
- {
127
- size: "icon",
128
- className: "h-12 w-12 rounded-full shadow-lg",
129
- onClick: () => {
130
- setWidgetOpen((prev) => !prev);
131
- setWidgetEverOpened(true);
132
- },
133
- "aria-label": widgetOpen ? tr("A11Y_CLOSE_CHAT", "aiChat.a11y.closeChat", "Close chat") : tr("A11Y_OPEN_CHAT", "aiChat.a11y.openChat", "Open chat"),
134
- "data-testid": "widget-trigger",
135
- children: widgetOpen ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-5 w-5" })
136
- }
137
- )
138
- ] });
141
+ "aria-label": widgetOpen ? tr("A11Y_CLOSE_CHAT", "aiChat.a11y.closeChat", "Close chat") : tr("A11Y_OPEN_CHAT", "aiChat.a11y.openChat", "Open chat"),
142
+ "data-testid": "widget-trigger",
143
+ children: widgetOpen ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-5 w-5" })
144
+ }
145
+ )
146
+ ]
147
+ }
148
+ );
139
149
  }
140
150
  return /* @__PURE__ */ jsxRuntime.jsxs(
141
151
  "div",
142
152
  {
143
153
  className: utils.cn(
144
154
  "flex h-[calc(100vh-4rem)] w-full overflow-hidden",
145
- className
155
+ className,
156
+ classNames?.container
146
157
  ),
147
158
  "data-testid": "chat-layout",
148
159
  children: [
@@ -23,7 +23,7 @@ function ChatLayout(props) {
23
23
  onMessagesChange,
24
24
  onClear
25
25
  } = props;
26
- const { localization } = usePluginOverrides("aiChat", {});
26
+ const { localization, classNames } = usePluginOverrides("aiChat", {});
27
27
  const { plugins } = useStack();
28
28
  const resolvedMode = resolveAiChatMode(plugins?.aiChat?.config);
29
29
  const showSidebar = requestedShowSidebar && resolvedMode !== "public";
@@ -45,102 +45,113 @@ function ChatLayout(props) {
45
45
  }
46
46
  }, [conversationId]);
47
47
  if (layout === "widget") {
48
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-end gap-3", className), children: [
49
- /* @__PURE__ */ jsxs(
50
- "div",
51
- {
52
- className: cn(
53
- "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
54
- widgetOpen ? "flex" : "hidden"
55
- ),
56
- style: { height: widgetHeight, width: widgetWidth },
57
- children: [
58
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
59
- /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
60
- pageAIContext ? /* @__PURE__ */ jsx(
61
- Badge,
62
- {
63
- variant: "secondary",
64
- className: "text-xs",
65
- "data-testid": "page-context-badge",
66
- children: pageAIContext.routeName
67
- }
68
- ) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-medium", children: tr("A11Y_CHAT_TITLE", "aiChat.a11y.title", "AI Chat") }),
69
- /* @__PURE__ */ jsx("div", { className: "flex-1" }),
70
- /* @__PURE__ */ jsx(
71
- Button,
72
- {
73
- variant: "ghost",
74
- size: "icon",
75
- className: "h-5 w-5",
76
- onClick: () => {
77
- onClear?.();
78
- setWidgetResetKey((prev) => prev + 1);
79
- },
80
- "aria-label": tr(
81
- "A11Y_CLEAR_CHAT",
82
- "aiChat.a11y.clearChat",
83
- "Clear chat"
84
- ),
85
- title: tr(
86
- "A11Y_CLEAR_CHAT",
87
- "aiChat.a11y.clearChat",
88
- "Clear chat"
89
- ),
90
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
91
- }
48
+ return /* @__PURE__ */ jsxs(
49
+ "div",
50
+ {
51
+ className: cn(
52
+ "flex flex-col items-end gap-3",
53
+ className,
54
+ classNames?.container
55
+ ),
56
+ children: [
57
+ /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ className: cn(
61
+ "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
62
+ widgetOpen ? "flex" : "hidden"
92
63
  ),
93
- /* @__PURE__ */ jsx(
94
- Button,
95
- {
96
- variant: "ghost",
97
- size: "icon",
98
- className: "h-5 w-5",
99
- onClick: () => setWidgetOpen(false),
100
- "aria-label": tr(
101
- "A11Y_CLOSE_CHAT",
102
- "aiChat.a11y.closeChat",
103
- "Close chat"
64
+ style: { height: widgetHeight, width: widgetWidth },
65
+ children: [
66
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
67
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
68
+ pageAIContext ? /* @__PURE__ */ jsx(
69
+ Badge,
70
+ {
71
+ variant: "secondary",
72
+ className: "text-xs",
73
+ "data-testid": "page-context-badge",
74
+ children: pageAIContext.routeName
75
+ }
76
+ ) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-medium", children: tr("A11Y_CHAT_TITLE", "aiChat.a11y.title", "AI Chat") }),
77
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
78
+ /* @__PURE__ */ jsx(
79
+ Button,
80
+ {
81
+ variant: "ghost",
82
+ size: "icon",
83
+ className: "h-5 w-5",
84
+ onClick: () => {
85
+ onClear?.();
86
+ setWidgetResetKey((prev) => prev + 1);
87
+ },
88
+ "aria-label": tr(
89
+ "A11Y_CLEAR_CHAT",
90
+ "aiChat.a11y.clearChat",
91
+ "Clear chat"
92
+ ),
93
+ title: tr(
94
+ "A11Y_CLEAR_CHAT",
95
+ "aiChat.a11y.clearChat",
96
+ "Clear chat"
97
+ ),
98
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
99
+ }
104
100
  ),
105
- children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
106
- }
107
- )
108
- ] }),
109
- widgetEverOpened && /* @__PURE__ */ jsx(
110
- ChatInterface,
111
- {
112
- id: conversationId,
113
- variant: "widget",
114
- initialMessages,
115
- onMessagesChange
101
+ /* @__PURE__ */ jsx(
102
+ Button,
103
+ {
104
+ variant: "ghost",
105
+ size: "icon",
106
+ className: "h-5 w-5",
107
+ onClick: () => setWidgetOpen(false),
108
+ "aria-label": tr(
109
+ "A11Y_CLOSE_CHAT",
110
+ "aiChat.a11y.closeChat",
111
+ "Close chat"
112
+ ),
113
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
114
+ }
115
+ )
116
+ ] }),
117
+ widgetEverOpened && /* @__PURE__ */ jsx(
118
+ ChatInterface,
119
+ {
120
+ id: conversationId,
121
+ variant: "widget",
122
+ initialMessages,
123
+ onMessagesChange
124
+ },
125
+ `widget-${conversationId ?? "new"}-${widgetResetKey}`
126
+ )
127
+ ]
128
+ }
129
+ ),
130
+ showTrigger && /* @__PURE__ */ jsx(
131
+ Button,
132
+ {
133
+ size: "icon",
134
+ className: "h-12 w-12 rounded-full shadow-lg",
135
+ onClick: () => {
136
+ setWidgetOpen((prev) => !prev);
137
+ setWidgetEverOpened(true);
116
138
  },
117
- `widget-${conversationId ?? "new"}-${widgetResetKey}`
118
- )
119
- ]
120
- }
121
- ),
122
- showTrigger && /* @__PURE__ */ jsx(
123
- Button,
124
- {
125
- size: "icon",
126
- className: "h-12 w-12 rounded-full shadow-lg",
127
- onClick: () => {
128
- setWidgetOpen((prev) => !prev);
129
- setWidgetEverOpened(true);
130
- },
131
- "aria-label": widgetOpen ? tr("A11Y_CLOSE_CHAT", "aiChat.a11y.closeChat", "Close chat") : tr("A11Y_OPEN_CHAT", "aiChat.a11y.openChat", "Open chat"),
132
- "data-testid": "widget-trigger",
133
- children: widgetOpen ? /* @__PURE__ */ jsx(X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Sparkles, { className: "h-5 w-5" })
134
- }
135
- )
136
- ] });
139
+ "aria-label": widgetOpen ? tr("A11Y_CLOSE_CHAT", "aiChat.a11y.closeChat", "Close chat") : tr("A11Y_OPEN_CHAT", "aiChat.a11y.openChat", "Open chat"),
140
+ "data-testid": "widget-trigger",
141
+ children: widgetOpen ? /* @__PURE__ */ jsx(X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Sparkles, { className: "h-5 w-5" })
142
+ }
143
+ )
144
+ ]
145
+ }
146
+ );
137
147
  }
138
148
  return /* @__PURE__ */ jsxs(
139
149
  "div",
140
150
  {
141
151
  className: cn(
142
152
  "flex h-[calc(100vh-4rem)] w-full overflow-hidden",
143
- className
153
+ className,
154
+ classNames?.container
144
155
  ),
145
156
  "data-testid": "chat-layout",
146
157
  children: [
@@ -82,7 +82,11 @@ function ChatMessage({
82
82
  isRetrying = false
83
83
  }) {
84
84
  const isUser = message.role === "user";
85
- const { localization: customLocalization, toolRenderers } = context.usePluginOverrides(
85
+ const {
86
+ localization: customLocalization,
87
+ toolRenderers,
88
+ classNames
89
+ } = context.usePluginOverrides(
86
90
  "aiChat",
87
91
  {}
88
92
  );
@@ -176,8 +180,11 @@ function ChatMessage({
176
180
  className: utils.cn(
177
181
  "flex gap-3 w-full",
178
182
  isCompact ? "mb-3" : "mb-4",
179
- isUser ? "justify-end" : "justify-start"
183
+ isUser ? "justify-end" : "justify-start",
184
+ classNames?.message
180
185
  ),
186
+ "data-testid": "chat-message",
187
+ "data-role": message.role,
181
188
  "aria-label": isUser ? tr("A11Y_USER_MESSAGE", "aiChat.a11y.userMessage", "Your message") : tr(
182
189
  "A11Y_ASSISTANT_MESSAGE",
183
190
  "aiChat.a11y.assistantMessage",
@@ -201,8 +208,10 @@ function ChatMessage({
201
208
  className: utils.cn(
202
209
  "rounded-lg",
203
210
  isCompact ? "px-3 py-2" : "px-4 py-3",
204
- isUser ? "bg-primary text-primary-foreground" : "bg-muted"
211
+ isUser ? "bg-primary text-primary-foreground" : "bg-muted",
212
+ isUser ? classNames?.userMessage : classNames?.assistantMessage
205
213
  ),
214
+ "data-testid": "chat-message-bubble",
206
215
  children: isUser ? (
207
216
  // User messages: files + images + text (or edit mode)
208
217
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
@@ -76,7 +76,11 @@ function ChatMessage({
76
76
  isRetrying = false
77
77
  }) {
78
78
  const isUser = message.role === "user";
79
- const { localization: customLocalization, toolRenderers } = usePluginOverrides(
79
+ const {
80
+ localization: customLocalization,
81
+ toolRenderers,
82
+ classNames
83
+ } = usePluginOverrides(
80
84
  "aiChat",
81
85
  {}
82
86
  );
@@ -170,8 +174,11 @@ function ChatMessage({
170
174
  className: cn(
171
175
  "flex gap-3 w-full",
172
176
  isCompact ? "mb-3" : "mb-4",
173
- isUser ? "justify-end" : "justify-start"
177
+ isUser ? "justify-end" : "justify-start",
178
+ classNames?.message
174
179
  ),
180
+ "data-testid": "chat-message",
181
+ "data-role": message.role,
175
182
  "aria-label": isUser ? tr("A11Y_USER_MESSAGE", "aiChat.a11y.userMessage", "Your message") : tr(
176
183
  "A11Y_ASSISTANT_MESSAGE",
177
184
  "aiChat.a11y.assistantMessage",
@@ -195,8 +202,10 @@ function ChatMessage({
195
202
  className: cn(
196
203
  "rounded-lg",
197
204
  isCompact ? "px-3 py-2" : "px-4 py-3",
198
- isUser ? "bg-primary text-primary-foreground" : "bg-muted"
205
+ isUser ? "bg-primary text-primary-foreground" : "bg-muted",
206
+ isUser ? classNames?.userMessage : classNames?.assistantMessage
199
207
  ),
208
+ "data-testid": "chat-message-bubble",
200
209
  children: isUser ? (
201
210
  // User messages: files + images + text (or edit mode)
202
211
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
@@ -23,7 +23,7 @@ function ChatSidebar({
23
23
  onNewChat,
24
24
  className
25
25
  }) {
26
- const { localization: customLocalization } = context.usePluginOverrides("aiChat", {});
26
+ const { localization: customLocalization, classNames } = context.usePluginOverrides("aiChat", {});
27
27
  const { basePath: stackBasePath, plugins, router } = context.useStack();
28
28
  const navigate = router?.navigate;
29
29
  const siteBaseURL = plugins?.aiChat?.site.baseURL;
@@ -148,7 +148,11 @@ function ChatSidebar({
148
148
  "div",
149
149
  {
150
150
  "data-testid": "chat-sidebar",
151
- className: utils.cn("flex flex-col h-full bg-muted/30 border-r", className),
151
+ className: utils.cn(
152
+ "flex flex-col h-full bg-muted/30 border-r",
153
+ className,
154
+ classNames?.sidebar
155
+ ),
152
156
  children: [
153
157
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b", children: /* @__PURE__ */ jsxRuntime.jsx(context.PermissionAccess, { permission: plugins_aiChat_permissions.aiChatPermissions.conversation.create(), children: /* @__PURE__ */ jsxRuntime.jsxs(
154
158
  button.Button,
@@ -21,7 +21,7 @@ function ChatSidebar({
21
21
  onNewChat,
22
22
  className
23
23
  }) {
24
- const { localization: customLocalization } = usePluginOverrides("aiChat", {});
24
+ const { localization: customLocalization, classNames } = usePluginOverrides("aiChat", {});
25
25
  const { basePath: stackBasePath, plugins, router } = useStack();
26
26
  const navigate = router?.navigate;
27
27
  const siteBaseURL = plugins?.aiChat?.site.baseURL;
@@ -146,7 +146,11 @@ function ChatSidebar({
146
146
  "div",
147
147
  {
148
148
  "data-testid": "chat-sidebar",
149
- className: cn("flex flex-col h-full bg-muted/30 border-r", className),
149
+ className: cn(
150
+ "flex flex-col h-full bg-muted/30 border-r",
151
+ className,
152
+ classNames?.sidebar
153
+ ),
150
154
  children: [
151
155
  /* @__PURE__ */ jsx("div", { className: "p-4 border-b", children: /* @__PURE__ */ jsx(PermissionAccess, { permission: aiChatPermissions.conversation.create(), children: /* @__PURE__ */ jsxs(
152
156
  Button,
@@ -5,19 +5,20 @@ const jsxRuntime = require('react/jsx-runtime');
5
5
  const context = require('@btst/stack/context');
6
6
  const pageWrapper = require('../../../../../../../ui/src/components/page-wrapper.cjs');
7
7
  const constants = require('../../constants.cjs');
8
+ const utils = require('../../../utils.cjs');
8
9
 
9
10
  function PageWrapper({
10
11
  children,
11
12
  className,
12
13
  testId
13
14
  }) {
14
- const { showAttribution } = context.usePluginOverrides(constants.BLOG_PLUGIN_ID, {
15
+ const { showAttribution, classNames } = context.usePluginOverrides(constants.BLOG_PLUGIN_ID, {
15
16
  showAttribution: true
16
17
  });
17
18
  return /* @__PURE__ */ jsxRuntime.jsx(
18
19
  pageWrapper.PageWrapper,
19
20
  {
20
- className,
21
+ className: utils.cn(className, classNames?.container),
21
22
  testId,
22
23
  showAttribution,
23
24
  children
@@ -3,19 +3,20 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { usePluginOverrides } from '@btst/stack/context';
4
4
  import { PageWrapper as PageWrapper$1 } from '../../../../../../../ui/src/components/page-wrapper.mjs';
5
5
  import { BLOG_PLUGIN_ID } from '../../constants.mjs';
6
+ import { cn } from '../../../utils.mjs';
6
7
 
7
8
  function PageWrapper({
8
9
  children,
9
10
  className,
10
11
  testId
11
12
  }) {
12
- const { showAttribution } = usePluginOverrides(BLOG_PLUGIN_ID, {
13
+ const { showAttribution, classNames } = usePluginOverrides(BLOG_PLUGIN_ID, {
13
14
  showAttribution: true
14
15
  });
15
16
  return /* @__PURE__ */ jsx(
16
17
  PageWrapper$1,
17
18
  {
18
- className,
19
+ className: cn(className, classNames?.container),
19
20
  testId,
20
21
  showAttribution,
21
22
  children