@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,185 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as RadixToggle from "@radix-ui/react-toggle";
3
+ import { useState } from "react";
4
+ import { tv } from "tailwind-variants";
5
+ import { HeartFilled, HeartOutline } from "../icons/generated";
6
+ import { Label } from "../typography/Label";
7
+ const toggleStyles = tv({
8
+ slots: {
9
+ base: [
10
+ "inline-flex",
11
+ "items-center",
12
+ "justify-center",
13
+ "gap-2",
14
+ "h-8",
15
+ "px-3",
16
+ "py-2",
17
+ "rounded-full",
18
+ "transition-all",
19
+ "duration-150",
20
+ "ease-in-out",
21
+ "focus-visible:outline-none",
22
+ "focus-visible:ring-2",
23
+ "focus-visible:ring-offset-2",
24
+ "disabled:opacity-50",
25
+ "disabled:pointer-events-none",
26
+ ],
27
+ icon: ["inline-flex"],
28
+ label: [],
29
+ },
30
+ variants: {
31
+ pressed: {
32
+ false: {
33
+ base: ["bg-transparent", "hover:bg-pink-50", "hover:text-pink-600"],
34
+ icon: [
35
+ "text-inherit",
36
+ "hover:transition-all",
37
+ "hover:duration-350",
38
+ "hover:ease-in-out",
39
+ ],
40
+ label: [
41
+ "text-inherit",
42
+ "hover:transition-all",
43
+ "hover:duration-350",
44
+ "hover:ease-in-out",
45
+ ],
46
+ },
47
+ true: {
48
+ base: [],
49
+ icon: ["text-pink-500", "transition-all", "duration-300", "ease-out"],
50
+ label: [
51
+ "text-pink-900",
52
+ "transition-transform",
53
+ "duration-300",
54
+ "ease-out",
55
+ ],
56
+ },
57
+ },
58
+ hasLikes: {
59
+ true: {
60
+ base: ["hover:bg-pink-50", "hover:text-pink-600"],
61
+ icon: ["text-pink-500"],
62
+ label: ["text-pink-900"],
63
+ },
64
+ false: "",
65
+ },
66
+ animating: {
67
+ true: {},
68
+ false: {},
69
+ },
70
+ },
71
+ compoundVariants: [
72
+ // pressed + animating --> Label ausblenden / nach oben verschieben
73
+ {
74
+ pressed: true,
75
+ animating: true,
76
+ class: {
77
+ label: [
78
+ "opacity-0",
79
+ "-translate-y-1",
80
+ "transition-all",
81
+ "duration-300",
82
+ "ease-out",
83
+ ],
84
+ icon: ["text-pink-500"],
85
+ },
86
+ },
87
+ // pressed + nicht animating --> Label sichtbar
88
+ {
89
+ pressed: true,
90
+ animating: false,
91
+ class: {
92
+ label: [
93
+ "opacity-100",
94
+ "translate-y-0",
95
+ "text-pink-900",
96
+ "transition-all",
97
+ "duration-300",
98
+ "ease-out",
99
+ ],
100
+ icon: ["text-pink-500"],
101
+ },
102
+ },
103
+ // pressed + hasLikes --> überschreibt Hover-Farbe
104
+ {
105
+ pressed: true,
106
+ hasLikes: true,
107
+ class: {
108
+ label: ["text-pink-900"],
109
+ },
110
+ },
111
+ // not pressed + animating
112
+ {
113
+ pressed: false,
114
+ animating: true,
115
+ class: {
116
+ label: [
117
+ "opacity-0",
118
+ "-translate-y-1",
119
+ "transition-all",
120
+ "duration-300",
121
+ "ease-out",
122
+ ],
123
+ },
124
+ },
125
+ // not pressed + nicht animating
126
+ {
127
+ pressed: false,
128
+ animating: false,
129
+ class: {
130
+ label: [
131
+ "opacity-100",
132
+ "translate-y-0",
133
+ "transition-all",
134
+ "duration-300",
135
+ "ease-out",
136
+ ],
137
+ },
138
+ },
139
+ ],
140
+ defaultVariants: {
141
+ pressed: false,
142
+ animating: false,
143
+ },
144
+ });
145
+ export const LikeToggle = ({ pressed = false, likes = 0, onLikeChange, }) => {
146
+ const [animating, setAnimating] = useState(false);
147
+ const [selected, setSelected] = useState(pressed);
148
+ const [currentLikes, setCurrentLikes] = useState(likes);
149
+ const [label, setLabel] = useState(likes ? (likes === 1 ? `${likes} Like` : `${likes} Likes`) : "Like");
150
+ const { base, icon, label: labelSlot, } = toggleStyles({
151
+ pressed: selected,
152
+ hasLikes: currentLikes > 0,
153
+ animating,
154
+ });
155
+ const handlePressedChange = (nextSelected) => {
156
+ // Ignore redundant events
157
+ if (nextSelected === selected)
158
+ return;
159
+ setSelected(nextSelected);
160
+ // Immediate label: show 'Liked' when liking, otherwise reflect current count or 'Like' if zero
161
+ if (nextSelected) {
162
+ setLabel("Liked");
163
+ }
164
+ else {
165
+ setLabel(currentLikes === 0
166
+ ? "Like"
167
+ : currentLikes === 1
168
+ ? "1 Like"
169
+ : `${currentLikes} Likes`);
170
+ }
171
+ onLikeChange(nextSelected);
172
+ // After 2s apply count change + dissolve animation
173
+ setTimeout(() => {
174
+ setCurrentLikes((prev) => {
175
+ const updated = Math.max(0, prev + (nextSelected ? 1 : -1));
176
+ // Final label after animation
177
+ setLabel(updated === 0 ? "Like" : updated === 1 ? "1 Like" : `${updated} Likes`);
178
+ setAnimating(true);
179
+ setTimeout(() => setAnimating(false), 300);
180
+ return updated;
181
+ });
182
+ }, 2000);
183
+ };
184
+ return (_jsxs(RadixToggle.Root, { className: base(), pressed: selected, onPressedChange: handlePressedChange, children: [_jsx("span", { className: icon(), "aria-hidden": "true", "aria-label": selected ? "HeartFilled" : "HeartOutline", children: selected ? _jsx(HeartFilled, {}) : _jsx(HeartOutline, {}) }), _jsx("span", { className: labelSlot(), children: _jsx(Label, { as: "span", size: "md", children: label }) })] }));
185
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
3
+ import { describe, expect, test, vi } from "vitest";
4
+ import { LikeToggle } from "./LikeToggle";
5
+ describe("LikeToggle", () => {
6
+ test("should render icon and label", async () => {
7
+ // Arrange
8
+ render(_jsx(LikeToggle, { likes: 3, onLikeChange: () => { } }));
9
+ const button = screen.getByRole("button");
10
+ expect(button).toBeVisible();
11
+ expect(button).toHaveTextContent("3 Likes");
12
+ // Icon prüfen
13
+ expect(screen.getByLabelText("HeartOutline")).toBeInTheDocument();
14
+ });
15
+ test("renders initial state and toggles correctly", async () => {
16
+ // Arrange
17
+ const onLikeChange = vi.fn();
18
+ render(_jsx(LikeToggle, { likes: 3, onLikeChange: onLikeChange }));
19
+ const button = screen.getByRole("button");
20
+ expect(button).toBeVisible();
21
+ // Initial state with Likes
22
+ expect(button).toHaveTextContent("3 Likes");
23
+ expect(screen.getByLabelText("HeartOutline")).toBeInTheDocument();
24
+ // Simulate click
25
+ fireEvent.click(button);
26
+ // Immediate state after click: "Liked" label + HeartFilled
27
+ expect(button).toHaveTextContent("Liked");
28
+ expect(screen.getByLabelText("HeartFilled")).toBeInTheDocument();
29
+ expect(onLikeChange).toHaveBeenCalledWith(true);
30
+ // Wait for animation + likes count update (2s delay + 300ms animation)
31
+ await waitFor(() => {
32
+ expect(button).toHaveTextContent("4 Likes");
33
+ }, { timeout: 2500 });
34
+ });
35
+ });
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import { type VariantProps } from "tailwind-variants";
3
+ declare const modalStyles: import("tailwind-variants").TVReturnType<{
4
+ [key: string]: {
5
+ [key: string]: import("tailwind-merge").ClassNameValue | {
6
+ title?: import("tailwind-merge").ClassNameValue;
7
+ content?: import("tailwind-merge").ClassNameValue;
8
+ overlay?: import("tailwind-merge").ClassNameValue;
9
+ container?: import("tailwind-merge").ClassNameValue;
10
+ actions?: import("tailwind-merge").ClassNameValue;
11
+ };
12
+ };
13
+ } | {
14
+ [x: string]: {
15
+ [x: string]: import("tailwind-merge").ClassNameValue | {
16
+ title?: import("tailwind-merge").ClassNameValue;
17
+ content?: import("tailwind-merge").ClassNameValue;
18
+ overlay?: import("tailwind-merge").ClassNameValue;
19
+ container?: import("tailwind-merge").ClassNameValue;
20
+ actions?: import("tailwind-merge").ClassNameValue;
21
+ };
22
+ };
23
+ } | {}, {
24
+ overlay: string[];
25
+ content: string[];
26
+ title: string[];
27
+ container: string[];
28
+ actions: string[];
29
+ }, undefined, {
30
+ [key: string]: {
31
+ [key: string]: import("tailwind-merge").ClassNameValue | {
32
+ title?: import("tailwind-merge").ClassNameValue;
33
+ content?: import("tailwind-merge").ClassNameValue;
34
+ overlay?: import("tailwind-merge").ClassNameValue;
35
+ container?: import("tailwind-merge").ClassNameValue;
36
+ actions?: import("tailwind-merge").ClassNameValue;
37
+ };
38
+ };
39
+ } | {}, {
40
+ overlay: string[];
41
+ content: string[];
42
+ title: string[];
43
+ container: string[];
44
+ actions: string[];
45
+ }, import("tailwind-variants").TVReturnType<unknown, {
46
+ overlay: string[];
47
+ content: string[];
48
+ title: string[];
49
+ container: string[];
50
+ actions: string[];
51
+ }, undefined, unknown, unknown, undefined>>;
52
+ type ModalVariants = VariantProps<typeof modalStyles>;
53
+ interface ModalProps extends ModalVariants {
54
+ title: string;
55
+ open: boolean;
56
+ onOpenChange: (isOpen: boolean) => void;
57
+ children: React.ReactNode;
58
+ }
59
+ export declare const Modal: React.FC<ModalProps> & {
60
+ Body: typeof ModalBody;
61
+ Actions: typeof ModalActions;
62
+ };
63
+ export declare function ModalBody({ children }: {
64
+ children: React.ReactNode;
65
+ }): React.ReactNode;
66
+ export declare namespace ModalBody {
67
+ var displayName: string;
68
+ }
69
+ export declare function ModalActions({ children }: {
70
+ children: React.ReactNode;
71
+ }): React.ReactNode;
72
+ export declare namespace ModalActions {
73
+ var displayName: string;
74
+ }
75
+ export {};
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as RadixDialog from "@radix-ui/react-dialog";
3
+ import React from "react";
4
+ import { tv } from "tailwind-variants";
5
+ import { Cancel } from "../icons/generated";
6
+ import { Heading } from "../typography/Heading";
7
+ const modalStyles = tv({
8
+ slots: {
9
+ overlay: ["fixed", "inset-0", "bg-black/20"],
10
+ content: [
11
+ "fixed",
12
+ "top-1/2",
13
+ "left-1/2",
14
+ "w-full",
15
+ "max-w-md",
16
+ "-translate-x-1/2",
17
+ "-translate-y-1/2",
18
+ "rounded-2xl",
19
+ "bg-white",
20
+ ],
21
+ title: [
22
+ "flex",
23
+ "justify-between",
24
+ "rounded-t-2xl",
25
+ "bg-violet-600",
26
+ "pt-6",
27
+ "pr-8",
28
+ "pb-6",
29
+ "pl-8",
30
+ "text-white",
31
+ ],
32
+ container: ["flex", "flex-col", "items-center", "gap-12", "p-8"],
33
+ actions: ["flex", "items-center", "gap-4"],
34
+ },
35
+ });
36
+ export const Modal = (props) => {
37
+ let modalBody = null;
38
+ let modalActions = null;
39
+ React.Children.forEach(props.children, (child) => {
40
+ if (!React.isValidElement(child))
41
+ return;
42
+ switch (child.type) {
43
+ case ModalBody:
44
+ modalBody = child;
45
+ break;
46
+ case ModalActions:
47
+ modalActions = child;
48
+ break;
49
+ }
50
+ });
51
+ const { overlay, content, title, container, actions } = modalStyles(props);
52
+ return (_jsx(RadixDialog.Root, { open: props.open, onOpenChange: props.onOpenChange, children: _jsxs(RadixDialog.Portal, { children: [_jsx(RadixDialog.Overlay, { className: overlay() }), _jsxs(RadixDialog.Content, { className: content(), children: [_jsxs(RadixDialog.Title, { className: title(), children: [_jsx(Heading, { as: "span", size: "3", children: props.title }), _jsx(RadixDialog.Close, { children: _jsx(Cancel, {}) })] }), _jsxs("div", { className: container(), children: [_jsx("div", { children: modalBody }), _jsx("div", { className: actions(), children: modalActions })] })] })] }) }));
53
+ };
54
+ ModalBody.displayName = "ModalBody";
55
+ export function ModalBody({ children }) {
56
+ return children;
57
+ }
58
+ ModalActions.displayName = "ModalActions";
59
+ export function ModalActions({ children }) {
60
+ return children;
61
+ }
62
+ Modal.Body = ModalBody;
63
+ Modal.Actions = ModalActions;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { describe, expect, test } from "vitest";
4
+ import { Button } from "../button/Button";
5
+ import { Cancel, Checkmark } from "../icons/generated";
6
+ import { Modal } from "./Modal";
7
+ describe("Modal", () => {
8
+ test("should open modal", async () => {
9
+ // Arrange
10
+ render(_jsx("div", { children: _jsxs(Modal, { open: true, onOpenChange: () => { }, title: "Modal", children: [_jsx(Modal.Body, { children: "Body" }), _jsxs(Modal.Actions, { children: [_jsx(Button, { intent: "primary", size: "md", label: "Exit", onClick: () => { }, children: _jsx(Cancel, {}) }), _jsx(Button, { intent: "secondary", size: "md", label: "Save", onClick: () => { }, children: _jsx(Checkmark, {}) })] })] }) }));
11
+ // Assert
12
+ expect(screen.getByRole("dialog")).toBeVisible();
13
+ expect(screen.getByText(/body/i)).toBeVisible();
14
+ expect(screen.getByText(/modal/i)).toBeVisible();
15
+ expect(screen.getByRole("button", { name: /exit/i })).toBeVisible();
16
+ expect(screen.getByRole("button", { name: /save/i })).toBeVisible();
17
+ });
18
+ test("should open modal", async () => {
19
+ // Arrange
20
+ render(_jsx("div", { children: _jsxs(Modal, { open: false, onOpenChange: () => { }, title: "Modal", children: [_jsx(Modal.Body, { children: "Body" }), _jsxs(Modal.Actions, { children: [_jsx(Button, { intent: "primary", size: "md", label: "Exit", onClick: () => { }, children: _jsx(Cancel, {}) }), _jsx(Button, { intent: "secondary", size: "md", label: "Save", onClick: () => { }, children: _jsx(Checkmark, {}) })] })] }) }));
21
+ // Assert
22
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
23
+ });
24
+ });
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { type VariantProps } from "tailwind-variants";
3
+ import type { IconBaseProps } from "../icons/IconBase";
4
+ declare const naviButtonStyles: import("tailwind-variants").TVReturnType<{
5
+ intent: {
6
+ secondary: string[];
7
+ };
8
+ }, undefined, string[], {
9
+ intent: {
10
+ secondary: string[];
11
+ };
12
+ }, undefined, import("tailwind-variants").TVReturnType<{
13
+ intent: {
14
+ secondary: string[];
15
+ };
16
+ }, undefined, string[], unknown, unknown, undefined>>;
17
+ type NaviButtonVariants = VariantProps<typeof naviButtonStyles>;
18
+ type NaviButtonIntent = "secondary";
19
+ interface NaviButtonProps extends NaviButtonVariants {
20
+ label: string;
21
+ intent?: NaviButtonIntent;
22
+ onClick: () => void;
23
+ children: React.ReactElement<IconBaseProps>;
24
+ }
25
+ export declare const NaviButton: ({ intent, ...props }: NaviButtonProps) => import("react/jsx-runtime").JSX.Element;
26
+ export {};
@@ -0,0 +1,29 @@
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 naviButtonStyles = tv({
6
+ base: [
7
+ "flex",
8
+ "flex-col",
9
+ "gap-1",
10
+ "transition",
11
+ "duration-300",
12
+ "ease-in-out",
13
+ "text-white",
14
+ "rounded-lg",
15
+ "items-center",
16
+ "pt-3",
17
+ "pb-3",
18
+ "pl-2",
19
+ "pr-2",
20
+ ],
21
+ variants: {
22
+ intent: {
23
+ secondary: ["bg-violet-600", "hover:bg-violet-700"],
24
+ },
25
+ },
26
+ });
27
+ export const NaviButton = ({ intent = "secondary", ...props }) => {
28
+ return (_jsxs("button", { className: naviButtonStyles({ intent, ...props }), onClick: props.onClick, "aria-label": props.label, children: [props.children, _jsx(Label, { as: "span", size: "sm", children: props.label })] }));
29
+ };
@@ -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 { Mumble } from "../icons/generated";
5
+ import { NaviButton } from "./NaviButton";
6
+ describe("NaviButton", () => {
7
+ test("should render button with icon", async () => {
8
+ // Arrange
9
+ render(_jsx(NaviButton, { 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 call onClick when clicked", () => {
16
+ // Arrange
17
+ const onClick = vi.fn();
18
+ render(_jsx(NaviButton, { label: "button", onClick: onClick, children: _jsx(Mumble, {}) }));
19
+ fireEvent.click(screen.getByRole("button"));
20
+ expect(onClick).toHaveBeenCalled();
21
+ });
22
+ });
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { type VariantProps } from "tailwind-variants";
3
+ declare const naviUserButtonStyles: import("tailwind-variants").TVReturnType<{
4
+ intent: {
5
+ secondary: string[];
6
+ };
7
+ }, undefined, string[], {
8
+ intent: {
9
+ secondary: string[];
10
+ };
11
+ }, undefined, import("tailwind-variants").TVReturnType<{
12
+ intent: {
13
+ secondary: string[];
14
+ };
15
+ }, undefined, string[], unknown, unknown, undefined>>;
16
+ type NaviUserButtonVariants = VariantProps<typeof naviUserButtonStyles>;
17
+ type NaviUserButtonIntent = "secondary";
18
+ interface NaviUserButtonProps extends NaviUserButtonVariants {
19
+ ariaLabel: string;
20
+ intent?: NaviUserButtonIntent;
21
+ src: string;
22
+ onClick: () => void;
23
+ children: React.ReactNode;
24
+ }
25
+ export declare const NaviUserButton: ({ intent, ...props }: NaviUserButtonProps) => import("react/jsx-runtime").JSX.Element;
26
+ export {};
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { tv } from "tailwind-variants";
4
+ import { Avatar } from "../avatar/Avatar";
5
+ const naviUserButtonStyles = tv({
6
+ base: [
7
+ "flex",
8
+ "flex-col",
9
+ "gap-1",
10
+ "transition",
11
+ "duration-300",
12
+ "ease-in-out",
13
+ "text-white",
14
+ "rounded-lg",
15
+ "items-center",
16
+ "pt-3",
17
+ "pb-3",
18
+ "pl-2",
19
+ "pr-2",
20
+ ],
21
+ variants: {
22
+ intent: {
23
+ secondary: ["bg-violet-600", "hover:bg-violet-700"],
24
+ },
25
+ },
26
+ });
27
+ export const NaviUserButton = ({ intent = "secondary", ...props }) => {
28
+ return (_jsx("button", { className: naviUserButtonStyles({ intent, ...props }), onClick: props.onClick, "aria-label": props.ariaLabel, children: _jsx(Avatar, { label: props.ariaLabel, size: "sm", src: props.src, children: props.children }) }));
29
+ };
@@ -0,0 +1,25 @@
1
+ import { type VariantProps } from "tailwind-variants";
2
+ import type { IconBaseProps } from "../icons/IconBase";
3
+ declare const roundButtonStyles: import("tailwind-variants").TVReturnType<{
4
+ intent: {
5
+ primary: string[];
6
+ };
7
+ }, undefined, string[], {
8
+ intent: {
9
+ primary: string[];
10
+ };
11
+ }, undefined, import("tailwind-variants").TVReturnType<{
12
+ intent: {
13
+ primary: string[];
14
+ };
15
+ }, undefined, string[], unknown, unknown, undefined>>;
16
+ type RoundButtonVariants = VariantProps<typeof roundButtonStyles>;
17
+ type RoundButtonIntent = "primary";
18
+ interface RoundButtonProps extends RoundButtonVariants {
19
+ intent?: RoundButtonIntent;
20
+ ariaLabel: string;
21
+ onClick: () => void;
22
+ children: React.ReactElement<IconBaseProps>;
23
+ }
24
+ export declare const RoundButton: ({ intent, ...props }: RoundButtonProps) => import("react/jsx-runtime").JSX.Element;
25
+ export {};
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { tv } from "tailwind-variants";
3
+ const roundButtonStyles = tv({
4
+ base: [
5
+ "text-white",
6
+ "rounded-full",
7
+ "hover:ring-3",
8
+ "active:ring-4",
9
+ "transition",
10
+ "duration-350",
11
+ "active:duration-300",
12
+ "ease-in-out",
13
+ "p-4",
14
+ ],
15
+ variants: {
16
+ intent: {
17
+ primary: [
18
+ "bg-slate-600",
19
+ "hover:bg-slate-700",
20
+ "hover:ring-slate-100",
21
+ "active:ring-violet-200",
22
+ ],
23
+ },
24
+ },
25
+ });
26
+ export const RoundButton = ({ intent = "primary", ...props }) => {
27
+ return (_jsx("button", { className: roundButtonStyles({ intent }), onClick: props.onClick, "aria-label": props.ariaLabel, children: props.children }));
28
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
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 { RoundButton } from "./RoundButton";
6
+ describe("RoundButton", () => {
7
+ test("should render button with icon", async () => {
8
+ // Arrange
9
+ render(_jsx(RoundButton, { onClick: vi.fn(), ariaLabel: "Mumble", children: _jsx(Mumble, {}) }));
10
+ // Assert
11
+ expect(screen.getByRole("button")).toBeVisible();
12
+ expect(screen.getByText("Mumble")).toBeVisible();
13
+ });
14
+ test("should call onChange when second tab clicked", () => {
15
+ // Arrange
16
+ const onClick = vi.fn();
17
+ render(_jsx(RoundButton, { onClick: onClick, ariaLabel: "Mumble", children: _jsx(Mumble, {}) }));
18
+ fireEvent.click(screen.getByRole("button"));
19
+ expect(onClick).toHaveBeenCalled();
20
+ });
21
+ });
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { type VariantProps } from "tailwind-variants";
3
+ declare const tabItemStyles: import("tailwind-variants").TVReturnType<{} | {} | {}, undefined, undefined, {} | {}, undefined, import("tailwind-variants").TVReturnType<unknown, undefined, undefined, unknown, unknown, undefined>>;
4
+ type TabItemVariants = VariantProps<typeof tabItemStyles>;
5
+ export interface TabItemProps extends TabItemVariants {
6
+ value: string;
7
+ label: string;
8
+ children: React.ReactNode;
9
+ }
10
+ export declare const TabItem: (props: TabItemProps) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as RadixTabs from "@radix-ui/react-tabs";
3
+ import React from "react";
4
+ import { tv } from "tailwind-variants";
5
+ const tabItemStyles = tv({});
6
+ export const TabItem = (props) => {
7
+ return (_jsx(RadixTabs.Content, { value: props.value, className: tabItemStyles(props), children: React.Children.map(props.children, (child, index) => {
8
+ if (React.isValidElement(child)) {
9
+ return React.cloneElement(child, { key: props.value || index });
10
+ }
11
+ return child;
12
+ }) }));
13
+ };