;
export const input = tv({
- base: "py-[6px] bg-secondary border border-border-mid rounded-[10px] hover:border-border-strong focus:shadow-focus text-sm px-3 w-full bg-secondary disabled:bg-transparent focus:outline-none",
+ base: "py-[6px] bg-secondary border border-border-mid rounded-[10px] hover:border-border-strong focus:shadow-focus text-sm px-3 w-full bg-secondary disabled:bg-transparent focus:outline-none data-[focus=true]:shadow-focus",
variants: {
invalid: {
true: "border-border-danger",
@@ -15,6 +18,41 @@ export const input = tv({
},
});
-export function Input({ invalid, ...props }: Props) {
+export function Input({
+ invalid,
+ icon: IconComponent,
+ onValueChange,
+ ...props
+}: Props) {
+ if (IconComponent) {
+ const [focus, setFocus] = useState(false);
+ return (
+
+
+ {
+ setFocus(true);
+ props.onFocus?.(e);
+ }}
+ onBlur={(e) => {
+ setFocus(false);
+ props.onBlur?.(e);
+ }}
+ aria-invalid={invalid}
+ className="w-full outline-none"
+ {...props}
+ onChange={(e) => {
+ onValueChange?.(e.currentTarget.value);
+ props.onChange?.(e);
+ }}
+ />
+
+ );
+ }
return ;
}
diff --git a/packages/ui/src/Atoms/Spinner/Spinner.tsx b/packages/ui/src/Atoms/Spinner/Spinner.tsx
index 0cfa047d7..f0ec16424 100644
--- a/packages/ui/src/Atoms/Spinner/Spinner.tsx
+++ b/packages/ui/src/Atoms/Spinner/Spinner.tsx
@@ -1,11 +1,15 @@
import clsx from "clsx";
-type Props = { size: number; className?: string };
+type Props = { size?: number; className?: string; centered?: boolean };
-export function Spinner({ size = 16, className }: Props) {
+export function Spinner({ size = 16, className, centered }: Props) {
return (
);
diff --git a/packages/ui/src/Atoms/Tabs/Tabs.stories.tsx b/packages/ui/src/Atoms/Tabs/Tabs.stories.tsx
new file mode 100644
index 000000000..348be5a8e
--- /dev/null
+++ b/packages/ui/src/Atoms/Tabs/Tabs.stories.tsx
@@ -0,0 +1,20 @@
+import { Tabs, TabLink } from "./Tabs";
+import type { Meta, StoryObj } from "@storybook/react";
+
+export default {
+ title: "Atoms/Tabs",
+ component: Tabs,
+ argTypes: {},
+} satisfies Meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+ Tab 1
+ Tab 2
+ Tab 3
+
+ ),
+};
diff --git a/packages/ui/src/Atoms/Tabs/Tabs.tsx b/packages/ui/src/Atoms/Tabs/Tabs.tsx
new file mode 100644
index 000000000..bc781ddf9
--- /dev/null
+++ b/packages/ui/src/Atoms/Tabs/Tabs.tsx
@@ -0,0 +1,33 @@
+import type { PropsWithChildren } from "react";
+import { NavLink } from "react-router";
+import { Root, List } from "@radix-ui/react-tabs";
+import clsx from "clsx";
+
+export function Tabs(props: PropsWithChildren) {
+ return (
+
+
+
+
+
+ );
+}
+
+export function TabLink(props: PropsWithChildren<{ to: string }>) {
+ return (
+
+ clsx(
+ "py-4 hover:text-txt-primary border-b-2 active:border-border-active -mb-[1px] active:text-txt-primary",
+ params.isActive
+ ? "border-border-active text-txt-primary"
+ : "border-transparent",
+ )
+ }
+ {...props}
+ />
+ );
+}
diff --git a/packages/ui/src/Molecules/Dialog/Dialog.tsx b/packages/ui/src/Molecules/Dialog/Dialog.tsx
index aac6d0fbf..20638448e 100644
--- a/packages/ui/src/Molecules/Dialog/Dialog.tsx
+++ b/packages/ui/src/Molecules/Dialog/Dialog.tsx
@@ -70,23 +70,35 @@ export function Dialog({
);
}
-export function DialogFooter({ children }: { children?: ReactNode }) {
+export function DialogFooter({
+ children,
+ exitLabel,
+}: {
+ children?: ReactNode;
+ exitLabel?: string;
+}) {
const { __ } = useTranslate();
return (
);
}
-export function DialogContent(props: HTMLAttributes) {
+export function DialogContent(
+ props: HTMLAttributes & { padded?: boolean },
+) {
return (