Updates
This commit is contained in:
@@ -9,6 +9,8 @@ export const TWUIDropdownContentPositions = [
|
||||
"left",
|
||||
"bottom-left",
|
||||
"top-left",
|
||||
"top",
|
||||
"bottom",
|
||||
"right",
|
||||
"bottom-right",
|
||||
"top-right",
|
||||
@@ -160,6 +162,8 @@ export default function Dropdown({
|
||||
? "right-0 top-[100%]"
|
||||
: position == "center"
|
||||
? "left-[50%] -translate-x-[50%] top-[100%]"
|
||||
: position == "top"
|
||||
? "left-[50%] -translate-x-[50%] bottom-[100%]"
|
||||
: "top-[100%]",
|
||||
above ? "-translate-y-[120%]" : "",
|
||||
open ? "flex" : "hidden",
|
||||
|
||||
@@ -2,19 +2,26 @@ import { ComponentProps, DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import Center from "../layout/Center";
|
||||
import Loading from "./Loading";
|
||||
import Row from "../layout/Row";
|
||||
import Span from "../layout/Span";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {
|
||||
loadingProps?: ComponentProps<typeof Loading>;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Loading Overlay Component
|
||||
* @className_wrapper twui-loading-overlay
|
||||
*/
|
||||
export default function LoadingOverlay({ loadingProps, ...props }: Props) {
|
||||
export default function LoadingOverlay({
|
||||
loadingProps,
|
||||
label,
|
||||
...props
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
@@ -26,7 +33,10 @@ export default function LoadingOverlay({ loadingProps, ...props }: Props) {
|
||||
)}
|
||||
>
|
||||
<Center>
|
||||
<Loading {...loadingProps} />
|
||||
<Row>
|
||||
<Loading {...loadingProps} />
|
||||
{label && <Span>{label}</Span>}
|
||||
</Row>
|
||||
</Center>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -32,6 +32,7 @@ export type TWUI_MODAL_PROPS = DetailedHTMLProps<
|
||||
trigger?: (typeof TWUIPopoverTriggers)[number];
|
||||
debounce?: number;
|
||||
onClose?: () => any;
|
||||
hoverOpen?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -55,6 +56,7 @@ export default function Modal(props: TWUI_MODAL_PROPS) {
|
||||
trigger = "hover",
|
||||
debounce = 500,
|
||||
onClose,
|
||||
hoverOpen,
|
||||
} = props;
|
||||
|
||||
const [ready, setReady] = React.useState(false);
|
||||
@@ -65,6 +67,9 @@ export default function Modal(props: TWUI_MODAL_PROPS) {
|
||||
const modalRoot = document.getElementById(IDName);
|
||||
|
||||
if (modalRoot) {
|
||||
if (isPopover) {
|
||||
modalRoot.style.zIndex = "1000";
|
||||
}
|
||||
setReady(true);
|
||||
} else {
|
||||
const newModalRootEl = document.createElement("div");
|
||||
@@ -144,12 +149,12 @@ export default function Modal(props: TWUI_MODAL_PROPS) {
|
||||
onClick={(e) => setOpen(!open)}
|
||||
ref={finalTargetRef}
|
||||
onMouseEnter={
|
||||
isPopover && trigger === "hover"
|
||||
isPopover && (trigger === "hover" || hoverOpen)
|
||||
? popoverEnterFn
|
||||
: targetWrapperProps?.onMouseEnter
|
||||
}
|
||||
onMouseLeave={
|
||||
isPopover && trigger === "hover"
|
||||
isPopover && (trigger === "hover" || hoverOpen)
|
||||
? popoverLeaveFn
|
||||
: targetWrapperProps?.onMouseLeave
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export type SearchProps<KeyType extends string> = DetailedHTMLProps<
|
||||
>;
|
||||
loading?: boolean;
|
||||
placeholder?: string;
|
||||
componentRef?: React.RefObject<HTMLInputElement | null>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ export default function Search<KeyType extends string>({
|
||||
buttonProps,
|
||||
loading,
|
||||
placeholder,
|
||||
componentRef,
|
||||
...props
|
||||
}: SearchProps<KeyType>) {
|
||||
const [input, setInput] = React.useState(
|
||||
@@ -52,7 +54,7 @@ export default function Search<KeyType extends string>({
|
||||
}, delay);
|
||||
}, [input]);
|
||||
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
const inputRef = componentRef || React.useRef<HTMLInputElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (props.autoFocus) {
|
||||
@@ -64,7 +66,7 @@ export default function Search<KeyType extends string>({
|
||||
<Row
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"relative xl:flex-nowrap items-stretch gap-0",
|
||||
"relative xl:flex-nowrap items-stretch gap-0 flex-nowrap",
|
||||
"twui-search-wrapper",
|
||||
props?.className
|
||||
)}
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function Table({ data }: Props) {
|
||||
<th
|
||||
key={header}
|
||||
className={twMerge(
|
||||
"px-3 py-2 text-left text-sm opacity-50",
|
||||
"px-3 py-2 text-left opacity-50",
|
||||
"font-semibold"
|
||||
)}
|
||||
title={header}
|
||||
@@ -58,7 +58,7 @@ export default function Table({ data }: Props) {
|
||||
<td
|
||||
key={`${header}-${index}`}
|
||||
className={twMerge(
|
||||
"px-3 py-2 whitespace-nowrap text-sm text-foreground-light",
|
||||
"px-3 py-2 whitespace-nowrap text-foreground-light",
|
||||
"dark:text-foreground-dark max-w-[200px] overflow-hidden",
|
||||
"overflow-ellipsis"
|
||||
)}
|
||||
|
||||
@@ -8,7 +8,7 @@ import twuiSlugify from "../utils/slugify";
|
||||
export type TWUITabsObject = {
|
||||
title: string;
|
||||
value?: string;
|
||||
content: React.ReactNode;
|
||||
content?: React.ReactNode;
|
||||
defaultActive?: boolean;
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@ export type TWUI_TOGGLE_PROPS = React.ComponentProps<typeof Stack> & {
|
||||
* @className twui-tab-buttons
|
||||
* @className twui-tab-button-active
|
||||
* @className twui-tab-buttons-wrapper
|
||||
* @className twui-tab-buttons-container
|
||||
* @className twui-tabs-border
|
||||
*/
|
||||
export default function Tabs({
|
||||
tabsContentArray,
|
||||
@@ -91,13 +93,14 @@ export default function Tabs({
|
||||
)}
|
||||
>
|
||||
<Border
|
||||
className="p-0 w-full overflow-hidden"
|
||||
className="p-0 w-full overflow-hidden twui-tabs-border"
|
||||
{...tabsBorderProps}
|
||||
>
|
||||
<Row
|
||||
className={twMerge(
|
||||
"gap-0 items-stretch w-full flex-nowrap overflow-x-auto",
|
||||
centered && "justify-center"
|
||||
centered && "justify-center",
|
||||
"twui-tab-buttons-container"
|
||||
)}
|
||||
>
|
||||
{values.map((value, index) => {
|
||||
|
||||
@@ -18,6 +18,7 @@ type Props = {
|
||||
loading?: boolean;
|
||||
mdRes?: string;
|
||||
setMdRes: React.Dispatch<React.SetStateAction<string>>;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
export default function AIPromptBlock({
|
||||
@@ -27,6 +28,7 @@ export default function AIPromptBlock({
|
||||
loading = false,
|
||||
mdRes = "",
|
||||
setMdRes,
|
||||
placeholder,
|
||||
}: Props) {
|
||||
const [prompt, setPrompt] = React.useState("");
|
||||
const currentPromptRef = React.useRef("");
|
||||
@@ -43,7 +45,7 @@ export default function AIPromptBlock({
|
||||
<MessageCircleMore
|
||||
size={15}
|
||||
opacity={0.5}
|
||||
className="-mt-[1px]"
|
||||
className="-mt-px"
|
||||
/>
|
||||
</Row>
|
||||
</Card>
|
||||
@@ -53,11 +55,15 @@ export default function AIPromptBlock({
|
||||
setStreamRes={setMdRes}
|
||||
streamRes={mdRes}
|
||||
history={history}
|
||||
loading={loading}
|
||||
/>
|
||||
<Stack className="w-full relative">
|
||||
{loading && <LoadingOverlay />}
|
||||
<Textarea
|
||||
placeholder={model ? `Prompt ${model}` : "Prompt AI"}
|
||||
placeholder={
|
||||
placeholder ||
|
||||
(model ? `Prompt ${model}` : "Prompt AI")
|
||||
}
|
||||
wrapperProps={{ className: "outline-none" }}
|
||||
wrapperWrapperProps={{ className: "w-full" }}
|
||||
value={prompt}
|
||||
@@ -65,7 +71,7 @@ export default function AIPromptBlock({
|
||||
setPrompt(e.target.value);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key == "Enter" && !e.ctrlKey) {
|
||||
if (e.key == "Enter" && !e.ctrlKey && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
currentPromptRef.current = prompt;
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -8,12 +8,14 @@ type Props = {
|
||||
streamRes: string;
|
||||
setStreamRes: React.Dispatch<React.SetStateAction<string>>;
|
||||
history: ChatCompletionMessageParam[];
|
||||
loading?: boolean;
|
||||
};
|
||||
|
||||
export default function AIPromptPreview({
|
||||
setStreamRes,
|
||||
streamRes,
|
||||
history,
|
||||
loading,
|
||||
}: Props) {
|
||||
const responseContentRef = React.useRef<HTMLDivElement>(null);
|
||||
const isContentInterrupted = React.useRef(false);
|
||||
@@ -27,7 +29,7 @@ export default function AIPromptPreview({
|
||||
}
|
||||
}, [streamRes]);
|
||||
|
||||
if (!streamRes?.match(/./)) return null;
|
||||
if (loading || !streamRes?.match(/./)) return null;
|
||||
|
||||
return (
|
||||
<Stack className="w-full">
|
||||
|
||||
Reference in New Issue
Block a user