@emblemvault/hustle-react 1.2.0 → 1.3.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.
@@ -2638,6 +2638,14 @@ var animations = `
2638
2638
  text-shadow: 0 0 8px ${defaults.colors.accentPrimary};
2639
2639
  }
2640
2640
  }
2641
+ /* Hide scrollbar while maintaining scroll functionality */
2642
+ .hustle-hide-scrollbar {
2643
+ -ms-overflow-style: none; /* IE and Edge */
2644
+ scrollbar-width: none; /* Firefox */
2645
+ }
2646
+ .hustle-hide-scrollbar::-webkit-scrollbar {
2647
+ display: none; /* Chrome, Safari, Opera */
2648
+ }
2641
2649
  `;
2642
2650
  hljs.registerLanguage("javascript", javascript);
2643
2651
  hljs.registerLanguage("js", javascript);
@@ -3490,6 +3498,7 @@ function HustleChat({
3490
3498
  placeholder = "Type a message...",
3491
3499
  showSettings = false,
3492
3500
  showDebug = false,
3501
+ hideHeader = false,
3493
3502
  initialSystemPrompt = "",
3494
3503
  onMessage,
3495
3504
  onToolCall,
@@ -3653,7 +3662,7 @@ function HustleChat({
3653
3662
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3654
3663
  /* @__PURE__ */ jsx("style", { children: animations }),
3655
3664
  /* @__PURE__ */ jsxs("div", { className, style: styles.container, children: [
3656
- /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
3665
+ !hideHeader && /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
3657
3666
  /* @__PURE__ */ jsx("h2", { style: styles.headerTitle, children: "Chat" }),
3658
3667
  /* @__PURE__ */ jsxs("div", { style: styles.headerActions, children: [
3659
3668
  selectedModel && /* @__PURE__ */ jsx("span", { style: { fontSize: tokens.typography.fontSizeSm, color: tokens.colors.textSecondary }, children: selectedModel.split("/").pop() }),
@@ -3828,7 +3837,7 @@ function HustleChat({
3828
3837
  ] })
3829
3838
  ] })
3830
3839
  ] }) }),
3831
- /* @__PURE__ */ jsxs("div", { style: styles.messagesArea, children: [
3840
+ /* @__PURE__ */ jsxs("div", { className: "hustle-hide-scrollbar", style: styles.messagesArea, children: [
3832
3841
  messages.length === 0 && /* @__PURE__ */ jsx("div", { style: styles.messagesEmpty, children: /* @__PURE__ */ jsx("p", { children: getPlaceholderMessage() }) }),
3833
3842
  /* @__PURE__ */ jsx("div", { style: styles.messagesContainer, children: messages.map((message) => /* @__PURE__ */ jsx(
3834
3843
  MessageBubble,
@@ -3955,7 +3964,344 @@ function SettingsIcon() {
3955
3964
  function AttachIcon() {
3956
3965
  return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
3957
3966
  }
3967
+ var sizeConfigs = {
3968
+ sm: { width: "320px", height: "400px" },
3969
+ md: { width: "380px", height: "520px" },
3970
+ lg: { width: "420px", height: "600px" },
3971
+ xl: { width: "480px", height: "700px" },
3972
+ full: { width: "100vw", height: "100vh" }
3973
+ };
3974
+ var widgetStyles = {
3975
+ // Container for absolute positioning
3976
+ container: {
3977
+ position: "fixed",
3978
+ zIndex: 9999,
3979
+ fontFamily: tokens.typography.fontFamily
3980
+ },
3981
+ // Launcher button
3982
+ launcher: {
3983
+ width: "56px",
3984
+ height: "56px",
3985
+ borderRadius: tokens.radius.full,
3986
+ background: `linear-gradient(135deg, ${tokens.colors.accentPrimary} 0%, #2d7dd2 100%)`,
3987
+ border: "none",
3988
+ cursor: "pointer",
3989
+ display: "flex",
3990
+ alignItems: "center",
3991
+ justifyContent: "center",
3992
+ boxShadow: `0 4px 20px rgba(76, 154, 255, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3)`,
3993
+ transition: `all ${tokens.transitions.normal}`,
3994
+ color: tokens.colors.textInverse
3995
+ },
3996
+ launcherHover: {
3997
+ transform: "scale(1.05)",
3998
+ boxShadow: `0 6px 24px rgba(76, 154, 255, 0.5), 0 4px 12px rgba(0, 0, 0, 0.4)`
3999
+ },
4000
+ // Badge
4001
+ badge: {
4002
+ position: "absolute",
4003
+ top: "-4px",
4004
+ right: "-4px",
4005
+ minWidth: "20px",
4006
+ height: "20px",
4007
+ borderRadius: tokens.radius.pill,
4008
+ background: tokens.colors.accentError,
4009
+ color: tokens.colors.textInverse,
4010
+ fontSize: tokens.typography.fontSizeXs,
4011
+ fontWeight: tokens.typography.fontWeightSemibold,
4012
+ display: "flex",
4013
+ alignItems: "center",
4014
+ justifyContent: "center",
4015
+ padding: "0 6px",
4016
+ border: `2px solid ${tokens.colors.bgPrimary}`
4017
+ },
4018
+ // Chat panel
4019
+ panel: {
4020
+ position: "absolute",
4021
+ borderRadius: tokens.radius.xl,
4022
+ background: tokens.colors.bgSecondary,
4023
+ border: `1px solid ${tokens.colors.borderPrimary}`,
4024
+ boxShadow: `0 16px 48px rgba(0, 0, 0, 0.5)`,
4025
+ overflow: "hidden",
4026
+ display: "flex",
4027
+ flexDirection: "column",
4028
+ transition: `all ${tokens.transitions.slow}`
4029
+ },
4030
+ panelHidden: {
4031
+ opacity: 0,
4032
+ transform: "scale(0.95) translateY(10px)",
4033
+ pointerEvents: "none"
4034
+ },
4035
+ panelVisible: {
4036
+ opacity: 1,
4037
+ transform: "scale(1) translateY(0)"
4038
+ },
4039
+ // Full screen mode overrides
4040
+ panelFull: {
4041
+ position: "fixed",
4042
+ top: 0,
4043
+ left: 0,
4044
+ right: 0,
4045
+ bottom: 0,
4046
+ borderRadius: 0,
4047
+ width: "100vw",
4048
+ height: "100vh"
4049
+ },
4050
+ // Close button in panel header
4051
+ closeBtn: {
4052
+ width: "32px",
4053
+ height: "32px",
4054
+ borderRadius: tokens.radius.md,
4055
+ background: "transparent",
4056
+ border: "none",
4057
+ color: tokens.colors.textTertiary,
4058
+ cursor: "pointer",
4059
+ display: "flex",
4060
+ alignItems: "center",
4061
+ justifyContent: "center",
4062
+ transition: `all ${tokens.transitions.fast}`
4063
+ },
4064
+ closeBtnHover: {
4065
+ background: tokens.colors.bgTertiary,
4066
+ color: tokens.colors.textPrimary
4067
+ }
4068
+ };
4069
+ function ChatIcon() {
4070
+ return /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
4071
+ }
4072
+ function CloseIcon() {
4073
+ return /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4074
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4075
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4076
+ ] });
4077
+ }
4078
+ function MinimizeIcon() {
4079
+ return /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4080
+ /* @__PURE__ */ jsx("polyline", { points: "4 14 10 14 10 20" }),
4081
+ /* @__PURE__ */ jsx("polyline", { points: "20 10 14 10 14 4" }),
4082
+ /* @__PURE__ */ jsx("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
4083
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
4084
+ ] });
4085
+ }
4086
+ function HustleChatWidget({
4087
+ config = {},
4088
+ ...chatProps
4089
+ }) {
4090
+ const {
4091
+ position = "bottom-right",
4092
+ size = "md",
4093
+ title = "Chat",
4094
+ defaultOpen = false,
4095
+ launcherIcon,
4096
+ offset = { x: 24, y: 24 },
4097
+ zIndex = 9999,
4098
+ showBadge = false,
4099
+ badgeContent,
4100
+ launcherStyle,
4101
+ panelStyle,
4102
+ onOpen,
4103
+ onClose,
4104
+ storageKey = "hustle-widget-open"
4105
+ } = config;
4106
+ const [isOpen, setIsOpen] = useState(false);
4107
+ const [isHovered, setIsHovered] = useState(false);
4108
+ const [closeHovered, setCloseHovered] = useState(false);
4109
+ const [mounted, setMounted] = useState(false);
4110
+ useEffect(() => {
4111
+ setMounted(true);
4112
+ if (storageKey && typeof window !== "undefined") {
4113
+ const stored = localStorage.getItem(storageKey);
4114
+ if (stored !== null) {
4115
+ setIsOpen(stored === "true");
4116
+ } else {
4117
+ setIsOpen(defaultOpen);
4118
+ }
4119
+ } else {
4120
+ setIsOpen(defaultOpen);
4121
+ }
4122
+ }, [defaultOpen, storageKey]);
4123
+ useEffect(() => {
4124
+ if (!mounted) return;
4125
+ if (storageKey && typeof window !== "undefined") {
4126
+ localStorage.setItem(storageKey, String(isOpen));
4127
+ }
4128
+ }, [isOpen, storageKey, mounted]);
4129
+ const toggle = useCallback(() => {
4130
+ setIsOpen((prev) => {
4131
+ const next = !prev;
4132
+ if (next) {
4133
+ onOpen?.();
4134
+ } else {
4135
+ onClose?.();
4136
+ }
4137
+ return next;
4138
+ });
4139
+ }, [onOpen, onClose]);
4140
+ const positionStyles = getPositionStyles(position, offset);
4141
+ const sizeConfig = sizeConfigs[size];
4142
+ if (!mounted) {
4143
+ return null;
4144
+ }
4145
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4146
+ /* @__PURE__ */ jsx("style", { children: animations }),
4147
+ /* @__PURE__ */ jsx("style", { children: `
4148
+ @keyframes hustle-widget-bounce {
4149
+ 0%, 100% { transform: translateY(0); }
4150
+ 50% { transform: translateY(-4px); }
4151
+ }
4152
+ ` }),
4153
+ /* @__PURE__ */ jsxs(
4154
+ "div",
4155
+ {
4156
+ style: {
4157
+ ...widgetStyles.container,
4158
+ ...positionStyles.container,
4159
+ zIndex
4160
+ },
4161
+ children: [
4162
+ /* @__PURE__ */ jsxs(
4163
+ "div",
4164
+ {
4165
+ style: {
4166
+ ...widgetStyles.panel,
4167
+ ...positionStyles.panel,
4168
+ ...size === "full" ? widgetStyles.panelFull : {
4169
+ width: sizeConfig.width,
4170
+ height: sizeConfig.height
4171
+ },
4172
+ ...isOpen ? widgetStyles.panelVisible : widgetStyles.panelHidden,
4173
+ ...panelStyle
4174
+ },
4175
+ children: [
4176
+ /* @__PURE__ */ jsxs(
4177
+ "div",
4178
+ {
4179
+ style: {
4180
+ display: "flex",
4181
+ alignItems: "center",
4182
+ justifyContent: "space-between",
4183
+ padding: `${tokens.spacing.md} ${tokens.spacing.lg}`,
4184
+ background: tokens.colors.bgPrimary,
4185
+ borderBottom: `1px solid ${tokens.colors.borderPrimary}`,
4186
+ borderRadius: `${tokens.radius.xl} ${tokens.radius.xl} 0 0`,
4187
+ flexShrink: 0
4188
+ },
4189
+ children: [
4190
+ /* @__PURE__ */ jsx(
4191
+ "span",
4192
+ {
4193
+ style: {
4194
+ fontWeight: tokens.typography.fontWeightSemibold,
4195
+ color: tokens.colors.textPrimary,
4196
+ fontSize: tokens.typography.fontSizeMd
4197
+ },
4198
+ children: title
4199
+ }
4200
+ ),
4201
+ /* @__PURE__ */ jsx(
4202
+ "button",
4203
+ {
4204
+ onClick: toggle,
4205
+ onMouseEnter: () => setCloseHovered(true),
4206
+ onMouseLeave: () => setCloseHovered(false),
4207
+ style: {
4208
+ ...widgetStyles.closeBtn,
4209
+ ...closeHovered ? widgetStyles.closeBtnHover : {}
4210
+ },
4211
+ title: "Close chat",
4212
+ children: size === "full" ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(CloseIcon, {})
4213
+ }
4214
+ )
4215
+ ]
4216
+ }
4217
+ ),
4218
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: /* @__PURE__ */ jsx(HustleChatInner, { ...chatProps }) })
4219
+ ]
4220
+ }
4221
+ ),
4222
+ (size !== "full" || !isOpen) && /* @__PURE__ */ jsxs(
4223
+ "button",
4224
+ {
4225
+ onClick: toggle,
4226
+ onMouseEnter: () => setIsHovered(true),
4227
+ onMouseLeave: () => setIsHovered(false),
4228
+ style: {
4229
+ ...widgetStyles.launcher,
4230
+ ...isHovered ? widgetStyles.launcherHover : {},
4231
+ ...positionStyles.launcher,
4232
+ ...launcherStyle,
4233
+ ...isOpen ? { opacity: 0, pointerEvents: "none" } : {}
4234
+ },
4235
+ title: isOpen ? "Close chat" : "Open chat",
4236
+ "aria-label": isOpen ? "Close chat" : "Open chat",
4237
+ children: [
4238
+ launcherIcon || /* @__PURE__ */ jsx(ChatIcon, {}),
4239
+ showBadge && badgeContent && !isOpen && /* @__PURE__ */ jsx("span", { style: widgetStyles.badge, children: badgeContent })
4240
+ ]
4241
+ }
4242
+ )
4243
+ ]
4244
+ }
4245
+ )
4246
+ ] });
4247
+ }
4248
+ function HustleChatInner(props) {
4249
+ return /* @__PURE__ */ jsx(HustleChat, { ...props, hideHeader: true });
4250
+ }
4251
+ function getPositionStyles(position, offset, isOpen, size) {
4252
+ const panelGap = 16;
4253
+ switch (position) {
4254
+ case "bottom-right":
4255
+ return {
4256
+ container: {
4257
+ bottom: `${offset.y}px`,
4258
+ right: `${offset.x}px`
4259
+ },
4260
+ launcher: {},
4261
+ panel: {
4262
+ bottom: `${56 + panelGap}px`,
4263
+ right: 0
4264
+ }
4265
+ };
4266
+ case "bottom-left":
4267
+ return {
4268
+ container: {
4269
+ bottom: `${offset.y}px`,
4270
+ left: `${offset.x}px`
4271
+ },
4272
+ launcher: {},
4273
+ panel: {
4274
+ bottom: `${56 + panelGap}px`,
4275
+ left: 0
4276
+ }
4277
+ };
4278
+ case "top-right":
4279
+ return {
4280
+ container: {
4281
+ top: `${offset.y}px`,
4282
+ right: `${offset.x}px`
4283
+ },
4284
+ launcher: {},
4285
+ panel: {
4286
+ top: `${56 + panelGap}px`,
4287
+ right: 0
4288
+ }
4289
+ };
4290
+ case "top-left":
4291
+ return {
4292
+ container: {
4293
+ top: `${offset.y}px`,
4294
+ left: `${offset.x}px`
4295
+ },
4296
+ launcher: {},
4297
+ panel: {
4298
+ top: `${56 + panelGap}px`,
4299
+ left: 0
4300
+ }
4301
+ };
4302
+ }
4303
+ }
3958
4304
 
3959
- export { HustleChat, MarkdownContent };
4305
+ export { HustleChat, HustleChatWidget, MarkdownContent };
3960
4306
  //# sourceMappingURL=index.js.map
3961
4307
  //# sourceMappingURL=index.js.map