fix: React Console Warnings and Accessibility Issues in Langflow Frontend (#6950)
* fix errors on console jsx * ✨ (NodeOutputfield/index.tsx): Refactor InspectButton component to use forwardRef for better performance and maintainability ♻️ (NodeOutputfield/index.tsx): Refactor AlertDropdown component to use forwardRef for better performance and maintainability * 📝 (dialog.tsx): Add VisuallyHidden component for accessibility and improve semantics in DialogContent component 🔧 (dialog.tsx): Update DialogContent component to conditionally include VisuallyHidden component for DialogTitle 🔧 (dialog.tsx): Export VisuallyHidden component from dialog.tsx ♻️ (textAnimation.tsx): Refactor TextEffectPerChar component to use TextEffect component with per="char" and as="span" properties for consistency * ✨ (CustomEdges/index.tsx): Destructure props to extract specific properties and pass the rest as domSafeProps for cleaner code ♻️ (singleAlertComponent/index.tsx): Remove unnecessary aria-hidden attribute from IconComponent to improve accessibility and reduce redundancy * ✨ (index.tsx): introduce ShortUniqueId library to generate unique keys for alert items in the dropdown list * ✨ (frontend): add support for displaying a list of items in the NoticeAlert component 📝 (frontend): update NoticeAlertType interface to include a list property for displaying multiple items in the alert * ✨ (styleUtils.ts): introduce new icon PencilRuler to the list of nodeIconsLucide for use in the frontend styling utilities.
This commit is contained in:
parent
47753d37d3
commit
08f886f507
11 changed files with 243 additions and 197 deletions
|
|
@ -56,11 +56,26 @@ export function DefaultEdge({
|
||||||
targetY: targetYNew,
|
targetY: targetYNew,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
animated,
|
||||||
|
selectable,
|
||||||
|
deletable,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
pathOptions,
|
||||||
|
selected,
|
||||||
|
...domSafeProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseEdge
|
<BaseEdge
|
||||||
path={targetHandleObject.output_types ? edgePathLoop : edgePath}
|
path={targetHandleObject.output_types ? edgePathLoop : edgePath}
|
||||||
strokeDasharray={targetHandleObject.output_types ? "5 5" : "0"}
|
strokeDasharray={targetHandleObject.output_types ? "5 5" : "0"}
|
||||||
{...props}
|
{...domSafeProps}
|
||||||
|
data-animated={animated ? "true" : "false"}
|
||||||
|
data-selectable={selectable ? "true" : "false"}
|
||||||
|
data-deletable={deletable ? "true" : "false"}
|
||||||
|
data-selected={selected ? "true" : "false"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,14 @@ import { ICON_STROKE_WIDTH } from "@/constants/constants";
|
||||||
import { targetHandleType } from "@/types/flow";
|
import { targetHandleType } from "@/types/flow";
|
||||||
import { useUpdateNodeInternals } from "@xyflow/react";
|
import { useUpdateNodeInternals } from "@xyflow/react";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { memo, useCallback, useEffect, useMemo, useRef } from "react";
|
import {
|
||||||
|
forwardRef,
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import ForwardedIconComponent, {
|
import ForwardedIconComponent, {
|
||||||
default as IconComponent,
|
default as IconComponent,
|
||||||
} from "../../../../components/common/genericIconComponent";
|
} from "../../../../components/common/genericIconComponent";
|
||||||
|
|
@ -96,49 +103,56 @@ const HideShowButton = memo(
|
||||||
);
|
);
|
||||||
|
|
||||||
const InspectButton = memo(
|
const InspectButton = memo(
|
||||||
({
|
forwardRef(
|
||||||
disabled,
|
(
|
||||||
displayOutputPreview,
|
{
|
||||||
unknownOutput,
|
disabled,
|
||||||
errorOutput,
|
displayOutputPreview,
|
||||||
isToolMode,
|
unknownOutput,
|
||||||
title,
|
errorOutput,
|
||||||
onClick,
|
isToolMode,
|
||||||
id,
|
title,
|
||||||
}: {
|
onClick,
|
||||||
disabled: boolean | undefined;
|
id,
|
||||||
displayOutputPreview: boolean;
|
}: {
|
||||||
unknownOutput: boolean | undefined;
|
disabled: boolean | undefined;
|
||||||
errorOutput: boolean;
|
displayOutputPreview: boolean;
|
||||||
isToolMode: boolean;
|
unknownOutput: boolean | undefined;
|
||||||
title: string;
|
errorOutput: boolean;
|
||||||
onClick: () => void;
|
isToolMode: boolean;
|
||||||
id: string;
|
title: string;
|
||||||
}) => (
|
onClick: () => void;
|
||||||
<Button
|
id: string;
|
||||||
disabled={disabled}
|
},
|
||||||
data-testid={`output-inspection-${title.toLowerCase()}-${id.toLowerCase()}`}
|
ref: React.ForwardedRef<HTMLButtonElement>,
|
||||||
unstyled
|
) => (
|
||||||
onClick={onClick}
|
<Button
|
||||||
>
|
ref={ref}
|
||||||
<IconComponent
|
disabled={disabled}
|
||||||
name="TextSearchIcon"
|
data-testid={`output-inspection-${title.toLowerCase()}-${id.toLowerCase()}`}
|
||||||
strokeWidth={ICON_STROKE_WIDTH}
|
unstyled
|
||||||
className={cn(
|
onClick={onClick}
|
||||||
"icon-size",
|
>
|
||||||
isToolMode
|
<IconComponent
|
||||||
? displayOutputPreview && !unknownOutput
|
name="TextSearchIcon"
|
||||||
? "text-background hover:text-secondary-hover"
|
strokeWidth={ICON_STROKE_WIDTH}
|
||||||
: "cursor-not-allowed text-placeholder-foreground opacity-80"
|
className={cn(
|
||||||
: displayOutputPreview && !unknownOutput
|
"icon-size",
|
||||||
? "text-foreground hover:text-primary-hover"
|
isToolMode
|
||||||
: "cursor-not-allowed text-placeholder-foreground opacity-60",
|
? displayOutputPreview && !unknownOutput
|
||||||
errorOutput ? "text-destructive" : "",
|
? "text-background hover:text-secondary-hover"
|
||||||
)}
|
: "cursor-not-allowed text-placeholder-foreground opacity-80"
|
||||||
/>
|
: displayOutputPreview && !unknownOutput
|
||||||
</Button>
|
? "text-foreground hover:text-primary-hover"
|
||||||
|
: "cursor-not-allowed text-placeholder-foreground opacity-60",
|
||||||
|
errorOutput ? "text-destructive" : "",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
InspectButton.displayName = "InspectButton";
|
||||||
|
|
||||||
const MemoizedOutputComponent = memo(OutputComponent);
|
const MemoizedOutputComponent = memo(OutputComponent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,7 @@ export default function SingleAlert({
|
||||||
key={dropItem.id}
|
key={dropItem.id}
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<IconComponent
|
<IconComponent name="XCircle" className="h-5 w-5 text-status-red" />
|
||||||
name="XCircle"
|
|
||||||
className="h-5 w-5 text-status-red"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
<h3 className="text-sm font-medium text-error-foreground word-break-break-word">
|
<h3 className="text-sm font-medium text-error-foreground word-break-break-word">
|
||||||
|
|
@ -80,11 +76,7 @@ export default function SingleAlert({
|
||||||
className="inline-flex rounded-md p-1.5 text-status-red"
|
className="inline-flex rounded-md p-1.5 text-status-red"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Dismiss</span>
|
<span className="sr-only">Dismiss</span>
|
||||||
<IconComponent
|
<IconComponent name="X" className="h-4 w-4 text-error-foreground" />
|
||||||
name="X"
|
|
||||||
className="h-4 w-4 text-error-foreground"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -95,11 +87,7 @@ export default function SingleAlert({
|
||||||
key={dropItem.id}
|
key={dropItem.id}
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0 cursor-help">
|
<div className="flex-shrink-0 cursor-help">
|
||||||
<IconComponent
|
<IconComponent name="Info" className="h-5 w-5 text-status-blue" />
|
||||||
name="Info"
|
|
||||||
className="h-5 w-5 text-status-blue"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
<div className="ml-3 flex-1 md:flex md:justify-between">
|
||||||
<p className="text-sm font-medium text-info-foreground">
|
<p className="text-sm font-medium text-info-foreground">
|
||||||
|
|
@ -131,11 +119,7 @@ export default function SingleAlert({
|
||||||
className="inline-flex rounded-md p-1.5 text-info-foreground"
|
className="inline-flex rounded-md p-1.5 text-info-foreground"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Dismiss</span>
|
<span className="sr-only">Dismiss</span>
|
||||||
<IconComponent
|
<IconComponent name="X" className="h-4 w-4 text-info-foreground" />
|
||||||
name="X"
|
|
||||||
className="h-4 w-4 text-info-foreground"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -149,7 +133,6 @@ export default function SingleAlert({
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="CheckCircle2"
|
name="CheckCircle2"
|
||||||
className="h-5 w-5 text-status-green"
|
className="h-5 w-5 text-status-green"
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
|
|
@ -173,7 +156,6 @@ export default function SingleAlert({
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="X"
|
name="X"
|
||||||
className="h-4 w-4 text-success-foreground"
|
className="h-4 w-4 text-success-foreground"
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||||
import { useEffect, useState } from "react";
|
import { forwardRef, useEffect, useState } from "react";
|
||||||
|
import ShortUniqueId from "short-unique-id";
|
||||||
import IconComponent from "../../components/common/genericIconComponent";
|
import IconComponent from "../../components/common/genericIconComponent";
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
|
|
@ -11,85 +12,90 @@ import useAlertStore from "../../stores/alertStore";
|
||||||
import { AlertDropdownType } from "../../types/alerts";
|
import { AlertDropdownType } from "../../types/alerts";
|
||||||
import SingleAlert from "./components/singleAlertComponent";
|
import SingleAlert from "./components/singleAlertComponent";
|
||||||
|
|
||||||
export default function AlertDropdown({
|
const AlertDropdown = forwardRef<HTMLDivElement, AlertDropdownType>(
|
||||||
children,
|
function AlertDropdown({ children, notificationRef, onClose }, ref) {
|
||||||
notificationRef,
|
const notificationList = useAlertStore((state) => state.notificationList);
|
||||||
onClose,
|
const clearNotificationList = useAlertStore(
|
||||||
}: AlertDropdownType): JSX.Element {
|
(state) => state.clearNotificationList,
|
||||||
const notificationList = useAlertStore((state) => state.notificationList);
|
);
|
||||||
const clearNotificationList = useAlertStore(
|
const removeFromNotificationList = useAlertStore(
|
||||||
(state) => state.clearNotificationList,
|
(state) => state.removeFromNotificationList,
|
||||||
);
|
);
|
||||||
const removeFromNotificationList = useAlertStore(
|
const setNotificationCenter = useAlertStore(
|
||||||
(state) => state.removeFromNotificationList,
|
(state) => state.setNotificationCenter,
|
||||||
);
|
);
|
||||||
const setNotificationCenter = useAlertStore(
|
|
||||||
(state) => state.setNotificationCenter,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
onClose?.();
|
onClose?.();
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [open, onClose]);
|
||||||
|
|
||||||
return (
|
const uid = new ShortUniqueId();
|
||||||
<Popover
|
|
||||||
data-testid="notification-dropdown"
|
return (
|
||||||
open={open}
|
<Popover
|
||||||
onOpenChange={(target) => {
|
data-testid="notification-dropdown"
|
||||||
setOpen(target);
|
open={open}
|
||||||
if (target) {
|
onOpenChange={(target) => {
|
||||||
setNotificationCenter(false);
|
setOpen(target);
|
||||||
}
|
if (target) {
|
||||||
}}
|
setNotificationCenter(false);
|
||||||
>
|
}
|
||||||
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
}}
|
||||||
<PopoverContent
|
|
||||||
ref={notificationRef}
|
|
||||||
data-testid="notification-dropdown-content"
|
|
||||||
className="noflow nowheel nopan nodelete nodrag z-10 flex h-[500px] w-[500px] flex-col"
|
|
||||||
>
|
>
|
||||||
<div className="text-md flex flex-row justify-between pl-3 font-medium text-foreground">
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||||
Notifications
|
<PopoverContent
|
||||||
<div className="flex gap-3 pr-3">
|
ref={ref}
|
||||||
<button
|
data-testid="notification-dropdown-content"
|
||||||
className="text-foreground hover:text-status-red"
|
className="noflow nowheel nopan nodelete nodrag z-10 flex h-[500px] w-[500px] flex-col"
|
||||||
onClick={() => {
|
>
|
||||||
setOpen(false);
|
<div
|
||||||
setTimeout(clearNotificationList, 100);
|
ref={notificationRef}
|
||||||
}}
|
className="text-md flex flex-row justify-between pl-3 font-medium text-foreground"
|
||||||
>
|
>
|
||||||
<IconComponent name="Trash2" className="h-4 w-4" />
|
Notifications
|
||||||
</button>
|
<div className="flex gap-3 pr-3">
|
||||||
<button
|
<button
|
||||||
className="text-foreground opacity-70 hover:opacity-100"
|
className="text-foreground hover:text-status-red"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
setTimeout(clearNotificationList, 100);
|
||||||
>
|
}}
|
||||||
<Cross2Icon className="h-4 w-4" />
|
>
|
||||||
</button>
|
<IconComponent name="Trash2" className="h-4 w-4" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
<button
|
||||||
<div className="text-high-foreground mt-3 flex h-full w-full flex-col overflow-y-scroll scrollbar-hide">
|
className="text-foreground opacity-70 hover:opacity-100"
|
||||||
{notificationList.length !== 0 ? (
|
onClick={() => {
|
||||||
notificationList.map((alertItem, index) => (
|
setOpen(false);
|
||||||
<SingleAlert
|
}}
|
||||||
key={alertItem.id}
|
>
|
||||||
dropItem={alertItem}
|
<Cross2Icon className="h-4 w-4" />
|
||||||
removeAlert={removeFromNotificationList}
|
</button>
|
||||||
/>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<div className="flex h-full w-full items-center justify-center pb-16 text-ring">
|
|
||||||
{ZERO_NOTIFICATIONS}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
<div className="text-high-foreground mt-3 flex h-full w-full flex-col overflow-y-scroll scrollbar-hide">
|
||||||
</PopoverContent>
|
{notificationList.length !== 0 ? (
|
||||||
</Popover>
|
notificationList.map((alertItem) => (
|
||||||
);
|
<SingleAlert
|
||||||
}
|
key={uid.randomUUID(10)}
|
||||||
|
dropItem={alertItem}
|
||||||
|
removeAlert={removeFromNotificationList}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full w-full items-center justify-center pb-16 text-ring">
|
||||||
|
{ZERO_NOTIFICATIONS}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AlertDropdown;
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
import { CustomLink } from "@/customization/components/custom-link";
|
import { CustomLink } from "@/customization/components/custom-link";
|
||||||
import { Transition } from "@headlessui/react";
|
import { Transition } from "@headlessui/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import Markdown from "react-markdown";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
import IconComponent from "../../components/common/genericIconComponent";
|
import IconComponent from "../../components/common/genericIconComponent";
|
||||||
import { NoticeAlertType } from "../../types/alerts";
|
import { NoticeAlertType } from "../../types/alerts";
|
||||||
|
|
||||||
export default function NoticeAlert({
|
export default function NoticeAlert({
|
||||||
title,
|
title,
|
||||||
link,
|
list = [],
|
||||||
id,
|
id,
|
||||||
|
link,
|
||||||
removeAlert,
|
removeAlert,
|
||||||
}: NoticeAlertType): JSX.Element {
|
}: NoticeAlertType): JSX.Element {
|
||||||
const [show, setShow] = useState(true);
|
const [show, setShow] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timeoutId = setTimeout(() => {
|
if (show) {
|
||||||
setShow(false);
|
|
||||||
// Wait for the leave transition before calling removeAlert
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeAlert(id);
|
setShow(false);
|
||||||
}, 500); // match the duration of the leave transition
|
setTimeout(() => {
|
||||||
}, 5000); // auto-dismiss alert after 5 seconds
|
removeAlert(id);
|
||||||
|
}, 500);
|
||||||
return () => clearTimeout(timeoutId); // Cleanup timeout on component unmount or re-render
|
}, 5000);
|
||||||
}, [id, removeAlert]);
|
}
|
||||||
|
}, [id, removeAlert, show]);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
setShow(false);
|
setShow(false);
|
||||||
// Wait for the leave transition before calling removeAlert
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeAlert(id);
|
removeAlert(id);
|
||||||
}, 500); // Ensure the alert is removed after the animation
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -35,35 +35,65 @@ const DialogOverlay = React.forwardRef<
|
||||||
));
|
));
|
||||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
|
// Create a VisuallyHidden component for accessibility
|
||||||
|
const VisuallyHidden = React.forwardRef<
|
||||||
|
HTMLSpanElement,
|
||||||
|
React.HTMLAttributes<HTMLSpanElement>
|
||||||
|
>(({ children, ...props }, ref) => (
|
||||||
|
<span
|
||||||
|
ref={ref}
|
||||||
|
className="absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0"
|
||||||
|
style={{ clip: "rect(0 0 0 0)", clipPath: "inset(50%)" }}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
));
|
||||||
|
VisuallyHidden.displayName = "VisuallyHidden";
|
||||||
|
|
||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
||||||
>(({ className, children, ...props }, ref) => (
|
hideTitle?: boolean;
|
||||||
<DialogPortal>
|
}
|
||||||
<DialogOverlay />
|
>(({ className, children, hideTitle = false, ...props }, ref) => {
|
||||||
<DialogPrimitive.Content
|
// Check if DialogTitle is included in children
|
||||||
ref={ref}
|
const hasDialogTitle = React.Children.toArray(children).some(
|
||||||
className={cn(
|
(child) => React.isValidElement(child) && child.type === DialogTitle,
|
||||||
"fixed z-50 flex w-full max-w-lg flex-col gap-4 rounded-xl border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]",
|
);
|
||||||
className,
|
|
||||||
)}
|
return (
|
||||||
{...props}
|
<DialogPortal>
|
||||||
>
|
<DialogOverlay />
|
||||||
{children}
|
<DialogPrimitive.Content
|
||||||
<ShadTooltip
|
ref={ref}
|
||||||
styleClasses="z-50"
|
className={cn(
|
||||||
content="Close"
|
"fixed z-50 flex w-full max-w-lg flex-col gap-4 rounded-xl border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]",
|
||||||
side="bottom"
|
className,
|
||||||
avoidCollisions
|
)}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<DialogPrimitive.Close className="absolute right-2 top-2 flex h-8 w-8 items-center justify-center rounded-sm ring-offset-background transition-opacity hover:bg-secondary-hover hover:text-accent-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
{!hasDialogTitle && (
|
||||||
<Cross2Icon className="h-[18px] w-[18px]" />
|
<VisuallyHidden>
|
||||||
<span className="sr-only">Close</span>
|
<DialogTitle>Dialog</DialogTitle>
|
||||||
</DialogPrimitive.Close>
|
</VisuallyHidden>
|
||||||
</ShadTooltip>
|
)}
|
||||||
</DialogPrimitive.Content>
|
{children}
|
||||||
</DialogPortal>
|
<ShadTooltip
|
||||||
));
|
styleClasses="z-50"
|
||||||
|
content="Close"
|
||||||
|
side="bottom"
|
||||||
|
avoidCollisions
|
||||||
|
>
|
||||||
|
<DialogPrimitive.Close className="absolute right-2 top-2 flex h-8 w-8 items-center justify-center rounded-sm ring-offset-background transition-opacity hover:bg-secondary-hover hover:text-accent-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||||
|
<Cross2Icon className="h-[18px] w-[18px]" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</ShadTooltip>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
);
|
||||||
|
});
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({
|
const DialogHeader = ({
|
||||||
|
|
@ -126,4 +156,5 @@ export {
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
|
VisuallyHidden,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,7 @@ const AnimationComponent: React.FC<{
|
||||||
{segment}
|
{segment}
|
||||||
</motion.span>
|
</motion.span>
|
||||||
) : per === "word" ? (
|
) : per === "word" ? (
|
||||||
<motion.span
|
<motion.span variants={variants} className="inline-block whitespace-pre">
|
||||||
aria-hidden="true"
|
|
||||||
variants={variants}
|
|
||||||
className="inline-block whitespace-pre"
|
|
||||||
>
|
|
||||||
{segment}
|
{segment}
|
||||||
</motion.span>
|
</motion.span>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -123,7 +119,6 @@ const AnimationComponent: React.FC<{
|
||||||
{segment.split("").map((char, charIndex) => (
|
{segment.split("").map((char, charIndex) => (
|
||||||
<motion.span
|
<motion.span
|
||||||
key={`char-${charIndex}`}
|
key={`char-${charIndex}`}
|
||||||
aria-hidden="true"
|
|
||||||
variants={variants}
|
variants={variants}
|
||||||
className="inline-block whitespace-pre"
|
className="inline-block whitespace-pre"
|
||||||
>
|
>
|
||||||
|
|
@ -151,7 +146,7 @@ AnimationComponent.displayName = "AnimationComponent";
|
||||||
export function TextEffect({
|
export function TextEffect({
|
||||||
children,
|
children,
|
||||||
per = "word",
|
per = "word",
|
||||||
as = "p",
|
as = "span",
|
||||||
variants,
|
variants,
|
||||||
className,
|
className,
|
||||||
preset,
|
preset,
|
||||||
|
|
@ -224,7 +219,7 @@ export function TextEffect({
|
||||||
|
|
||||||
export function TextEffectPerChar({ children }: { children: string }) {
|
export function TextEffectPerChar({ children }: { children: string }) {
|
||||||
return (
|
return (
|
||||||
<TextEffect per="char" preset="fade">
|
<TextEffect per="char" preset="fade" as="span">
|
||||||
{children}
|
{children}
|
||||||
</TextEffect>
|
</TextEffect>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -9,6 +9,7 @@ export type NoticeAlertType = {
|
||||||
link?: string;
|
link?: string;
|
||||||
id: string;
|
id: string;
|
||||||
removeAlert: (id: string) => void;
|
removeAlert: (id: string) => void;
|
||||||
|
list?: Array<string>;
|
||||||
};
|
};
|
||||||
export type SuccessAlertType = {
|
export type SuccessAlertType = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@ import {
|
||||||
Pen,
|
Pen,
|
||||||
Pencil,
|
Pencil,
|
||||||
PencilLine,
|
PencilLine,
|
||||||
|
PencilRuler,
|
||||||
PieChart,
|
PieChart,
|
||||||
Pin,
|
Pin,
|
||||||
Plane,
|
Plane,
|
||||||
|
|
@ -857,6 +858,7 @@ export const nodeIconsLucide: iconsType = {
|
||||||
UserMinus2,
|
UserMinus2,
|
||||||
UserPlus2,
|
UserPlus2,
|
||||||
Pencil,
|
Pencil,
|
||||||
|
PencilRuler,
|
||||||
ChevronsRight,
|
ChevronsRight,
|
||||||
ChevronsLeft,
|
ChevronsLeft,
|
||||||
EyeOff,
|
EyeOff,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue