Fix build
This commit is contained in:
parent
c014b95e62
commit
c04a437283
8 changed files with 5115 additions and 159 deletions
|
|
@ -11,6 +11,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@floating-ui/react": "^0.27.4",
|
||||
"@internationalized/date": "^3.7.0",
|
||||
"@react-aria/i18n": "^3.12.7",
|
||||
"@react-aria/toast": "^3.0.0",
|
||||
"@react-stately/toast": "^3.0.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
|
|
@ -39,6 +41,8 @@
|
|||
"vite": "^6.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.0.14"
|
||||
"@react-stately/calendar": "^3.7.1",
|
||||
"@tailwindcss/vite": "^4.0.14",
|
||||
"react-stately": "^3.36.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,25 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
'@react-stately/calendar':
|
||||
specifier: ^3.7.1
|
||||
version: 3.7.1(react@19.0.0)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.0.14
|
||||
version: 4.0.14(vite@6.2.2(jiti@2.4.2)(lightningcss@1.29.2))
|
||||
react-stately:
|
||||
specifier: ^3.36.1
|
||||
version: 3.36.1(react@19.0.0)
|
||||
devDependencies:
|
||||
'@floating-ui/react':
|
||||
specifier: ^0.27.4
|
||||
version: 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@internationalized/date':
|
||||
specifier: ^3.7.0
|
||||
version: 3.7.0
|
||||
'@react-aria/i18n':
|
||||
specifier: ^3.12.7
|
||||
version: 3.12.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@react-aria/toast':
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
|
|
@ -24,9 +36,6 @@ importers:
|
|||
'@tailwindcss/container-queries':
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1(tailwindcss@4.0.14)
|
||||
'@tailwindcss/postcss':
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.14
|
||||
'@types/react':
|
||||
specifier: 19.0.10
|
||||
version: 19.0.10
|
||||
|
|
@ -99,10 +108,6 @@ importers:
|
|||
|
||||
packages:
|
||||
|
||||
'@alloc/quick-lru@5.2.0':
|
||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
|
@ -1237,9 +1242,6 @@ packages:
|
|||
resolution: {integrity: sha512-M8VCNyO/NBi5vJ2cRcI9u8w7Si+i76a7o1vveoGtbbjpEYJZYiyc7f2VGps/DqawO56l3tImIbq2OT/533jcrA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tailwindcss/postcss@4.0.14':
|
||||
resolution: {integrity: sha512-+uIR6KtKhla1XeIanF27KtrfYy+PX+R679v5LxbkmEZlhQe3g8rk+wKj7Xgt++rWGRuFLGMXY80Ek8JNn+kN/g==}
|
||||
|
||||
'@tailwindcss/vite@4.0.14':
|
||||
resolution: {integrity: sha512-y69ztPTRFy+13EPS/7dEFVl7q2Goh1pQueVO8IfGeyqSpcx/joNJXFk0lLhMgUbF0VFJotwRSb9ZY7Xoq3r26Q==}
|
||||
peerDependencies:
|
||||
|
|
@ -2210,8 +2212,6 @@ packages:
|
|||
|
||||
snapshots:
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.8
|
||||
|
|
@ -3721,15 +3721,6 @@ snapshots:
|
|||
'@tailwindcss/oxide-win32-arm64-msvc': 4.0.14
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.0.14
|
||||
|
||||
'@tailwindcss/postcss@4.0.14':
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.0.14
|
||||
'@tailwindcss/oxide': 4.0.14
|
||||
lightningcss: 1.29.2
|
||||
postcss: 8.5.3
|
||||
tailwindcss: 4.0.14
|
||||
|
||||
'@tailwindcss/vite@4.0.14(vite@6.2.2(jiti@2.4.2)(lightningcss@1.29.2))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.0.14
|
||||
|
|
|
|||
|
|
@ -355,6 +355,17 @@ export const App = () => {
|
|||
</section>
|
||||
</main>
|
||||
</div>
|
||||
<footer className="mt-24 py-8 border-t border-slate-200 dark:border-slate-800">
|
||||
<div className="container mx-auto px-4 text-center">
|
||||
<p className="text-slate-600 dark:text-slate-400 text-sm">
|
||||
© {new Date().getFullYear()} XTablo. Tous droits réservés.
|
||||
</p>
|
||||
<p className="text-slate-500 dark:text-slate-500 text-xs mt-2">
|
||||
XTablo est une marque déposée. Les logos et noms de marques sont des
|
||||
marques déposées de leurs propriétaires respectifs.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
<style>
|
||||
{`
|
||||
@keyframes slide {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import React from "react";
|
||||
import {
|
||||
Heading,
|
||||
Calendar as RACCalendar,
|
||||
|
|
@ -13,24 +13,24 @@ import {
|
|||
useLocale,
|
||||
composeRenderProps,
|
||||
CalendarStateContext,
|
||||
} from 'react-aria-components';
|
||||
import { Button, ButtonGroup } from './button';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from './icons';
|
||||
} from "react-aria-components";
|
||||
import { Button, ButtonGroup } from "./button";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "./icons";
|
||||
import {
|
||||
CalendarDate,
|
||||
getLocalTimeZone,
|
||||
isToday,
|
||||
} from '@internationalized/date';
|
||||
import { CalendarState } from '@react-stately/calendar';
|
||||
import { useDateFormatter } from '@react-aria/i18n';
|
||||
import { NativeSelect, NativeSelectField } from './native-select';
|
||||
import { Label } from './field';
|
||||
} from "@internationalized/date";
|
||||
import { CalendarState } from "@react-stately/calendar";
|
||||
import { useDateFormatter } from "@react-aria/i18n";
|
||||
import { NativeSelect, NativeSelectField } from "./native-select";
|
||||
import { Label } from "./field";
|
||||
|
||||
export type YearRange = number | [yearsBefore: number, yearsAfter: number];
|
||||
|
||||
export interface CalendarProps<T extends DateValue>
|
||||
extends Omit<RACCalendarProps<T>, 'visibleDuration'> {
|
||||
extends Omit<RACCalendarProps<T>, "visibleDuration"> {
|
||||
yearRange?: YearRange;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ export function Calendar<T extends DateValue>({
|
|||
<RACCalendar
|
||||
{...props}
|
||||
className={composeRenderProps(props.className, (className) => {
|
||||
return twMerge('px-1 py-2.5', className);
|
||||
return twMerge("px-1 py-2.5", className);
|
||||
})}
|
||||
>
|
||||
<CalendarHeader yearRange={yearRange} />
|
||||
|
|
@ -59,7 +59,7 @@ export function Calendar<T extends DateValue>({
|
|||
<CalendarCell
|
||||
date={date}
|
||||
className={composeRenderProps(
|
||||
'',
|
||||
"",
|
||||
(
|
||||
className,
|
||||
{
|
||||
|
|
@ -70,30 +70,30 @@ export function Calendar<T extends DateValue>({
|
|||
isInvalid,
|
||||
isUnavailable,
|
||||
isFocusVisible,
|
||||
},
|
||||
}
|
||||
) => {
|
||||
return twMerge(
|
||||
'relative flex size-10 cursor-default items-center justify-center rounded-lg text-sm outline-hidden',
|
||||
"relative flex size-10 cursor-default items-center justify-center rounded-lg text-sm outline-hidden",
|
||||
isToday(date, getLocalTimeZone()) &&
|
||||
'bg-zinc-100 dark:bg-zinc-800',
|
||||
isHovered && 'bg-zinc-100 dark:bg-zinc-800',
|
||||
isPressed && 'bg-accent/90 text-white',
|
||||
isDisabled && 'opacity-50',
|
||||
"bg-zinc-100 dark:bg-zinc-800",
|
||||
isHovered && "bg-zinc-100 dark:bg-zinc-800",
|
||||
isPressed && "bg-accent/90 text-white",
|
||||
isDisabled && "opacity-50",
|
||||
isSelected && [
|
||||
'bg-accent text-sm text-[lch(from_var(--color-accent)_calc((49.44_-_l)_*_infinity)_0_0)]',
|
||||
isHovered && 'bg-accent dark:bg-accent',
|
||||
"bg-accent text-sm text-[lch(from_var(--color-accent)_calc((49.44_-_l)_*_infinity)_0_0)]",
|
||||
isHovered && "bg-accent dark:bg-accent",
|
||||
isInvalid &&
|
||||
'border-destructive bg-destructive text-white',
|
||||
"border-destructive bg-destructive text-white",
|
||||
],
|
||||
isUnavailable &&
|
||||
'text-destructive decoration-destructive line-through',
|
||||
"text-destructive decoration-destructive line-through",
|
||||
isFocusVisible && [
|
||||
'outline-ring outline outline-2',
|
||||
isSelected && 'outline-offset-1',
|
||||
"outline-ring outline outline-2",
|
||||
isSelected && "outline-offset-1",
|
||||
],
|
||||
className,
|
||||
className
|
||||
);
|
||||
},
|
||||
}
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
|
@ -117,8 +117,8 @@ export function CalendarHeader({ yearRange }: { yearRange?: YearRange }) {
|
|||
return (
|
||||
<header
|
||||
className={twMerge(
|
||||
'flex w-full items-center py-1 ps-4 pe-2',
|
||||
yearRange ? 'ps-2' : 'ps-4',
|
||||
"flex w-full items-center py-1 ps-4 pe-2",
|
||||
yearRange ? "ps-2" : "ps-4"
|
||||
)}
|
||||
>
|
||||
{yearRange ? (
|
||||
|
|
@ -143,7 +143,7 @@ export function CalendarHeader({ yearRange }: { yearRange?: YearRange }) {
|
|||
aria-label="Previous"
|
||||
className="[&:not(:hover)]:text-muted/75 focus-visible:-outline-offset-2"
|
||||
>
|
||||
{direction === 'rtl' ? (
|
||||
{direction === "rtl" ? (
|
||||
<ChevronRightIcon className="sm:size-5" />
|
||||
) : (
|
||||
<ChevronLeftIcon className="sm:size-5" />
|
||||
|
|
@ -158,7 +158,7 @@ export function CalendarHeader({ yearRange }: { yearRange?: YearRange }) {
|
|||
aria-label="Next"
|
||||
className="[&:not(:hover)]:text-muted/75 focus-visible:-outline-offset-2"
|
||||
>
|
||||
{direction === 'rtl' ? (
|
||||
{direction === "rtl" ? (
|
||||
<ChevronLeftIcon className="sm:size-5" />
|
||||
) : (
|
||||
<ChevronRightIcon className="sm:size-5" />
|
||||
|
|
@ -193,7 +193,7 @@ function YearDropdown({
|
|||
formatted: string;
|
||||
}> = [];
|
||||
const formatter = useDateFormatter({
|
||||
year: 'numeric',
|
||||
year: "numeric",
|
||||
timeZone: state.timeZone,
|
||||
});
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ function YearDropdown({
|
|||
|
||||
if (yearsBefore <= 0 || yearsAfter <= 0) {
|
||||
throw new Error(
|
||||
'The yearRange prop must be a positive number or an array of two positive numbers.',
|
||||
"The yearRange prop must be a positive number or an array of two positive numbers."
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ function YearDropdown({
|
|||
function MonthDropdown({ state }: { state: CalendarState }) {
|
||||
const months: Array<string> = [];
|
||||
const formatter = useDateFormatter({
|
||||
month: 'long',
|
||||
month: "long",
|
||||
timeZone: state.timeZone,
|
||||
});
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ function MonthDropdown({ state }: { state: CalendarState }) {
|
|||
// systems, such as the Hebrew, the number of months may differ
|
||||
// between years.
|
||||
const numMonths = state.focusedDate.calendar.getMonthsInYear(
|
||||
state.focusedDate,
|
||||
state.focusedDate
|
||||
);
|
||||
for (let i = 1; i <= numMonths; i++) {
|
||||
const date = state.focusedDate.set({ month: i });
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { twMerge } from 'tailwind-merge';
|
||||
import { TextProps } from 'react-aria-components';
|
||||
import { Text } from './text';
|
||||
import { Heading, HeadingProps } from './heading';
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { TextProps } from "react-aria-components";
|
||||
import { Text } from "./text";
|
||||
import { Heading, HeadingProps } from "./heading";
|
||||
|
||||
export function EmptyState({
|
||||
className,
|
||||
...props
|
||||
}: React.JSX.IntrinsicElements['div']) {
|
||||
}: React.JSX.IntrinsicElements["div"]) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
'flex h-full w-full flex-col items-center justify-center gap-1 p-4 text-center @container',
|
||||
className,
|
||||
"flex h-full w-full flex-col items-center justify-center gap-1 p-4 text-center @container",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
|
@ -22,17 +22,17 @@ export function EmptyStateIcon({
|
|||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.JSX.IntrinsicElements['div']) {
|
||||
}: React.JSX.IntrinsicElements["div"]) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
'mb-2 flex max-w-32 items-center justify-center @md:max-w-40',
|
||||
'[&>svg:not([class*=text-])]:text-muted [&>svg]:h-auto [&>svg]:min-w-12 [&>svg]:max-w-full',
|
||||
className,
|
||||
"mb-2 flex max-w-32 items-center justify-center @md:max-w-40",
|
||||
"[&>svg:not([class*=text-])]:text-muted [&>svg]:h-auto [&>svg]:min-w-12 [&>svg]:max-w-full",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -43,10 +43,11 @@ export function EmptyStateHeading({
|
|||
...props
|
||||
}: HeadingProps) {
|
||||
return (
|
||||
// @ts-ignore
|
||||
<Heading
|
||||
{...props}
|
||||
level={level}
|
||||
className={twMerge('text-balance', className)}
|
||||
className={twMerge("text-balance", className)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -55,7 +56,7 @@ export function EmptyStateDescription({ className, ...props }: TextProps) {
|
|||
return (
|
||||
<Text
|
||||
{...props}
|
||||
className={twMerge('max-w-prose text-balance', className)}
|
||||
className={twMerge("max-w-prose text-balance", className)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -63,13 +64,13 @@ export function EmptyStateDescription({ className, ...props }: TextProps) {
|
|||
export function EmptyStateActions({
|
||||
className,
|
||||
...props
|
||||
}: React.JSX.IntrinsicElements['div']) {
|
||||
}: React.JSX.IntrinsicElements["div"]) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
'mt-3 flex flex-col items-center justify-center gap-4 p-2',
|
||||
className,
|
||||
"mt-3 flex flex-col items-center justify-center gap-4 p-2",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import { LabelContext, TextFieldProps, type Key } from 'react-aria-components';
|
||||
import { Tag, TagGroup, TagList } from './tag-group';
|
||||
import { ListData } from 'react-stately';
|
||||
import { Input, TextField } from './field';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import React from "react";
|
||||
import { LabelContext, TextFieldProps, type Key } from "react-aria-components";
|
||||
import { Tag, TagGroup, TagList } from "./tag-group";
|
||||
import { ListData } from "react-stately";
|
||||
import { Input, TextField } from "./field";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
interface TagItem {
|
||||
id: number;
|
||||
|
|
@ -22,14 +22,14 @@ function useTagInputContext() {
|
|||
const context = React.useContext(TagInputContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('<TagInputContext.Provider> is required');
|
||||
throw new Error("<TagInputContext.Provider> is required");
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export interface TagInputProps
|
||||
extends Omit<ContextType, 'tagGroupId'>,
|
||||
extends Omit<ContextType, "tagGroupId">,
|
||||
TextFieldProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
|
|
@ -50,7 +50,7 @@ export function TagsInputField({
|
|||
name={name}
|
||||
hidden
|
||||
readOnly
|
||||
value={list.items.map(({ name }) => name).join(',')}
|
||||
value={list.items.map(({ name }) => name).join(",")}
|
||||
/>
|
||||
)}
|
||||
</TagInputContext.Provider>
|
||||
|
|
@ -63,7 +63,7 @@ export function TagsInput({
|
|||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
const [inputValue, setInputValue] = React.useState('');
|
||||
const [inputValue, setInputValue] = React.useState("");
|
||||
const { list, onTagAdd, onTagRemove } = useTagInputContext();
|
||||
|
||||
const deleteLast = React.useCallback(() => {
|
||||
|
|
@ -84,12 +84,12 @@ export function TagsInput({
|
|||
}, [list, onTagRemove]);
|
||||
|
||||
function handleKeyDown(e: React.KeyboardEvent) {
|
||||
if (e.key === 'Enter' || e.key === ',' || e.key === ';') {
|
||||
if (e.key === "Enter" || e.key === "," || e.key === ";") {
|
||||
e.preventDefault();
|
||||
addTag();
|
||||
}
|
||||
|
||||
if (e.key === 'Backspace' && inputValue === '') {
|
||||
if (e.key === "Backspace" && inputValue === "") {
|
||||
deleteLast();
|
||||
}
|
||||
}
|
||||
|
|
@ -100,21 +100,21 @@ export function TagsInput({
|
|||
tagNames.forEach((tagName) => {
|
||||
const formattedName = tagName
|
||||
.trim()
|
||||
.replace(/\s\s+/g, ' ')
|
||||
.replace(/\t|\\t|\r|\\r|\n|\\n/g, '');
|
||||
.replace(/\s\s+/g, " ")
|
||||
.replace(/\t|\\t|\r|\\r|\n|\\n/g, "");
|
||||
|
||||
if (formattedName === '') {
|
||||
if (formattedName === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasTagExists = list.items.find(
|
||||
({ name }) =>
|
||||
name.toLocaleLowerCase() === formattedName.toLocaleLowerCase(),
|
||||
name.toLocaleLowerCase() === formattedName.toLocaleLowerCase()
|
||||
);
|
||||
|
||||
if (!hasTagExists) {
|
||||
const tag = {
|
||||
id: (list.items.at(-1)?.id || 0) + 1,
|
||||
id: (list.items[list.items.length - 1]?.id || 0) + 1,
|
||||
name: formattedName,
|
||||
};
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ export function TagsInput({
|
|||
}
|
||||
});
|
||||
|
||||
setInputValue('');
|
||||
setInputValue("");
|
||||
}
|
||||
|
||||
function handleRemove(keys: Set<Key>) {
|
||||
|
|
@ -143,15 +143,15 @@ export function TagsInput({
|
|||
<TagGroup
|
||||
aria-labelledby={labelId}
|
||||
onRemove={handleRemove}
|
||||
className={twMerge(className, 'w-full')}
|
||||
className={twMerge(className, "w-full")}
|
||||
data-ui="control"
|
||||
>
|
||||
<div
|
||||
className={twMerge(
|
||||
'flex min-h-9 items-center rounded-md',
|
||||
'border has-[input[data-focused=true]]:border-ring',
|
||||
'has-[input[data-invalid=true][data-focused=true]]:border-ring has-[input[data-invalid=true]]:border-destructive',
|
||||
'has-[input[data-focused=true]]:ring-1 has-[input[data-focused=true]]:ring-ring',
|
||||
"flex min-h-9 items-center rounded-md",
|
||||
"border has-[input[data-focused=true]]:border-ring",
|
||||
"has-[input[data-invalid=true][data-focused=true]]:border-ring has-[input[data-invalid=true]]:border-destructive",
|
||||
"has-[input[data-focused=true]]:ring-1 has-[input[data-focused=true]]:ring-ring"
|
||||
)}
|
||||
>
|
||||
<div className="inline-flex flex-1 flex-wrap items-center gap-1 px-2 py-[5px]">
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useToastQueue } from '@react-stately/toast';
|
||||
import type { AriaToastRegionProps, ToastAria } from '@react-aria/toast';
|
||||
import type { ToastState } from '@react-stately/toast';
|
||||
import { useToastRegion } from '@react-aria/toast';
|
||||
import type { AriaToastProps } from '@react-aria/toast';
|
||||
import { useToast } from '@react-aria/toast';
|
||||
import React from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useToastQueue } from "@react-stately/toast";
|
||||
import type { AriaToastRegionProps, ToastAria } from "@react-aria/toast";
|
||||
import type { ToastState } from "@react-stately/toast";
|
||||
import { useToastRegion } from "@react-aria/toast";
|
||||
import type { AriaToastProps } from "@react-aria/toast";
|
||||
import { useToast } from "@react-aria/toast";
|
||||
import {
|
||||
ButtonProps as AriaButtonProps,
|
||||
composeRenderProps,
|
||||
} from 'react-aria-components';
|
||||
import { Button, ButtonProps } from '../button';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { toast, ToastConfig } from './toast-queue';
|
||||
} from "react-aria-components";
|
||||
import { Button, ButtonProps } from "../button";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { toast, ToastConfig } from "./toast-queue";
|
||||
import {
|
||||
CircleCheckIcon,
|
||||
CircleInfoIcon,
|
||||
CircleXIcon,
|
||||
OctagonAlertIcon,
|
||||
XIcon,
|
||||
} from '../icons';
|
||||
} from "../icons";
|
||||
|
||||
interface ToastRegionProps extends AriaToastRegionProps {
|
||||
state: ToastState<ToastConfig>;
|
||||
|
|
@ -35,24 +35,24 @@ function ToastRegion({ state, ...props }: ToastRegionProps) {
|
|||
|
||||
const position =
|
||||
state.visibleToasts[state.visibleToasts.length - 1].content.position ??
|
||||
'bottom-right';
|
||||
"bottom-right";
|
||||
|
||||
let className = 'bottom-6 right-6 anim ';
|
||||
let className = "bottom-6 right-6 anim ";
|
||||
switch (position) {
|
||||
case 'bottom-left':
|
||||
className = 'bottom-6 left-6';
|
||||
case "bottom-left":
|
||||
className = "bottom-6 left-6";
|
||||
break;
|
||||
case 'bottom-center':
|
||||
className = 'bottom-6 left-1/2 -translate-x-1/2';
|
||||
case "bottom-center":
|
||||
className = "bottom-6 left-1/2 -translate-x-1/2";
|
||||
break;
|
||||
case 'top-left':
|
||||
className = 'top-6 left-6 ';
|
||||
case "top-left":
|
||||
className = "top-6 left-6 ";
|
||||
break;
|
||||
case 'top-center':
|
||||
className = 'top-6 left-1/2 -translate-x-1/2';
|
||||
case "top-center":
|
||||
className = "top-6 left-1/2 -translate-x-1/2";
|
||||
break;
|
||||
case 'top-right':
|
||||
className = 'top-6 right-6';
|
||||
case "top-right":
|
||||
className = "top-6 right-6";
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -64,8 +64,8 @@ function ToastRegion({ state, ...props }: ToastRegionProps) {
|
|||
{...regionProps}
|
||||
ref={ref}
|
||||
className={twMerge(
|
||||
'toast-region fixed isolate z-20 flex flex-col gap-2 outline-hidden',
|
||||
className,
|
||||
"toast-region fixed isolate z-20 flex flex-col gap-2 outline-hidden",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{state.visibleToasts.map((toast) => (
|
||||
|
|
@ -90,34 +90,37 @@ function Toast({ state, ...props }: ToastProps) {
|
|||
titleProps,
|
||||
closeButtonProps,
|
||||
descriptionProps,
|
||||
}: Omit<ToastAria, 'closeButtonProps'> & {
|
||||
closeButtonProps: Omit<AriaButtonProps, 'children'>;
|
||||
}: Omit<ToastAria, "closeButtonProps"> & {
|
||||
closeButtonProps: Omit<AriaButtonProps, "children">;
|
||||
} = useToast(props, state, ref);
|
||||
|
||||
let enteringClassName = '';
|
||||
const position = props.toast.content.position ?? 'bottom-right';
|
||||
let enteringClassName = "";
|
||||
const position = props.toast.content.position ?? "bottom-right";
|
||||
|
||||
switch (position) {
|
||||
case 'bottom-right':
|
||||
case 'top-right':
|
||||
case "bottom-right":
|
||||
case "top-right":
|
||||
enteringClassName =
|
||||
props.toast.animation === 'entering'
|
||||
? 'duration-200 slide-in-from-right animate-in ease-out'
|
||||
: '';
|
||||
// @ts-ignore
|
||||
props.toast.animation === "entering"
|
||||
? "duration-200 slide-in-from-right animate-in ease-out"
|
||||
: "";
|
||||
break;
|
||||
case 'bottom-left':
|
||||
case 'top-left':
|
||||
case "bottom-left":
|
||||
case "top-left":
|
||||
enteringClassName =
|
||||
props.toast.animation === 'entering'
|
||||
? 'duration-200 slide-in-from-left animate-in ease-out'
|
||||
: '';
|
||||
// @ts-ignore
|
||||
props.toast.animation === "entering"
|
||||
? "duration-200 slide-in-from-left animate-in ease-out"
|
||||
: "";
|
||||
break;
|
||||
case 'bottom-center':
|
||||
case 'top-center':
|
||||
case "bottom-center":
|
||||
case "top-center":
|
||||
enteringClassName =
|
||||
props.toast.animation === 'entering'
|
||||
? 'duration-200 slide-in-from-top animate-in ease-out'
|
||||
: '';
|
||||
// @ts-ignore
|
||||
props.toast.animation === "entering"
|
||||
? "duration-200 slide-in-from-top animate-in ease-out"
|
||||
: "";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -130,13 +133,13 @@ function Toast({ state, ...props }: ToastProps) {
|
|||
{...toastProps}
|
||||
ref={ref}
|
||||
className={twMerge(
|
||||
'relative isolate flex w-[min(85vw,360px)] space-x-1 rounded-lg shadow-xs transition',
|
||||
'flex flex-1 rounded-ld bg-zinc-900 outline-hidden',
|
||||
type ? 'px-2.5' : 'px-4',
|
||||
'py-2.5',
|
||||
"relative isolate flex w-[min(85vw,360px)] space-x-1 rounded-lg shadow-xs transition",
|
||||
"flex flex-1 rounded-ld bg-zinc-900 outline-hidden",
|
||||
type ? "px-2.5" : "px-4",
|
||||
"py-2.5",
|
||||
!props.toast.content.render &&
|
||||
'border border-zinc-950 dark:border-zinc-800',
|
||||
enteringClassName,
|
||||
"border border-zinc-950 dark:border-zinc-800",
|
||||
enteringClassName
|
||||
)}
|
||||
>
|
||||
{props.toast.content.render ? (
|
||||
|
|
@ -144,19 +147,19 @@ function Toast({ state, ...props }: ToastProps) {
|
|||
) : (
|
||||
<>
|
||||
<div className="flex flex-1 items-center space-x-2.5 self-center">
|
||||
{type === 'info' && (
|
||||
{type === "info" && (
|
||||
<CircleInfoIcon className="mt-1 size-5 self-start text-blue-500" />
|
||||
)}
|
||||
|
||||
{type === 'error' && (
|
||||
{type === "error" && (
|
||||
<CircleXIcon className="mt-1 size-5 self-start text-destructive" />
|
||||
)}
|
||||
|
||||
{type === 'warning' && (
|
||||
{type === "warning" && (
|
||||
<OctagonAlertIcon className="mt-1 size-5 self-start text-warning" />
|
||||
)}
|
||||
|
||||
{type === 'success' && (
|
||||
{type === "success" && (
|
||||
<CircleCheckIcon className="mt-1 size-5 self-start text-success" />
|
||||
)}
|
||||
|
||||
|
|
@ -166,7 +169,7 @@ function Toast({ state, ...props }: ToastProps) {
|
|||
{...titleProps}
|
||||
className={twMerge(
|
||||
props.toast.content.description &&
|
||||
'text-sm/6 font-medium text-zinc-50',
|
||||
"text-sm/6 font-medium text-zinc-50"
|
||||
)}
|
||||
>
|
||||
{props.toast.content.title}
|
||||
|
|
@ -206,16 +209,13 @@ function Toast({ state, ...props }: ToastProps) {
|
|||
);
|
||||
}
|
||||
|
||||
export function ToastAction({
|
||||
variant = 'unstyle',
|
||||
...props
|
||||
}: ButtonProps) {
|
||||
export function ToastAction({ variant = "unstyle", ...props }: ButtonProps) {
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
variant={variant}
|
||||
className={composeRenderProps(props.className, (className) => {
|
||||
return twMerge('text-base/6 text-zinc-50 sm:text-sm/6', className);
|
||||
return twMerge("text-base/6 text-zinc-50 sm:text-sm/6", className);
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
4949
ui/stats.html
Normal file
4949
ui/stats.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue