@krrli/cm-designsystem 1.1.0 → 1.19.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +422 -2
- package/dist/components/avatar/Avatar.d.ts +71 -0
- package/dist/components/avatar/Avatar.js +63 -0
- package/dist/components/branding/BrandingGallery.d.ts +1 -0
- package/dist/components/branding/BrandingGallery.js +139 -0
- package/dist/components/button/Button.d.ts +54 -0
- package/dist/components/button/Button.js +56 -0
- package/dist/components/button/Button.test.d.ts +1 -0
- package/dist/components/button/Button.test.js +30 -0
- package/dist/components/color/ColorDoc.d.ts +4 -0
- package/dist/components/color/ColorDoc.js +10 -0
- package/dist/components/file-upload/FileUpload.d.ts +83 -0
- package/dist/components/file-upload/FileUpload.js +70 -0
- package/dist/components/form/Form.d.ts +54 -0
- package/dist/components/form/Form.js +38 -0
- package/dist/components/icon-button/IconButton.d.ts +50 -0
- package/dist/components/icon-button/IconButton.js +22 -0
- package/dist/components/icon-button/IconButton.test.d.ts +1 -0
- package/dist/components/icon-button/IconButton.test.js +22 -0
- package/dist/components/icons/IconBase.d.ts +5 -0
- package/dist/components/icons/IconBase.js +9 -0
- package/dist/components/icons/generated/ArrowDown.d.ts +3 -0
- package/dist/components/icons/generated/ArrowDown.js +4 -0
- package/dist/components/icons/generated/ArrowLeft.d.ts +3 -0
- package/dist/components/icons/generated/ArrowLeft.js +4 -0
- package/dist/components/icons/generated/ArrowRight.d.ts +3 -0
- package/dist/components/icons/generated/ArrowRight.js +4 -0
- package/dist/components/icons/generated/ArrowUp.d.ts +3 -0
- package/dist/components/icons/generated/ArrowUp.js +4 -0
- package/dist/components/icons/generated/Calendar.d.ts +3 -0
- package/dist/components/icons/generated/Calendar.js +4 -0
- package/dist/components/icons/generated/Cancel.d.ts +3 -0
- package/dist/components/icons/generated/Cancel.js +4 -0
- package/dist/components/icons/generated/Checkmark.d.ts +3 -0
- package/dist/components/icons/generated/Checkmark.js +4 -0
- package/dist/components/icons/generated/Edit.d.ts +3 -0
- package/dist/components/icons/generated/Edit.js +4 -0
- package/dist/components/icons/generated/Eye.d.ts +3 -0
- package/dist/components/icons/generated/Eye.js +4 -0
- package/dist/components/icons/generated/Fullscreen.d.ts +3 -0
- package/dist/components/icons/generated/Fullscreen.js +4 -0
- package/dist/components/icons/generated/HeartFilled.d.ts +3 -0
- package/dist/components/icons/generated/HeartFilled.js +4 -0
- package/dist/components/icons/generated/HeartOutline.d.ts +3 -0
- package/dist/components/icons/generated/HeartOutline.js +4 -0
- package/dist/components/icons/generated/Location.d.ts +3 -0
- package/dist/components/icons/generated/Location.js +4 -0
- package/dist/components/icons/generated/LogOut.d.ts +3 -0
- package/dist/components/icons/generated/LogOut.js +4 -0
- package/dist/components/icons/generated/Mumble.d.ts +3 -0
- package/dist/components/icons/generated/Mumble.js +4 -0
- package/dist/components/icons/generated/Profile.d.ts +3 -0
- package/dist/components/icons/generated/Profile.js +4 -0
- package/dist/components/icons/generated/ReplyFilled.d.ts +3 -0
- package/dist/components/icons/generated/ReplyFilled.js +4 -0
- package/dist/components/icons/generated/ReplyOutline.d.ts +3 -0
- package/dist/components/icons/generated/ReplyOutline.js +4 -0
- package/dist/components/icons/generated/Repost.d.ts +3 -0
- package/dist/components/icons/generated/Repost.js +4 -0
- package/dist/components/icons/generated/Send.d.ts +3 -0
- package/dist/components/icons/generated/Send.js +4 -0
- package/dist/components/icons/generated/Settings.d.ts +3 -0
- package/dist/components/icons/generated/Settings.js +4 -0
- package/dist/components/icons/generated/Share.d.ts +3 -0
- package/dist/components/icons/generated/Share.js +4 -0
- package/dist/components/icons/generated/Time.d.ts +3 -0
- package/dist/components/icons/generated/Time.js +4 -0
- package/dist/components/icons/generated/Upload.d.ts +3 -0
- package/dist/components/icons/generated/Upload.js +4 -0
- package/dist/components/icons/generated/index.d.ts +24 -0
- package/dist/components/icons/generated/index.js +24 -0
- package/dist/components/index.d.ts +25 -0
- package/dist/components/index.js +25 -0
- package/dist/components/input/Input.d.ts +61 -0
- package/dist/components/input/Input.js +47 -0
- package/dist/components/like-toggle/LikeToggle.d.ts +97 -0
- package/dist/components/like-toggle/LikeToggle.js +185 -0
- package/dist/components/like-toggle/LikeToggle.test.d.ts +1 -0
- package/dist/components/like-toggle/LikeToggle.test.js +35 -0
- package/dist/components/modal/Modal.d.ts +75 -0
- package/dist/components/modal/Modal.js +63 -0
- package/dist/components/modal/Modal.test.d.ts +1 -0
- package/dist/components/modal/Modal.test.js +24 -0
- package/dist/components/navi-button/NaviButton.d.ts +26 -0
- package/dist/components/navi-button/NaviButton.js +29 -0
- package/dist/components/navi-button/NaviButton.test.d.ts +1 -0
- package/dist/components/navi-button/NaviButton.test.js +22 -0
- package/dist/components/navi-user-button/NaviUserButton.d.ts +26 -0
- package/dist/components/navi-user-button/NaviUserButton.js +29 -0
- package/dist/components/round-button/RoundButton.d.ts +25 -0
- package/dist/components/round-button/RoundButton.js +28 -0
- package/dist/components/round-button/RoundButton.test.d.ts +1 -0
- package/dist/components/round-button/RoundButton.test.js +21 -0
- package/dist/components/tabs/TabItem.d.ts +11 -0
- package/dist/components/tabs/TabItem.js +13 -0
- package/dist/components/tabs/Tabs.d.ts +67 -0
- package/dist/components/tabs/Tabs.js +67 -0
- package/dist/components/tabs/Tabs.test.d.ts +1 -0
- package/dist/components/tabs/Tabs.test.js +61 -0
- package/dist/components/text-link/TextLink.d.ts +9 -0
- package/dist/components/text-link/TextLink.js +15 -0
- package/dist/components/text-link/TextLink.test.d.ts +1 -0
- package/dist/components/text-link/TextLink.test.js +14 -0
- package/dist/components/textarea/Textarea.d.ts +48 -0
- package/dist/components/textarea/Textarea.js +46 -0
- package/dist/components/timed-button/TimedButton.d.ts +56 -0
- package/dist/components/timed-button/TimedButton.js +106 -0
- package/dist/components/timed-button/TimedButton.test.d.ts +1 -0
- package/dist/components/timed-button/TimedButton.test.js +35 -0
- package/dist/components/toggle/Toggle.d.ts +62 -0
- package/dist/components/toggle/Toggle.js +67 -0
- package/dist/components/toggle/Toggle.test.d.ts +1 -0
- package/dist/components/toggle/Toggle.test.js +93 -0
- package/dist/components/typography/Heading.d.ts +17 -0
- package/dist/components/typography/Heading.js +11 -0
- package/dist/components/typography/Label.d.ts +15 -0
- package/dist/components/typography/Label.js +7 -0
- package/dist/components/typography/Paragraph.d.ts +15 -0
- package/dist/components/typography/Paragraph.js +7 -0
- package/dist/components/typography/Placeholder.d.ts +13 -0
- package/dist/components/typography/Placeholder.js +7 -0
- package/dist/components/typography/ValidationMessage.d.ts +15 -0
- package/dist/components/typography/ValidationMessage.js +9 -0
- package/dist/components/typography/styles.d.ts +74 -0
- package/dist/components/typography/styles.js +52 -0
- package/dist/favicon.svg +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +7550 -0
- package/dist/index.js +2 -0
- package/dist/logo-inline-gradient.svg +43 -0
- package/dist/setupTests.d.ts +1 -0
- package/dist/setupTests.js +7 -0
- package/package.json +78 -33
- package/.github/CODEOWNERS +0 -7
- package/.github/semantic.yml +0 -24
- package/.github/workflows/publish-npm.yml +0 -29
- package/.github/workflows/storybook.yml +0 -44
- package/.releaserc.json +0 -9
- package/.storybook/main.ts +0 -19
- package/.storybook/preview.ts +0 -21
- package/.storybook/vitest.setup.ts +0 -7
- package/src/index.ts +0 -4
- package/stories/Button.stories.ts +0 -54
- package/stories/Button.tsx +0 -37
- package/stories/Button2.stories.ts +0 -54
- package/stories/Button2.tsx +0 -41
- package/stories/Configure.mdx +0 -364
- package/stories/Header.stories.ts +0 -34
- package/stories/Header.tsx +0 -56
- package/stories/Page.stories.ts +0 -33
- package/stories/Page.tsx +0 -73
- package/stories/assets/accessibility.png +0 -0
- package/stories/assets/accessibility.svg +0 -1
- package/stories/assets/addon-library.png +0 -0
- package/stories/assets/assets.png +0 -0
- package/stories/assets/avif-test-image.avif +0 -0
- package/stories/assets/context.png +0 -0
- package/stories/assets/discord.svg +0 -1
- package/stories/assets/docs.png +0 -0
- package/stories/assets/figma-plugin.png +0 -0
- package/stories/assets/github.svg +0 -1
- package/stories/assets/share.png +0 -0
- package/stories/assets/styling.png +0 -0
- package/stories/assets/testing.png +0 -0
- package/stories/assets/theming.png +0 -0
- package/stories/assets/tutorials.svg +0 -1
- package/stories/assets/youtube.svg +0 -1
- package/stories/button.css +0 -30
- package/stories/button2.css +0 -30
- package/stories/header.css +0 -32
- package/stories/page.css +0 -68
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -35
- package/vitest.shims.d.ts +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type VariantProps } from "tailwind-variants";
|
|
2
|
+
import type { IconBaseProps } from "../icons/IconBase";
|
|
3
|
+
declare const buttonStyles: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
intent: {
|
|
5
|
+
primary: string[];
|
|
6
|
+
secondary: string[];
|
|
7
|
+
tertiary: string[];
|
|
8
|
+
};
|
|
9
|
+
size: {
|
|
10
|
+
md: string[];
|
|
11
|
+
lg: string[];
|
|
12
|
+
};
|
|
13
|
+
}, undefined, string[], {
|
|
14
|
+
intent: {
|
|
15
|
+
primary: string[];
|
|
16
|
+
secondary: string[];
|
|
17
|
+
tertiary: string[];
|
|
18
|
+
};
|
|
19
|
+
size: {
|
|
20
|
+
md: string[];
|
|
21
|
+
lg: string[];
|
|
22
|
+
};
|
|
23
|
+
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
24
|
+
intent: {
|
|
25
|
+
primary: string[];
|
|
26
|
+
secondary: string[];
|
|
27
|
+
tertiary: string[];
|
|
28
|
+
};
|
|
29
|
+
size: {
|
|
30
|
+
md: string[];
|
|
31
|
+
lg: string[];
|
|
32
|
+
};
|
|
33
|
+
}, undefined, string[], unknown, unknown, undefined>>;
|
|
34
|
+
type ButtonVariants = VariantProps<typeof buttonStyles>;
|
|
35
|
+
type ButtonIntent = "primary" | "secondary" | "tertiary";
|
|
36
|
+
type ButtonSize = "md" | "lg";
|
|
37
|
+
type BaseButtonProps = ButtonVariants & {
|
|
38
|
+
intent: ButtonIntent;
|
|
39
|
+
size: ButtonSize;
|
|
40
|
+
onClick: () => void;
|
|
41
|
+
className?: string;
|
|
42
|
+
children?: React.ReactElement<IconBaseProps>;
|
|
43
|
+
};
|
|
44
|
+
type ButtonWithLabel = BaseButtonProps & {
|
|
45
|
+
label: string;
|
|
46
|
+
ariaLabel?: string;
|
|
47
|
+
};
|
|
48
|
+
type ButtonIconOnly = BaseButtonProps & {
|
|
49
|
+
label?: undefined;
|
|
50
|
+
ariaLabel: string;
|
|
51
|
+
};
|
|
52
|
+
type ButtonProps = ButtonWithLabel | ButtonIconOnly;
|
|
53
|
+
export declare const Button: (props: ButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
import { Label } from "../typography/Label";
|
|
5
|
+
const buttonStyles = tv({
|
|
6
|
+
base: [
|
|
7
|
+
"flex",
|
|
8
|
+
"gap-2",
|
|
9
|
+
"text-white",
|
|
10
|
+
"rounded-lg",
|
|
11
|
+
"hover:ring-3",
|
|
12
|
+
"hover:ring-solid",
|
|
13
|
+
"active:ring-4",
|
|
14
|
+
"transition",
|
|
15
|
+
"duration-350",
|
|
16
|
+
"active:duration-300",
|
|
17
|
+
"ease-in-out",
|
|
18
|
+
],
|
|
19
|
+
variants: {
|
|
20
|
+
intent: {
|
|
21
|
+
primary: [
|
|
22
|
+
"bg-slate-600",
|
|
23
|
+
"hover:bg-slate-700",
|
|
24
|
+
"hover:ring-slate-100",
|
|
25
|
+
"active:ring-violet-200",
|
|
26
|
+
],
|
|
27
|
+
secondary: [
|
|
28
|
+
"bg-violet-600",
|
|
29
|
+
"hover:bg-violet-700",
|
|
30
|
+
"hover:ring-violet-100",
|
|
31
|
+
"active:ring-violet-200",
|
|
32
|
+
],
|
|
33
|
+
tertiary: [
|
|
34
|
+
"bg-linear-to-r",
|
|
35
|
+
"from-pink-500",
|
|
36
|
+
"from-0%",
|
|
37
|
+
"to-100%",
|
|
38
|
+
"to-violet-600",
|
|
39
|
+
"hover:to-80%",
|
|
40
|
+
"hover:ring-violet-100",
|
|
41
|
+
"active:to-70%",
|
|
42
|
+
"active:ring-violet-200",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
size: {
|
|
46
|
+
md: ["pt-3", "pb-3", "pl-3", "pr-3"],
|
|
47
|
+
lg: ["pt-4", "pb-4", "pl-6", "pr-6"],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
export const Button = (props) => {
|
|
52
|
+
const { label, ariaLabel, children, ...rest } = props;
|
|
53
|
+
// Set aria-label when no visible label exists
|
|
54
|
+
const finalAriaLabel = label ? undefined : ariaLabel;
|
|
55
|
+
return (_jsxs("button", { ...rest, className: twMerge(props.className, buttonStyles(props)), onClick: props.onClick, "aria-label": finalAriaLabel, children: [_jsx(Label, { as: "span", size: "md", children: label }), children] }));
|
|
56
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, test, vi } from "vitest";
|
|
4
|
+
import { Mumble } from "../icons/generated";
|
|
5
|
+
import { Button } from "./Button";
|
|
6
|
+
describe("Button", () => {
|
|
7
|
+
test("should render button with icon", async () => {
|
|
8
|
+
// Arrange
|
|
9
|
+
render(_jsx(Button, { intent: "primary", size: "md", label: "button", onClick: vi.fn(), children: _jsx(Mumble, {}) }));
|
|
10
|
+
// Assert
|
|
11
|
+
expect(screen.getByRole("button")).toBeVisible();
|
|
12
|
+
expect(screen.getByRole("button")).toHaveTextContent("button");
|
|
13
|
+
expect(screen.getByText("Mumble")).toBeVisible();
|
|
14
|
+
});
|
|
15
|
+
test("should render button without icon", async () => {
|
|
16
|
+
// Arrange
|
|
17
|
+
render(_jsx(Button, { intent: "primary", size: "md", label: "button", onClick: vi.fn() }));
|
|
18
|
+
// Assert
|
|
19
|
+
expect(screen.getByRole("button")).toBeVisible();
|
|
20
|
+
expect(screen.getByRole("button")).toHaveTextContent("button");
|
|
21
|
+
expect(screen.queryByText("Mumble")).not.toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
test("should call onClick when clicked", () => {
|
|
24
|
+
// Arrange
|
|
25
|
+
const onClick = vi.fn();
|
|
26
|
+
render(_jsx(Button, { intent: "primary", size: "md", label: "button", onClick: onClick, children: _jsx(Mumble, {}) }));
|
|
27
|
+
fireEvent.click(screen.getByRole("button"));
|
|
28
|
+
expect(onClick).toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const ColorDoc = ({ colorName, colorIntensity, }) => {
|
|
3
|
+
return (_jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: `flex h-31.25 w-31.25 items-center justify-center rounded-lg bg-${getCssVariableSuffix(colorName, colorIntensity)}`, children: _jsx("span", { className: "rounded-lg bg-white p-1", children: `${getCssVariableSuffix(colorName, colorIntensity)}` }) }), _jsxs("div", { className: "flex flex-col items-center", children: [_jsx("span", { children: `--color-${getCssVariableSuffix(colorName, colorIntensity)}` }), _jsx("span", { children: `.text-${getCssVariableSuffix(colorName, colorIntensity)}` }), _jsx("span", { children: `.bg-${getCssVariableSuffix(colorName, colorIntensity)}` })] })] }));
|
|
4
|
+
};
|
|
5
|
+
const getCssVariableSuffix = (colorName, colorIntensity) => {
|
|
6
|
+
if (colorIntensity == null) {
|
|
7
|
+
return colorName;
|
|
8
|
+
}
|
|
9
|
+
return `${colorName}-${colorIntensity}`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type VariantProps } from "tailwind-variants";
|
|
2
|
+
declare const fileUploadStyles: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
[key: string]: {
|
|
4
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
5
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
6
|
+
input?: import("tailwind-merge").ClassNameValue;
|
|
7
|
+
action?: import("tailwind-merge").ClassNameValue;
|
|
8
|
+
dropzone?: import("tailwind-merge").ClassNameValue;
|
|
9
|
+
uploadIcon?: import("tailwind-merge").ClassNameValue;
|
|
10
|
+
titleText?: import("tailwind-merge").ClassNameValue;
|
|
11
|
+
subtitleText?: import("tailwind-merge").ClassNameValue;
|
|
12
|
+
preview?: import("tailwind-merge").ClassNameValue;
|
|
13
|
+
previewLabel?: import("tailwind-merge").ClassNameValue;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
} | {
|
|
17
|
+
[x: string]: {
|
|
18
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
19
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
20
|
+
input?: import("tailwind-merge").ClassNameValue;
|
|
21
|
+
action?: import("tailwind-merge").ClassNameValue;
|
|
22
|
+
dropzone?: import("tailwind-merge").ClassNameValue;
|
|
23
|
+
uploadIcon?: import("tailwind-merge").ClassNameValue;
|
|
24
|
+
titleText?: import("tailwind-merge").ClassNameValue;
|
|
25
|
+
subtitleText?: import("tailwind-merge").ClassNameValue;
|
|
26
|
+
preview?: import("tailwind-merge").ClassNameValue;
|
|
27
|
+
previewLabel?: import("tailwind-merge").ClassNameValue;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
} | {}, {
|
|
31
|
+
base: string[];
|
|
32
|
+
dropzone: string[];
|
|
33
|
+
uploadIcon: string[];
|
|
34
|
+
titleText: string[];
|
|
35
|
+
subtitleText: string[];
|
|
36
|
+
action: string[];
|
|
37
|
+
input: string[];
|
|
38
|
+
preview: string[];
|
|
39
|
+
previewLabel: string[];
|
|
40
|
+
}, undefined, {
|
|
41
|
+
[key: string]: {
|
|
42
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
43
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
44
|
+
input?: import("tailwind-merge").ClassNameValue;
|
|
45
|
+
action?: import("tailwind-merge").ClassNameValue;
|
|
46
|
+
dropzone?: import("tailwind-merge").ClassNameValue;
|
|
47
|
+
uploadIcon?: import("tailwind-merge").ClassNameValue;
|
|
48
|
+
titleText?: import("tailwind-merge").ClassNameValue;
|
|
49
|
+
subtitleText?: import("tailwind-merge").ClassNameValue;
|
|
50
|
+
preview?: import("tailwind-merge").ClassNameValue;
|
|
51
|
+
previewLabel?: import("tailwind-merge").ClassNameValue;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
} | {}, {
|
|
55
|
+
base: string[];
|
|
56
|
+
dropzone: string[];
|
|
57
|
+
uploadIcon: string[];
|
|
58
|
+
titleText: string[];
|
|
59
|
+
subtitleText: string[];
|
|
60
|
+
action: string[];
|
|
61
|
+
input: string[];
|
|
62
|
+
preview: string[];
|
|
63
|
+
previewLabel: string[];
|
|
64
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
65
|
+
base: string[];
|
|
66
|
+
dropzone: string[];
|
|
67
|
+
uploadIcon: string[];
|
|
68
|
+
titleText: string[];
|
|
69
|
+
subtitleText: string[];
|
|
70
|
+
action: string[];
|
|
71
|
+
input: string[];
|
|
72
|
+
preview: string[];
|
|
73
|
+
previewLabel: string[];
|
|
74
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
75
|
+
type FileUploadVariants = VariantProps<typeof fileUploadStyles>;
|
|
76
|
+
interface FileUploadProps extends FileUploadVariants {
|
|
77
|
+
title?: string;
|
|
78
|
+
subtitle?: string;
|
|
79
|
+
actionLabel?: string;
|
|
80
|
+
onFileSelect: (file: File | null) => void;
|
|
81
|
+
}
|
|
82
|
+
export declare const FileUpload: ({ title, subtitle, actionLabel, ...props }: FileUploadProps) => import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
import { Button } from "../button/Button";
|
|
5
|
+
import { Cancel, Upload } from "../icons/generated";
|
|
6
|
+
import { Label } from "../typography/Label";
|
|
7
|
+
import { Paragraph } from "../typography/Paragraph";
|
|
8
|
+
const fileUploadStyles = tv({
|
|
9
|
+
slots: {
|
|
10
|
+
base: ["flex", "flex-col", "items-center", "gap-4"],
|
|
11
|
+
dropzone: [
|
|
12
|
+
"flex",
|
|
13
|
+
"w-full",
|
|
14
|
+
"cursor-pointer",
|
|
15
|
+
"flex-col",
|
|
16
|
+
"items-center",
|
|
17
|
+
"justify-center",
|
|
18
|
+
"gap-2",
|
|
19
|
+
"rounded-xl",
|
|
20
|
+
"border-2",
|
|
21
|
+
"border-dashed",
|
|
22
|
+
"border-slate-200",
|
|
23
|
+
"pt-12",
|
|
24
|
+
"pr-4",
|
|
25
|
+
"pb-12",
|
|
26
|
+
"pl-4",
|
|
27
|
+
],
|
|
28
|
+
uploadIcon: ["h-8", "w-8", "text-slate-500"],
|
|
29
|
+
titleText: ["text-slate-500"],
|
|
30
|
+
subtitleText: ["text-slate-500"],
|
|
31
|
+
action: [
|
|
32
|
+
"flex",
|
|
33
|
+
"w-full",
|
|
34
|
+
"items-center",
|
|
35
|
+
"justify-center",
|
|
36
|
+
"bg-slate-300",
|
|
37
|
+
"text-slate-600",
|
|
38
|
+
"hover:bg-slate-300",
|
|
39
|
+
],
|
|
40
|
+
input: ["hidden"],
|
|
41
|
+
preview: ["flex", "items-center", "gap-2"],
|
|
42
|
+
previewLabel: ["truncate"],
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
export const FileUpload = ({ title = "Drag & Drop your File", subtitle = "JPEG or PNG, max. 50 MB", actionLabel = ".. or select your File", ...props }) => {
|
|
46
|
+
const { base, dropzone, titleText, subtitleText, uploadIcon, action, input, preview, previewLabel, } = fileUploadStyles(props);
|
|
47
|
+
const [file, setFile] = useState(null);
|
|
48
|
+
const handleFileChange = (e) => {
|
|
49
|
+
const selected = e.target.files?.[0] || null;
|
|
50
|
+
if (selected) {
|
|
51
|
+
setFile(selected);
|
|
52
|
+
props.onFileSelect(selected);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const handleDrop = (e) => {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
if (e.dataTransfer.files?.[0]) {
|
|
58
|
+
setFile(e.dataTransfer.files[0]);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const handleDragOver = (e) => {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
};
|
|
64
|
+
return (_jsxs("div", { className: base(props), children: [_jsxs("div", { role: "region", "aria-label": "File upload dropzone", className: dropzone(props), onDrop: handleDrop, onDragOver: handleDragOver, onClick: () => document.getElementById("fileInput")?.click(), onKeyDown: (e) => {
|
|
65
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
document.getElementById("fileInput")?.click();
|
|
68
|
+
}
|
|
69
|
+
}, children: [_jsx(Upload, { className: uploadIcon(props) }), _jsx(Label, { size: "xl", className: titleText(props), children: title }), _jsx(Paragraph, { size: "md", className: subtitleText(props), children: subtitle })] }), _jsx(Button, { className: action(props), intent: "primary", size: "md", label: actionLabel, onClick: () => document.getElementById("fileInput")?.click(), children: _jsx(Upload, {}) }), _jsx("input", { id: "fileInput", "aria-label": title, type: "file", accept: ".jpg,.png", className: input(props), onChange: handleFileChange }), file && (_jsxs("div", { className: preview(props), children: [_jsx(Label, { size: "md", className: previewLabel(props), children: file.name }), _jsx(Cancel, { onClick: () => setFile(null) })] }))] }));
|
|
70
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type VariantProps } from "tailwind-variants";
|
|
3
|
+
declare const formStyles: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
[key: string]: {
|
|
5
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
6
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
7
|
+
fields?: import("tailwind-merge").ClassNameValue;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
} | {
|
|
11
|
+
[x: string]: {
|
|
12
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
13
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
14
|
+
fields?: import("tailwind-merge").ClassNameValue;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
} | {}, {
|
|
18
|
+
base: string[];
|
|
19
|
+
fields: string[];
|
|
20
|
+
}, undefined, {
|
|
21
|
+
[key: string]: {
|
|
22
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
23
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
24
|
+
fields?: import("tailwind-merge").ClassNameValue;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
} | {}, {
|
|
28
|
+
base: string[];
|
|
29
|
+
fields: string[];
|
|
30
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
31
|
+
base: string[];
|
|
32
|
+
fields: string[];
|
|
33
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
34
|
+
type FormVariants = VariantProps<typeof formStyles>;
|
|
35
|
+
interface FormProps extends FormVariants {
|
|
36
|
+
children?: React.ReactNode;
|
|
37
|
+
}
|
|
38
|
+
export declare const Form: React.FC<FormProps> & {
|
|
39
|
+
Fields: typeof FormFields;
|
|
40
|
+
Action: typeof FormAction;
|
|
41
|
+
};
|
|
42
|
+
export declare function FormFields({ children }: {
|
|
43
|
+
children: React.ReactNode;
|
|
44
|
+
}): React.ReactNode;
|
|
45
|
+
export declare namespace FormFields {
|
|
46
|
+
var displayName: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function FormAction({ children }: {
|
|
49
|
+
children: React.ReactElement;
|
|
50
|
+
}): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
|
|
51
|
+
export declare namespace FormAction {
|
|
52
|
+
var displayName: string;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as RadixForm from "@radix-ui/react-form";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
const formStyles = tv({
|
|
6
|
+
slots: {
|
|
7
|
+
base: ["gap-16", "flex", "flex-col"],
|
|
8
|
+
fields: ["gap-4", "flex", "flex-col"],
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
export const Form = (props) => {
|
|
12
|
+
const { base, fields } = formStyles(props);
|
|
13
|
+
let fieldElements = null;
|
|
14
|
+
let actionElement = null;
|
|
15
|
+
React.Children.forEach(props.children, (child) => {
|
|
16
|
+
if (!React.isValidElement(child))
|
|
17
|
+
return;
|
|
18
|
+
switch (child.type) {
|
|
19
|
+
case FormFields:
|
|
20
|
+
fieldElements = child;
|
|
21
|
+
break;
|
|
22
|
+
case FormAction:
|
|
23
|
+
actionElement = child;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return (_jsxs(RadixForm.Root, { className: base(), children: [_jsx("div", { className: fields(), children: fieldElements }), _jsx(RadixForm.Submit, { asChild: true, children: actionElement })] }));
|
|
28
|
+
};
|
|
29
|
+
FormFields.displayName = "FormField";
|
|
30
|
+
export function FormFields({ children }) {
|
|
31
|
+
return children;
|
|
32
|
+
}
|
|
33
|
+
FormAction.displayName = "ModalActions";
|
|
34
|
+
export function FormAction({ children }) {
|
|
35
|
+
return children;
|
|
36
|
+
}
|
|
37
|
+
Form.Fields = FormFields;
|
|
38
|
+
Form.Action = FormAction;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type VariantProps } from "tailwind-variants";
|
|
3
|
+
import type { IconBaseProps } from "../icons/IconBase";
|
|
4
|
+
declare const iconButtonStyles: import("tailwind-variants").TVReturnType<{
|
|
5
|
+
intent: {
|
|
6
|
+
primary: {
|
|
7
|
+
base: string[];
|
|
8
|
+
};
|
|
9
|
+
secondary: {
|
|
10
|
+
base: string[];
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
}, {
|
|
14
|
+
base: string[];
|
|
15
|
+
icon: string[];
|
|
16
|
+
}, undefined, {
|
|
17
|
+
intent: {
|
|
18
|
+
primary: {
|
|
19
|
+
base: string[];
|
|
20
|
+
};
|
|
21
|
+
secondary: {
|
|
22
|
+
base: string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
}, {
|
|
26
|
+
base: string[];
|
|
27
|
+
icon: string[];
|
|
28
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
29
|
+
intent: {
|
|
30
|
+
primary: {
|
|
31
|
+
base: string[];
|
|
32
|
+
};
|
|
33
|
+
secondary: {
|
|
34
|
+
base: string[];
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}, {
|
|
38
|
+
base: string[];
|
|
39
|
+
icon: string[];
|
|
40
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
41
|
+
type IconButtonVariants = VariantProps<typeof iconButtonStyles>;
|
|
42
|
+
type IconButtonIntent = "primary" | "secondary";
|
|
43
|
+
interface IconButtonProps extends IconButtonVariants {
|
|
44
|
+
label: string;
|
|
45
|
+
intent: IconButtonIntent;
|
|
46
|
+
onClick: () => void;
|
|
47
|
+
children: React.ReactElement<IconBaseProps>;
|
|
48
|
+
}
|
|
49
|
+
export declare const IconButton: (props: IconButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
import { Label } from "../typography/Label";
|
|
5
|
+
const iconButtonStyles = tv({
|
|
6
|
+
slots: {
|
|
7
|
+
base: ["flex", "gap-1", "transition", "duration-350", "ease-in-out"],
|
|
8
|
+
icon: ["w-3", "h-3"],
|
|
9
|
+
},
|
|
10
|
+
variants: {
|
|
11
|
+
intent: {
|
|
12
|
+
primary: { base: ["text-slate-500", "hover:text-slate-600"] },
|
|
13
|
+
secondary: { base: ["text-violet-600", "hover:text-violet-900"] },
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
export const IconButton = (props) => {
|
|
18
|
+
const { base, icon } = iconButtonStyles();
|
|
19
|
+
return (_jsxs("button", { className: base(props), onClick: props.onClick, "aria-label": props.label, children: [React.cloneElement(props.children, {
|
|
20
|
+
className: `${icon(props)}`,
|
|
21
|
+
}), _jsx(Label, { as: "span", size: "sm", children: props.label })] }));
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
import { describe, expect, test, vi } from "vitest";
|
|
4
|
+
import { Profile } from "../icons/generated";
|
|
5
|
+
import { IconButton } from "./IconButton";
|
|
6
|
+
describe("IconButton", () => {
|
|
7
|
+
test("should render icon-button with icon", async () => {
|
|
8
|
+
// Arrange
|
|
9
|
+
render(_jsx(IconButton, { intent: "primary", label: "button", onClick: vi.fn(), children: _jsx(Profile, {}) }));
|
|
10
|
+
// Assert
|
|
11
|
+
expect(screen.getByRole("button")).toBeVisible();
|
|
12
|
+
expect(screen.getByRole("button")).toHaveTextContent("button");
|
|
13
|
+
expect(screen.getByText("Profile")).toBeVisible();
|
|
14
|
+
});
|
|
15
|
+
test("should call onClick when clicked", () => {
|
|
16
|
+
// Arrange
|
|
17
|
+
const onClick = vi.fn();
|
|
18
|
+
render(_jsx(IconButton, { intent: "primary", label: "button", onClick: onClick, children: _jsx(Profile, {}) }));
|
|
19
|
+
fireEvent.click(screen.getByRole("button"));
|
|
20
|
+
expect(onClick).toHaveBeenCalled();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// src/components/icons/IconBase.tsx
|
|
3
|
+
import { AccessibleIcon } from "@radix-ui/react-accessible-icon";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { tv } from "tailwind-variants";
|
|
6
|
+
const iconStyles = tv({
|
|
7
|
+
base: ["w-4", "h-4"],
|
|
8
|
+
});
|
|
9
|
+
export const IconBase = ({ label = "", children, ...props }) => (_jsx(AccessibleIcon, { label: label, children: _jsx("svg", { className: iconStyles(), fill: "currentColor", viewBox: props.viewBox || "0 0 16 16", ...props, children: children }) }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const ArrowDown = (props) => (_jsxs(IconBase, { label: "ArrowDown", ...props, children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { fill: "currentColor", d: "M12 9H9V1a1 1 0 0 0-2 0v8H4a1 1 0 0 0-.78 1.625l4 5a1 1 0 0 0 1.561 0l4-5A1 1 0 0 0 12.001 9" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const ArrowLeft = (props) => (_jsxs(IconBase, { label: "ArrowLeft", ...props, children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { fill: "currentColor", d: "M15 7H7V4a1 1 0 0 0-1.625-.781l-5 4a1 1 0 0 0 0 1.562l5 4A1 1 0 0 0 7 12V9h8a1 1 0 0 0 0-2" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const ArrowRight = (props) => (_jsxs(IconBase, { label: "ArrowRight", ...props, children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { fill: "currentColor", d: "M10.625 3.219A1 1 0 0 0 9 3.999v3H1a1 1 0 1 0 0 2h8v3a1 1 0 0 0 1.625.782l5-4a1 1 0 0 0 0-1.562z" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const ArrowUp = (props) => (_jsxs(IconBase, { label: "ArrowUp", ...props, children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { fill: "currentColor", d: "M8.781.375a1.036 1.036 0 0 0-1.562 0l-4 5A1 1 0 0 0 4 7h3v8a1 1 0 1 0 2 0V7h3a1 1 0 0 0 .781-1.625z" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const Calendar = (props) => (_jsxs(IconBase, { label: "Calendar", ...props, children: [_jsx("g", { clipPath: "url(#a)", children: _jsx("path", { fill: "currentColor", d: "M14 3h-1V1a1 1 0 0 0-2 0v2H5V1a1 1 0 0 0-2 0v2H2a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2M2 14V7h12v7z" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const Cancel = (props) => (_jsx(IconBase, { label: "Cancel", ...props, children: _jsx("path", { fill: "currentColor", d: "M12.558 1.258a.5.5 0 0 0-.711.004L8 5.2 4.154 1.262a.5.5 0 0 0-.712-.004L1.258 3.442a.5.5 0 0 0 .004.712L5.2 8l-3.938 3.847a.5.5 0 0 0-.004.71l2.184 2.185a.5.5 0 0 0 .712-.004L8 10.8l3.847 3.938a.5.5 0 0 0 .71.004l2.185-2.184a.5.5 0 0 0-.004-.711L10.8 8l3.938-3.846a.5.5 0 0 0 .004-.712z" }) }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const Checkmark = (props) => (_jsx(IconBase, { label: "Checkmark", ...props, children: _jsx("path", { fill: "currentColor", d: "M5.6 9.6 2.753 6.754a.5.5 0 0 0-.707 0L.353 8.446a.5.5 0 0 0 0 .708l4.893 4.893a.5.5 0 0 0 .707 0l9.693-9.693a.5.5 0 0 0 0-.708l-1.693-1.692a.5.5 0 0 0-.707 0z" }) }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const Edit = (props) => (_jsxs(IconBase, { label: "Edit", ...props, children: [_jsx("g", { fill: "currentColor", clipPath: "url(#a)", children: _jsx("path", { d: "M8.1 3.5.3 11.3c-.2.2-.3.4-.3.7v3c0 .6.4 1 1 1h3c.3 0 .5-.1.7-.3l7.8-7.8zm7.6-.2-3-3c-.4-.4-1-.4-1.4 0L9.5 2.1l4.4 4.4 1.8-1.8c.4-.4.4-1 0-1.4" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "a", children: _jsx("path", { fill: "#fff", d: "M0 0h16v16H0z" }) }) })] }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconBase } from "../IconBase";
|
|
4
|
+
export const Eye = (props) => (_jsxs(IconBase, { label: "Eye", ...props, children: [_jsx("path", { fill: "currentColor", d: "M8 14c4.707 0 7.744-5.284 7.871-5.508a1 1 0 0 0 .001-.98C15.746 7.287 12.732 2 8 2 3.245 2 .251 7.289.126 7.514a1 1 0 0 0 .002.975C.254 8.713 3.27 14 8 14M8 4c2.84 0 5.036 2.835 5.818 4-.784 1.166-2.98 4-5.818 4-2.84 0-5.038-2.838-5.819-4.001C2.958 6.835 5.146 4 8.001 4" }), _jsx("path", { fill: "currentColor", d: "M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4" })] }));
|