@krrli/cm-designsystem 1.1.0 → 1.19.7

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.
Files changed (174) hide show
  1. package/README.md +391 -2
  2. package/dist/components/avatar/Avatar.d.ts +71 -0
  3. package/dist/components/avatar/Avatar.js +63 -0
  4. package/dist/components/branding/BrandingGallery.d.ts +1 -0
  5. package/dist/components/branding/BrandingGallery.js +139 -0
  6. package/dist/components/button/Button.d.ts +54 -0
  7. package/dist/components/button/Button.js +56 -0
  8. package/dist/components/button/Button.test.d.ts +1 -0
  9. package/dist/components/button/Button.test.js +30 -0
  10. package/dist/components/color/ColorDoc.d.ts +4 -0
  11. package/dist/components/color/ColorDoc.js +10 -0
  12. package/dist/components/file-upload/FileUpload.d.ts +83 -0
  13. package/dist/components/file-upload/FileUpload.js +70 -0
  14. package/dist/components/form/Form.d.ts +54 -0
  15. package/dist/components/form/Form.js +38 -0
  16. package/dist/components/icon-button/IconButton.d.ts +50 -0
  17. package/dist/components/icon-button/IconButton.js +22 -0
  18. package/dist/components/icon-button/IconButton.test.d.ts +1 -0
  19. package/dist/components/icon-button/IconButton.test.js +22 -0
  20. package/dist/components/icons/IconBase.d.ts +5 -0
  21. package/dist/components/icons/IconBase.js +9 -0
  22. package/dist/components/icons/generated/ArrowDown.d.ts +3 -0
  23. package/dist/components/icons/generated/ArrowDown.js +4 -0
  24. package/dist/components/icons/generated/ArrowLeft.d.ts +3 -0
  25. package/dist/components/icons/generated/ArrowLeft.js +4 -0
  26. package/dist/components/icons/generated/ArrowRight.d.ts +3 -0
  27. package/dist/components/icons/generated/ArrowRight.js +4 -0
  28. package/dist/components/icons/generated/ArrowUp.d.ts +3 -0
  29. package/dist/components/icons/generated/ArrowUp.js +4 -0
  30. package/dist/components/icons/generated/Calendar.d.ts +3 -0
  31. package/dist/components/icons/generated/Calendar.js +4 -0
  32. package/dist/components/icons/generated/Cancel.d.ts +3 -0
  33. package/dist/components/icons/generated/Cancel.js +4 -0
  34. package/dist/components/icons/generated/Checkmark.d.ts +3 -0
  35. package/dist/components/icons/generated/Checkmark.js +4 -0
  36. package/dist/components/icons/generated/Edit.d.ts +3 -0
  37. package/dist/components/icons/generated/Edit.js +4 -0
  38. package/dist/components/icons/generated/Eye.d.ts +3 -0
  39. package/dist/components/icons/generated/Eye.js +4 -0
  40. package/dist/components/icons/generated/Fullscreen.d.ts +3 -0
  41. package/dist/components/icons/generated/Fullscreen.js +4 -0
  42. package/dist/components/icons/generated/HeartFilled.d.ts +3 -0
  43. package/dist/components/icons/generated/HeartFilled.js +4 -0
  44. package/dist/components/icons/generated/HeartOutline.d.ts +3 -0
  45. package/dist/components/icons/generated/HeartOutline.js +4 -0
  46. package/dist/components/icons/generated/Location.d.ts +3 -0
  47. package/dist/components/icons/generated/Location.js +4 -0
  48. package/dist/components/icons/generated/LogOut.d.ts +3 -0
  49. package/dist/components/icons/generated/LogOut.js +4 -0
  50. package/dist/components/icons/generated/Mumble.d.ts +3 -0
  51. package/dist/components/icons/generated/Mumble.js +4 -0
  52. package/dist/components/icons/generated/Profile.d.ts +3 -0
  53. package/dist/components/icons/generated/Profile.js +4 -0
  54. package/dist/components/icons/generated/ReplyFilled.d.ts +3 -0
  55. package/dist/components/icons/generated/ReplyFilled.js +4 -0
  56. package/dist/components/icons/generated/ReplyOutline.d.ts +3 -0
  57. package/dist/components/icons/generated/ReplyOutline.js +4 -0
  58. package/dist/components/icons/generated/Repost.d.ts +3 -0
  59. package/dist/components/icons/generated/Repost.js +4 -0
  60. package/dist/components/icons/generated/Send.d.ts +3 -0
  61. package/dist/components/icons/generated/Send.js +4 -0
  62. package/dist/components/icons/generated/Settings.d.ts +3 -0
  63. package/dist/components/icons/generated/Settings.js +4 -0
  64. package/dist/components/icons/generated/Share.d.ts +3 -0
  65. package/dist/components/icons/generated/Share.js +4 -0
  66. package/dist/components/icons/generated/Time.d.ts +3 -0
  67. package/dist/components/icons/generated/Time.js +4 -0
  68. package/dist/components/icons/generated/Upload.d.ts +3 -0
  69. package/dist/components/icons/generated/Upload.js +4 -0
  70. package/dist/components/icons/generated/index.d.ts +24 -0
  71. package/dist/components/icons/generated/index.js +24 -0
  72. package/dist/components/index.d.ts +25 -0
  73. package/dist/components/index.js +25 -0
  74. package/dist/components/input/Input.d.ts +61 -0
  75. package/dist/components/input/Input.js +47 -0
  76. package/dist/components/like-toggle/LikeToggle.d.ts +97 -0
  77. package/dist/components/like-toggle/LikeToggle.js +185 -0
  78. package/dist/components/like-toggle/LikeToggle.test.d.ts +1 -0
  79. package/dist/components/like-toggle/LikeToggle.test.js +35 -0
  80. package/dist/components/modal/Modal.d.ts +75 -0
  81. package/dist/components/modal/Modal.js +63 -0
  82. package/dist/components/modal/Modal.test.d.ts +1 -0
  83. package/dist/components/modal/Modal.test.js +24 -0
  84. package/dist/components/navi-button/NaviButton.d.ts +26 -0
  85. package/dist/components/navi-button/NaviButton.js +29 -0
  86. package/dist/components/navi-button/NaviButton.test.d.ts +1 -0
  87. package/dist/components/navi-button/NaviButton.test.js +22 -0
  88. package/dist/components/navi-user-button/NaviUserButton.d.ts +26 -0
  89. package/dist/components/navi-user-button/NaviUserButton.js +29 -0
  90. package/dist/components/round-button/RoundButton.d.ts +25 -0
  91. package/dist/components/round-button/RoundButton.js +28 -0
  92. package/dist/components/round-button/RoundButton.test.d.ts +1 -0
  93. package/dist/components/round-button/RoundButton.test.js +21 -0
  94. package/dist/components/tabs/TabItem.d.ts +11 -0
  95. package/dist/components/tabs/TabItem.js +13 -0
  96. package/dist/components/tabs/Tabs.d.ts +67 -0
  97. package/dist/components/tabs/Tabs.js +67 -0
  98. package/dist/components/tabs/Tabs.test.d.ts +1 -0
  99. package/dist/components/tabs/Tabs.test.js +61 -0
  100. package/dist/components/text-link/TextLink.d.ts +9 -0
  101. package/dist/components/text-link/TextLink.js +15 -0
  102. package/dist/components/text-link/TextLink.test.d.ts +1 -0
  103. package/dist/components/text-link/TextLink.test.js +14 -0
  104. package/dist/components/textarea/Textarea.d.ts +48 -0
  105. package/dist/components/textarea/Textarea.js +46 -0
  106. package/dist/components/timed-button/TimedButton.d.ts +56 -0
  107. package/dist/components/timed-button/TimedButton.js +106 -0
  108. package/dist/components/timed-button/TimedButton.test.d.ts +1 -0
  109. package/dist/components/timed-button/TimedButton.test.js +35 -0
  110. package/dist/components/toggle/Toggle.d.ts +62 -0
  111. package/dist/components/toggle/Toggle.js +67 -0
  112. package/dist/components/toggle/Toggle.test.d.ts +1 -0
  113. package/dist/components/toggle/Toggle.test.js +93 -0
  114. package/dist/components/typography/Heading.d.ts +17 -0
  115. package/dist/components/typography/Heading.js +11 -0
  116. package/dist/components/typography/Label.d.ts +15 -0
  117. package/dist/components/typography/Label.js +7 -0
  118. package/dist/components/typography/Paragraph.d.ts +15 -0
  119. package/dist/components/typography/Paragraph.js +7 -0
  120. package/dist/components/typography/Placeholder.d.ts +13 -0
  121. package/dist/components/typography/Placeholder.js +7 -0
  122. package/dist/components/typography/ValidationMessage.d.ts +15 -0
  123. package/dist/components/typography/ValidationMessage.js +9 -0
  124. package/dist/components/typography/styles.d.ts +74 -0
  125. package/dist/components/typography/styles.js +52 -0
  126. package/dist/favicon.svg +18 -0
  127. package/dist/index.d.ts +1 -0
  128. package/dist/index.es.js +7550 -0
  129. package/dist/index.js +2 -0
  130. package/dist/logo-inline-gradient.svg +43 -0
  131. package/dist/setupTests.d.ts +1 -0
  132. package/dist/setupTests.js +7 -0
  133. package/package.json +78 -33
  134. package/.github/CODEOWNERS +0 -7
  135. package/.github/semantic.yml +0 -24
  136. package/.github/workflows/publish-npm.yml +0 -29
  137. package/.github/workflows/storybook.yml +0 -44
  138. package/.releaserc.json +0 -9
  139. package/.storybook/main.ts +0 -19
  140. package/.storybook/preview.ts +0 -21
  141. package/.storybook/vitest.setup.ts +0 -7
  142. package/src/index.ts +0 -4
  143. package/stories/Button.stories.ts +0 -54
  144. package/stories/Button.tsx +0 -37
  145. package/stories/Button2.stories.ts +0 -54
  146. package/stories/Button2.tsx +0 -41
  147. package/stories/Configure.mdx +0 -364
  148. package/stories/Header.stories.ts +0 -34
  149. package/stories/Header.tsx +0 -56
  150. package/stories/Page.stories.ts +0 -33
  151. package/stories/Page.tsx +0 -73
  152. package/stories/assets/accessibility.png +0 -0
  153. package/stories/assets/accessibility.svg +0 -1
  154. package/stories/assets/addon-library.png +0 -0
  155. package/stories/assets/assets.png +0 -0
  156. package/stories/assets/avif-test-image.avif +0 -0
  157. package/stories/assets/context.png +0 -0
  158. package/stories/assets/discord.svg +0 -1
  159. package/stories/assets/docs.png +0 -0
  160. package/stories/assets/figma-plugin.png +0 -0
  161. package/stories/assets/github.svg +0 -1
  162. package/stories/assets/share.png +0 -0
  163. package/stories/assets/styling.png +0 -0
  164. package/stories/assets/testing.png +0 -0
  165. package/stories/assets/theming.png +0 -0
  166. package/stories/assets/tutorials.svg +0 -1
  167. package/stories/assets/youtube.svg +0 -1
  168. package/stories/button.css +0 -30
  169. package/stories/button2.css +0 -30
  170. package/stories/header.css +0 -32
  171. package/stories/page.css +0 -68
  172. package/tsconfig.json +0 -13
  173. package/vitest.config.ts +0 -35
  174. 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,4 @@
1
+ export declare const ColorDoc: ({ colorName, colorIntensity, }: {
2
+ colorName: string;
3
+ colorIntensity: number;
4
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -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,5 @@
1
+ import * as React from "react";
2
+ export type IconBaseProps = React.SVGProps<SVGSVGElement> & {
3
+ label?: string;
4
+ };
5
+ export declare const IconBase: React.FC<IconBaseProps>;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const ArrowDown: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const ArrowLeft: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const ArrowRight: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const ArrowUp: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Calendar: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Cancel: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Checkmark: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Edit: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Eye: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;
@@ -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" })] }));
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ import { IconBase } from "../IconBase";
3
+ export declare const Fullscreen: (props: React.ComponentProps<typeof IconBase>) => import("react/jsx-runtime").JSX.Element;