Skip to content

Commit

Permalink
Unify contexts 4 (#6)
Browse files Browse the repository at this point in the history
* Unify contexts #4

* Make icons type optional in AssistantWindowProps
  • Loading branch information
mme authored Nov 17, 2023
1 parent 6d9a67a commit 79e19c4
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 118 deletions.
16 changes: 16 additions & 0 deletions packages/css/Assistant.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,20 @@
bottom: 1rem;
right: 1rem;
z-index: 30;
line-height: 1.5;
-webkit-text-size-adjust: 100%;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-feature-settings: normal;
font-variation-settings: normal;
touch-action: manipulation;
}

.beakAssistantWindow svg {
display: inline-block;
vertical-align: middle;
}
18 changes: 0 additions & 18 deletions packages/css/Theme.css

This file was deleted.

34 changes: 27 additions & 7 deletions packages/react/src/Assistant.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { useCallback, useEffect, useMemo } from "react";
import { useBeakContext } from "./Beak";
import {
BeakColorScheme,
BeakContext,
BeakIcons,
useBeakContext,
} from "./Beak";
import { Message } from "@beakjs/core";
import { ColorScheme, Icons, Theme } from "./Theme";
import {
ButtonProps,
HeaderProps,
Expand All @@ -21,8 +25,8 @@ interface AssistantWindowProps {
clickOutsideToClose?: boolean;
hitEscapeToClose?: boolean;
hotkey?: string;
icons?: Required<Icons>;
colorScheme?: ColorScheme;
icons?: BeakIcons;
colorScheme?: BeakColorScheme;
Window?: React.ComponentType<WindowProps>;
Button?: React.ComponentType<ButtonProps>;
Header?: React.ComponentType<HeaderProps>;
Expand Down Expand Up @@ -68,9 +72,25 @@ export const AssistantWindow: React.FC<AssistantWindowProps> = ({
await beak.runChatCompletion(message);
};

const ctx = useMemo(() => {
return {
...context,
icons: {
...context.icons,
...icons,
},
colorScheme: colorScheme || context.colorScheme,
};
}, [context, icons, colorScheme]);

const colorSchemeClass =
"beakColorScheme" +
ctx.colorScheme[0].toUpperCase() +
ctx.colorScheme.slice(1);

return (
<Theme colorScheme={colorScheme} icons={icons || {}}>
<div className="beakAssistantWindow">
<BeakContext.Provider value={ctx}>
<div className={`beakAssistantWindow ${colorSchemeClass}`}>
<Button open={open} setOpen={setOpen}></Button>
<Window
open={open}
Expand All @@ -84,7 +104,7 @@ export const AssistantWindow: React.FC<AssistantWindowProps> = ({
<Input inProgress={inProgress} onSend={sendMessage} />
</Window>
</div>
</Theme>
</BeakContext.Provider>
);
};

Expand Down
31 changes: 24 additions & 7 deletions packages/react/src/Beak.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import React, { useMemo } from "react";
import { BeakCore, OpenAIModel, DebugLogger } from "@beakjs/core";
import * as DefaultIcons from "./Icons";

const DEFAULT_DEBUG_LOGGER = new DebugLogger([]);

export type BeakColorScheme = "auto" | "light" | "dark";

export interface BeakIcons {
openIcon?: React.ReactNode;
closeIcon?: React.ReactNode;
headerCloseIcon?: React.ReactNode;
sendIcon?: React.ReactNode;
activityIcon?: React.ReactNode;
spinnerIcon?: React.ReactNode;
}

interface BeakLabels {
initial?: string | string[];
title?: string;
Expand All @@ -15,8 +27,9 @@ interface BeakLabels {
interface BeakContext {
beak: BeakCore;
labels: Required<BeakLabels>;
icons: Required<BeakIcons>;
colorScheme: BeakColorScheme;
debugLogger: DebugLogger;
theme: BeakTheme;
}

export const BeakContext = React.createContext<BeakContext | undefined>(
Expand All @@ -33,8 +46,6 @@ export function useBeakContext(): BeakContext {
return context;
}

type BeakTheme = "auto" | "light" | "dark";

interface BeakProps {
openAIApiKey: string;
openAIModel?: OpenAIModel;
Expand All @@ -43,7 +54,6 @@ interface BeakProps {
maxFeedback?: number;
labels?: BeakLabels;
debugLogger?: DebugLogger;
theme?: BeakTheme;
children?: React.ReactNode;
}

Expand All @@ -55,7 +65,6 @@ export const Beak: React.FC<BeakProps> = ({
maxFeedback,
labels,
debugLogger,
theme,
children,
}) => {
const beak = useMemo(
Expand Down Expand Up @@ -93,9 +102,17 @@ export const Beak: React.FC<BeakProps> = ({
},

debugLogger: debugLogger || DEFAULT_DEBUG_LOGGER,
theme: theme || "auto",
colorScheme: "auto" as BeakColorScheme,
icons: {
openIcon: DefaultIcons.OpenIcon,
closeIcon: DefaultIcons.CloseIcon,
headerCloseIcon: DefaultIcons.HeaderCloseIcon,
sendIcon: DefaultIcons.SendIcon,
activityIcon: DefaultIcons.ActivityIcon,
spinnerIcon: DefaultIcons.SpinnerIcon,
},
}),
[labels, debugLogger, theme]
[labels, debugLogger]
);
return (
<BeakContext.Provider value={context}>{children}</BeakContext.Provider>
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from "react";
import { ButtonProps } from "./props";
import { useBeakContext } from "./Beak";
import "../../css/Button.css";
import { useBeakThemeContext } from "./Theme";

export const Button: React.FC<ButtonProps> = ({ open, setOpen }) => {
const context = useBeakThemeContext();
const context = useBeakContext();
// To ensure that the mouse handler fires even when the button is scaled down
// we wrap the button in a div and attach the handler to the div
return (
Expand Down
4 changes: 1 addition & 3 deletions packages/react/src/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React from "react";
import { HeaderProps } from "./props";
import "../../css/Header.css";
import { useBeakThemeContext } from "./Theme";
import { useBeakContext } from "./Beak";

export const Header: React.FC<HeaderProps> = ({ setOpen }) => {
const context = useBeakContext();
const themeContext = useBeakThemeContext();

return (
<div className="beakHeader">
<div>{context.labels.title}</div>
<button onClick={() => setOpen(false)} aria-label="Close">
{themeContext.icons.headerCloseIcon}
{context.icons.headerCloseIcon}
</button>
</div>
);
Expand Down
6 changes: 1 addition & 5 deletions packages/react/src/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import React, { useRef, useState } from "react";
import TextareaAutosize from "react-textarea-autosize";
import { InputProps } from "./props";
import { useBeakContext } from "./Beak";
import { useBeakThemeContext } from "./Theme";
import "../../css/Input.css";

export const Input: React.FC<InputProps> = ({ inProgress, onSend }) => {
const context = useBeakContext();
const themeContext = useBeakThemeContext();
const textareaRef = useRef<HTMLTextAreaElement>(null);

const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {
Expand All @@ -26,9 +24,7 @@ export const Input: React.FC<InputProps> = ({ inProgress, onSend }) => {
textareaRef.current?.focus();
};

const icon = inProgress
? themeContext.icons.activityIcon
: themeContext.icons.sendIcon;
const icon = inProgress ? context.icons.activityIcon : context.icons.sendIcon;
const disabled = inProgress || text.length === 0;

return (
Expand Down
6 changes: 2 additions & 4 deletions packages/react/src/Messages.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { useEffect } from "react";
import { MessagesProps } from "./props";
import { useBeakContext } from "./Beak";
import { useBeakThemeContext } from "./Theme";
import "../../css/Messages.css";

export const Messages: React.FC<MessagesProps> = ({ messages }) => {
const context = useBeakContext();
const themeContext = useBeakThemeContext();
const messagesEndRef = React.useRef<HTMLDivElement>(null);

const scrollToBottom = () => {
Expand Down Expand Up @@ -34,13 +32,13 @@ export const Messages: React.FC<MessagesProps> = ({ messages }) => {
if (message.status === "pending" && !message.content) {
return (
<div key={index} className={`beakMessage beakAssistantMessage`}>
{themeContext.icons.spinnerIcon}
{context.icons.spinnerIcon}
</div>
);
} else if (message.status === "partial") {
return (
<div key={index} className={`beakMessage beakAssistantMessage`}>
{context.labels.thinking} {themeContext.icons.spinnerIcon}
{context.labels.thinking} {context.icons.spinnerIcon}
</div>
);
} else if (message.content) {
Expand Down
72 changes: 0 additions & 72 deletions packages/react/src/Theme.tsx

This file was deleted.

0 comments on commit 79e19c4

Please sign in to comment.