@peerbots/core 0.2.6 → 1.0.0

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 (121) hide show
  1. package/.changeset/config.json +1 -1
  2. package/.github/workflows/storybook.yml +9 -1
  3. package/CHANGELOG.md +94 -0
  4. package/dist/index.d.mts +643 -131
  5. package/dist/index.d.ts +643 -131
  6. package/dist/index.js +7 -6
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +7 -6
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -3
  11. package/src/charts/DistributionBarChart.tsx +10 -4
  12. package/src/charts/DistributionHistogram.tsx +13 -5
  13. package/src/charts/LineGraph.stories.tsx +60 -0
  14. package/src/charts/LineGraph.tsx +216 -0
  15. package/src/charts/index.ts +2 -0
  16. package/src/docs/DesignSystem.mdx +241 -25
  17. package/src/styles/theme.css +8 -0
  18. package/src/ui/feedback/Alert.stories.tsx +56 -0
  19. package/src/ui/feedback/Alert.tsx +168 -0
  20. package/src/ui/{Dialog.stories.tsx → feedback/Dialog.stories.tsx} +2 -2
  21. package/src/ui/{Dialog.tsx → feedback/Dialog.tsx} +2 -2
  22. package/src/ui/feedback/EmptyState.stories.tsx +57 -0
  23. package/src/ui/feedback/EmptyState.tsx +123 -0
  24. package/src/ui/feedback/Popover.stories.tsx +130 -0
  25. package/src/ui/feedback/Popover.tsx +135 -0
  26. package/src/ui/feedback/Skeleton.stories.tsx +88 -0
  27. package/src/ui/{Skeleton.tsx → feedback/Skeleton.tsx} +2 -2
  28. package/src/ui/feedback/Spinner.stories.tsx +77 -0
  29. package/src/ui/feedback/Spinner.tsx +62 -0
  30. package/src/ui/{Tooltip.stories.tsx → feedback/Tooltip.stories.tsx} +3 -3
  31. package/src/ui/{Tooltip.tsx → feedback/Tooltip.tsx} +2 -2
  32. package/src/ui/feedback/index.ts +7 -0
  33. package/src/ui/forms/Button.stories.tsx +181 -0
  34. package/src/ui/forms/Button.tsx +323 -0
  35. package/src/ui/{Checkbox.stories.tsx → forms/Checkbox.stories.tsx} +2 -2
  36. package/src/ui/{Checkbox.tsx → forms/Checkbox.tsx} +2 -2
  37. package/src/ui/forms/ChipGroup.stories.tsx +118 -0
  38. package/src/ui/forms/ChipGroup.tsx +239 -0
  39. package/src/ui/{Dropdown.tsx → forms/Dropdown.tsx} +1 -1
  40. package/src/ui/{Field.stories.tsx → forms/Field.stories.tsx} +3 -3
  41. package/src/ui/{Field.tsx → forms/Field.tsx} +1 -1
  42. package/src/ui/{Input.stories.tsx → forms/Input.stories.tsx} +6 -6
  43. package/src/ui/{Input.tsx → forms/Input.tsx} +1 -1
  44. package/src/ui/{Label.stories.tsx → forms/Label.stories.tsx} +2 -2
  45. package/src/ui/{Label.tsx → forms/Label.tsx} +2 -2
  46. package/src/ui/{NumberField.stories.tsx → forms/NumberField.stories.tsx} +2 -2
  47. package/src/ui/{NumberField.tsx → forms/NumberField.tsx} +8 -9
  48. package/src/ui/forms/PeerbotsColorSelector.stories.tsx +49 -0
  49. package/src/ui/forms/PeerbotsColorSelector.tsx +100 -0
  50. package/src/ui/{Select.stories.tsx → forms/Select.stories.tsx} +2 -2
  51. package/src/ui/{Select.tsx → forms/Select.tsx} +5 -3
  52. package/src/ui/{Slider.stories.tsx → forms/Slider.stories.tsx} +6 -4
  53. package/src/ui/{Slider.tsx → forms/Slider.tsx} +7 -3
  54. package/src/ui/forms/SliderWithNumberField.stories.tsx +136 -0
  55. package/src/ui/{SliderWithNumberField.tsx → forms/SliderWithNumberField.tsx} +19 -7
  56. package/src/ui/{Switch.stories.tsx → forms/Switch.stories.tsx} +2 -2
  57. package/src/ui/{Switch.tsx → forms/Switch.tsx} +1 -1
  58. package/src/ui/{TabRadio.stories.tsx → forms/TabRadio.stories.tsx} +3 -3
  59. package/src/ui/{TabRadio.tsx → forms/TabRadio.tsx} +1 -1
  60. package/src/ui/{TextArea.stories.tsx → forms/TextArea.stories.tsx} +5 -3
  61. package/src/ui/{TextArea.tsx → forms/TextArea.tsx} +1 -1
  62. package/src/ui/forms/index.ts +15 -0
  63. package/src/ui/foundations/Anchor.stories.tsx +39 -0
  64. package/src/ui/foundations/Anchor.tsx +96 -0
  65. package/src/ui/foundations/CodeBlock.stories.tsx +86 -0
  66. package/src/ui/foundations/CodeBlock.tsx +148 -0
  67. package/src/ui/foundations/Colors.stories.tsx +80 -0
  68. package/src/ui/{Icon.stories.tsx → foundations/Icon.stories.tsx} +1 -1
  69. package/src/ui/{Icon.tsx → foundations/Icon.tsx} +1 -1
  70. package/src/ui/{IconRegistry.tsx → foundations/IconRegistry.tsx} +261 -57
  71. package/src/ui/foundations/SocialLinks.stories.tsx +38 -0
  72. package/src/ui/foundations/SocialLinks.tsx +117 -0
  73. package/src/ui/foundations/Typography.stories.tsx +58 -0
  74. package/src/ui/foundations/Typography.tsx +163 -0
  75. package/src/ui/foundations/index.ts +6 -0
  76. package/src/ui/index.ts +7 -27
  77. package/src/ui/layout/Accordion.stories.tsx +86 -0
  78. package/src/ui/layout/Accordion.tsx +205 -0
  79. package/src/ui/layout/Card.stories.tsx +151 -0
  80. package/src/ui/layout/Card.tsx +124 -0
  81. package/src/ui/layout/Collapsible.stories.tsx +54 -0
  82. package/src/ui/layout/Collapsible.tsx +54 -0
  83. package/src/ui/{Separator.stories.tsx → layout/Separator.stories.tsx} +2 -2
  84. package/src/ui/{Separator.tsx → layout/Separator.tsx} +1 -1
  85. package/src/ui/{SettingsPanel.stories.tsx → layout/SettingsPanel.stories.tsx} +5 -5
  86. package/src/ui/{SettingsPanel.tsx → layout/SettingsPanel.tsx} +33 -29
  87. package/src/ui/layout/index.ts +5 -0
  88. package/src/ui/media/Avatar.stories.tsx +89 -0
  89. package/src/ui/media/Avatar.tsx +122 -0
  90. package/src/ui/media/Dropzone.stories.tsx +95 -0
  91. package/src/ui/media/Dropzone.tsx +328 -0
  92. package/src/ui/media/FileUpload.stories.tsx +62 -0
  93. package/src/ui/media/FileUpload.tsx +175 -0
  94. package/src/ui/media/index.ts +3 -0
  95. package/src/ui/{AuthFormUI.stories.tsx → patterns/AuthFormUI.stories.tsx} +1 -1
  96. package/src/ui/{AuthFormUI.tsx → patterns/AuthFormUI.tsx} +24 -23
  97. package/src/ui/patterns/CopyButton.stories.tsx +77 -0
  98. package/src/ui/patterns/CopyButton.tsx +93 -0
  99. package/src/ui/patterns/SearchInput.stories.tsx +51 -0
  100. package/src/ui/patterns/SearchInput.tsx +93 -0
  101. package/src/ui/patterns/Stepper.stories.tsx +129 -0
  102. package/src/ui/patterns/Stepper.tsx +295 -0
  103. package/src/ui/{TabSelection.stories.tsx → patterns/TabSelection.stories.tsx} +1 -1
  104. package/src/ui/{TabSelection.tsx → patterns/TabSelection.tsx} +2 -2
  105. package/src/ui/patterns/index.ts +6 -0
  106. package/src/ui/patterns/useClipboard.ts +75 -0
  107. package/src/ui/types.ts +48 -0
  108. package/src/ui/Alert.stories.tsx +0 -41
  109. package/src/ui/Alert.tsx +0 -72
  110. package/src/ui/Anchor.stories.tsx +0 -25
  111. package/src/ui/Anchor.tsx +0 -32
  112. package/src/ui/Button.stories.tsx +0 -108
  113. package/src/ui/Button.tsx +0 -121
  114. package/src/ui/Collapsible.stories.tsx +0 -91
  115. package/src/ui/Collapsible.tsx +0 -52
  116. package/src/ui/Colors.stories.tsx +0 -67
  117. package/src/ui/Popover.tsx +0 -42
  118. package/src/ui/Skeleton.stories.tsx +0 -43
  119. package/src/ui/SliderWithNumberField.stories.tsx +0 -101
  120. package/src/ui/Typography.stories.tsx +0 -87
  121. package/src/ui/Typography.tsx +0 -80
@@ -1,25 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Anchor } from "./Anchor";
3
-
4
- const meta = {
5
- title: "UI/Anchor",
6
- component: Anchor,
7
- parameters: {
8
- layout: "centered",
9
- },
10
- tags: ["autodocs"],
11
- argTypes: {
12
- href: { control: "text" },
13
- children: { control: "text" },
14
- },
15
- } satisfies Meta<typeof Anchor>;
16
-
17
- export default meta;
18
- type Story = StoryObj<typeof meta>;
19
-
20
- export const Default: Story = {
21
- args: {
22
- href: "https://peerbots.org",
23
- children: "Visit Peerbots",
24
- },
25
- };
package/src/ui/Anchor.tsx DELETED
@@ -1,32 +0,0 @@
1
- import * as React from "react";
2
- import { Link } from "react-router-dom";
3
- import { cn } from "./utils";
4
-
5
- export type AnchorProps = React.AnchorHTMLAttributes<HTMLAnchorElement>;
6
-
7
- const Anchor = React.forwardRef<HTMLAnchorElement, AnchorProps>(
8
- ({ className, href, target, ...props }, ref) => {
9
- const isInternal = href && !href.startsWith("http") && !target;
10
- const commonClass = cn(
11
- "pb:font-medium pb:text-teal-700 pb:underline pb:underline-offset-4 pb:hover:text-teal-900 pb:cursor-pointer",
12
- className,
13
- );
14
-
15
- if (isInternal) {
16
- return <Link to={href} ref={ref} className={commonClass} {...props} />;
17
- } else {
18
- return (
19
- <a
20
- href={href}
21
- target={target}
22
- ref={ref}
23
- className={commonClass}
24
- {...props}
25
- />
26
- );
27
- }
28
- },
29
- );
30
- Anchor.displayName = "Anchor";
31
-
32
- export { Anchor };
@@ -1,108 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Button } from "./Button";
3
- import { Icon } from "./Icon";
4
- import { Heading } from "./Typography";
5
-
6
- const meta: Meta<typeof Button> = {
7
- title: "UI/Button",
8
- component: Button,
9
- parameters: {
10
- layout: "centered",
11
- },
12
- tags: ["autodocs"],
13
- argTypes: {
14
- variant: {
15
- control: "select",
16
- options: ["primary", "secondary", "danger", "ghost", "ghostly-danger"],
17
- },
18
- size: {
19
- control: "select",
20
- options: ["sm", "md", "lg"],
21
- },
22
- disabled: { control: "boolean" },
23
- isLoading: { control: "boolean" },
24
- onClick: { action: "clicked" },
25
- },
26
- };
27
-
28
- export default meta;
29
- type Story = StoryObj<typeof Button>;
30
-
31
- export const Default: Story = {
32
- args: {
33
- children: "Button",
34
- variant: "primary",
35
- },
36
- };
37
-
38
- export const Variations: Story = {
39
- render: () => (
40
- <div className="pb:flex pb:flex-col pb:gap-8">
41
- <div className="pb:space-y-4">
42
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:italic">
43
- Variants
44
- </Heading>
45
- <div className="pb:flex pb:flex-wrap pb:gap-4 pb:items-center">
46
- <Button variant="primary">Primary</Button>
47
- <Button variant="secondary">Secondary</Button>
48
- <Button variant="danger">Danger</Button>
49
- <Button variant="ghost">Ghost</Button>
50
- <Button variant="ghostly-danger">Ghostly Danger</Button>
51
- </div>
52
- </div>
53
-
54
- <div className="pb:space-y-4">
55
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:italic">
56
- Sizes
57
- </Heading>
58
- <div className="pb:flex pb:flex-wrap pb:gap-4 pb:items-end">
59
- <Button size="sm">Small</Button>
60
- <Button size="md">Medium</Button>
61
- <Button size="lg">Large</Button>
62
- </div>
63
- </div>
64
-
65
- <div className="pb:space-y-4">
66
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:italic">
67
- States
68
- </Heading>
69
- <div className="pb:flex pb:flex-wrap pb:gap-4 pb:items-center">
70
- <Button isLoading>Loading</Button>
71
- <Button disabled>Disabled</Button>
72
- </div>
73
- </div>
74
-
75
- <div className="pb:space-y-4">
76
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:italic">
77
- With Icons
78
- </Heading>
79
- <div className="pb:flex pb:flex-wrap pb:gap-4 pb:items-center">
80
- <Button leftIcon={<Icon name="cloudArrowUp" />}>Upload</Button>
81
- <Button variant="secondary" rightIcon={<Icon name="chevronRight" />}>
82
- Next
83
- </Button>
84
- </div>
85
- </div>
86
-
87
- <div className="pb:space-y-4">
88
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:italic">
89
- Icon Only
90
- </Heading>
91
- <div className="pb:flex pb:flex-wrap pb:gap-4 pb:items-center">
92
- <Button size="sm">
93
- <Icon name="plus" />
94
- </Button>
95
- <Button size="md">
96
- <Icon name="plus" />
97
- </Button>
98
- <Button size="lg">
99
- <Icon name="plus" />
100
- </Button>
101
- <Button variant="ghost" size="sm" aria-label="Close">
102
- <Icon name="close" />
103
- </Button>
104
- </div>
105
- </div>
106
- </div>
107
- ),
108
- };
package/src/ui/Button.tsx DELETED
@@ -1,121 +0,0 @@
1
- import { Button as BaseButton } from "@base-ui/react";
2
- import React from "react";
3
- import { cn } from "./utils";
4
-
5
- export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
6
- variant?: "primary" | "secondary" | "danger" | "ghost" | "ghostly-danger";
7
- size?: "sm" | "md" | "lg";
8
- isLoading?: boolean;
9
- leftIcon?: React.ReactNode;
10
- rightIcon?: React.ReactNode;
11
- render?: BaseButton.Props["render"];
12
- nativeButton?: boolean;
13
- isIconOnly?: boolean;
14
- }
15
-
16
- export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
17
- (
18
- {
19
- className,
20
- variant = "primary",
21
- size = "md",
22
- isLoading = false,
23
- leftIcon,
24
- rightIcon,
25
- children,
26
- disabled,
27
- render,
28
- nativeButton,
29
- isIconOnly,
30
- ...props
31
- },
32
- ref,
33
- ) => {
34
- const isActuallyIconOnly =
35
- isIconOnly || (!children && (!!leftIcon || !!rightIcon));
36
-
37
- const variants = {
38
- primary:
39
- "pb:bg-primary pb:hover:bg-dark-primary pb:text-gray-900 pb:shadow-sm pb:border pb:border-transparent pb:font-bold pb:disabled:bg-gray-400 pb:disabled:hover:bg-gray-300",
40
- secondary:
41
- "pb:bg-gray-100 pb:hover:bg-gray-200 pb:text-gray-800 pb:border pb:border-gray-200 pb:border pb:font-normal pb:disabled:bg-gray-400 pb:disabled:hover:bg-gray-300",
42
- danger:
43
- "pb:bg-danger pb:hover:opacity-80 pb:text-gray-900 pb:shadow-sm pb:border pb:border-transparent pb:font-bold pb:disabled:bg-gray-400 pb:disabled:hover:bg-gray-300",
44
- ghost:
45
- "pb:bg-transparent pb:hover:bg-gray-100 pb:text-gray-700 pb:hover:text-gray-900 pb:font-medium",
46
- "ghostly-danger":
47
- "pb:bg-transparent pb:hover:bg-danger/10 pb:text-red-700 pb:border pb:border-red-700 pb:font-medium pb:disabled:border-gray-400 pb:disabled:text-gray-400",
48
- };
49
-
50
- const sizes = {
51
- sm: isActuallyIconOnly ? "pb:p-1 pb:text-xs" : "pb:px-2 pb:py-1 pb:text-xs",
52
- md: isActuallyIconOnly ? "pb:p-2 pb:text-sm" : "pb:px-4 pb:py-2 pb:text-sm",
53
- lg: isActuallyIconOnly ? "pb:p-3 pb:text-base" : "pb:px-6 pb:py-3 pb:text-base",
54
- };
55
-
56
- return (
57
- <BaseButton
58
- ref={ref}
59
- render={render}
60
- nativeButton={nativeButton}
61
- className={cn(
62
- "pb:inline-flex pb:items-center pb:justify-center pb:rounded-md pb:transition-colors pb:focus:outline-none pb:focus:ring-2 pb:focus:ring-primary pb:focus:ring-offset-2 pb:disabled:cursor-not-allowed pb:cursor-pointer",
63
- variants[variant],
64
- sizes[size],
65
- className,
66
- )}
67
- disabled={disabled || isLoading}
68
- {...props}
69
- >
70
- {isLoading && (
71
- <svg
72
- className={cn(
73
- "pb:animate-spin pb:h-4 pb:w-4",
74
- !isActuallyIconOnly && "pb:mr-2 pb:-ml-1",
75
- )}
76
- xmlns="http://www.w3.org/2000/svg"
77
- fill="none"
78
- viewBox="0 0 24 24"
79
- >
80
- <circle
81
- className="pb:opacity-25"
82
- cx="12"
83
- cy="12"
84
- r="10"
85
- stroke="currentColor"
86
- strokeWidth="4"
87
- ></circle>
88
- <path
89
- className="pb:opacity-75"
90
- fill="currentColor"
91
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
92
- ></path>
93
- </svg>
94
- )}
95
- {!isLoading && leftIcon && (
96
- <span
97
- className={cn(
98
- "pb:inline-flex pb:items-center pb:justify-center",
99
- !isActuallyIconOnly && "pb:mr-2 pb:-ml-1",
100
- )}
101
- >
102
- {leftIcon}
103
- </span>
104
- )}
105
- {children}
106
- {!isLoading && rightIcon && (
107
- <span
108
- className={cn(
109
- "pb:inline-flex pb:items-center pb:justify-center",
110
- !isActuallyIconOnly && "pb:ml-2 pb:-mr-1",
111
- )}
112
- >
113
- {rightIcon}
114
- </span>
115
- )}
116
- </BaseButton>
117
- );
118
- },
119
- );
120
-
121
- Button.displayName = "Button";
@@ -1,91 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Collapsible } from "./Collapsible";
3
- import { Heading } from "./Typography";
4
- import React from "react";
5
-
6
- const meta: Meta<typeof Collapsible> = {
7
- title: "UI/Collapsible",
8
- component: Collapsible,
9
- tags: ["autodocs"],
10
- };
11
-
12
- export default meta;
13
- type Story = StoryObj<typeof Collapsible>;
14
-
15
- export const Default: Story = {
16
- args: {
17
- title: "Click to expand",
18
- children: (
19
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
20
- This is the collapsible content. It can contain any elements.
21
- </div>
22
- ),
23
- },
24
- };
25
-
26
- export const Variations: Story = {
27
- render: () => (
28
- <div className="pb:flex pb:flex-col pb:gap-8 pb:p-4">
29
- <div className="pb:space-y-4">
30
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:uppercase">
31
- States & Styling
32
- </Heading>
33
- <div className="pb:space-y-4">
34
- <Collapsible title="Initially Open" defaultOpen={true}>
35
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
36
- This content is visible by default.
37
- </div>
38
- </Collapsible>
39
- <Collapsible
40
- title={<span className="pb:font-bold pb:text-primary">Styled Title</span>}
41
- className="pb:border pb:border-gray-200 pb:rounded-lg pb:overflow-hidden"
42
- >
43
- <div className="pb:p-4">Custom styled wrapper and title.</div>
44
- </Collapsible>
45
- </div>
46
- </div>
47
-
48
- <div className="pb:space-y-4">
49
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:uppercase">
50
- Variants
51
- </Heading>
52
- <div className="pb:space-y-4">
53
- <Collapsible title="Secondary (Default)" variant="secondary">
54
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
55
- Secondary variant content.
56
- </div>
57
- </Collapsible>
58
- <Collapsible title="Ghost" variant="ghost">
59
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
60
- Ghost variant content.
61
- </div>
62
- </Collapsible>
63
- <Collapsible title="Primary" variant="primary">
64
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
65
- Primary variant content.
66
- </div>
67
- </Collapsible>
68
- </div>
69
- </div>
70
-
71
- <div className="pb:space-y-4">
72
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:uppercase">
73
- Sizes
74
- </Heading>
75
- <div className="pb:space-y-4">
76
- <Collapsible title="Small" size="sm">
77
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">Small size content.</div>
78
- </Collapsible>
79
- <Collapsible title="Medium (Default)" size="md">
80
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">
81
- Medium size content.
82
- </div>
83
- </Collapsible>
84
- <Collapsible title="Large" size="lg">
85
- <div className="pb:p-4 pb:bg-gray-50 pb:rounded-md">Large size content.</div>
86
- </Collapsible>
87
- </div>
88
- </div>
89
- </div>
90
- ),
91
- };
@@ -1,52 +0,0 @@
1
- import React, { useState } from "react";
2
- import { cn } from "./utils";
3
- import { Button, ButtonProps } from "./Button";
4
- import { Icon } from "./Icon";
5
-
6
- export interface CollapsibleProps {
7
- title: React.ReactNode;
8
- children: React.ReactNode;
9
- /** The variant of the trigger button */
10
- variant?: ButtonProps["variant"];
11
- /** The size of the trigger button */
12
- size?: ButtonProps["size"];
13
- defaultOpen?: boolean;
14
- className?: string;
15
- }
16
-
17
- export function Collapsible({
18
- title,
19
- children,
20
- variant = "secondary",
21
- size = "md",
22
- defaultOpen = false,
23
- className,
24
- }: CollapsibleProps) {
25
- const [isOpen, setIsOpen] = useState(defaultOpen);
26
-
27
- return (
28
- <div className={cn("w-full", className)}>
29
- <Button
30
- variant={variant}
31
- size={size}
32
- className="pb:w-full pb:justify-between pb:font-medium"
33
- onClick={() => setIsOpen(!isOpen)}
34
- aria-expanded={isOpen}
35
- rightIcon={
36
- <Icon className="pb:h-5 pb:w-5 pb:text-gray-600" strokeWidth="2.5">
37
- {isOpen ? (
38
- <path d="M4.5 15.75l7.5-7.5 7.5 7.5" />
39
- ) : (
40
- <path d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
41
- )}
42
- </Icon>
43
- }
44
- >
45
- <span>{title}</span>
46
- </Button>
47
- {isOpen && (
48
- <div className="pb:px-4 pb:pt-4 pb:pb-2 pb:text-sm pb:text-gray-500">{children}</div>
49
- )}
50
- </div>
51
- );
52
- }
@@ -1,67 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
-
3
- const meta: Meta = {
4
- title: "UI/Colors",
5
- tags: ["autodocs"],
6
- };
7
-
8
- export default meta;
9
-
10
- export const Variations: StoryObj = {
11
- render: () => (
12
- <div className="pb:flex pb:flex-col pb:gap-8 pb:p-4 pb:bg-white">
13
- <div>
14
- <h3 className="pb:text-sm pb:font-medium pb:text-black pb:uppercase pb:tracking-wider pb:border-b pb:pb-1 pb:mb-4">
15
- Theme Colors
16
- </h3>
17
- <div className="pb:grid pb:grid-cols-2 pb:md:grid-cols-3 pb:lg:grid-cols-5 pb:gap-4">
18
- <ColorItem name="Primary" variable="var(--pb-color-primary)" />
19
- <ColorItem name="Secondary" variable="var(--pb-color-secondary)" />
20
- <ColorItem name="Accent" variable="var(--pb-color-accent)" />
21
- <ColorItem name="Danger" variable="var(--pb-color-danger)" />
22
- <ColorItem name="Light BG" variable="var(--pb-color-light-bg)" />
23
- </div>
24
- </div>
25
-
26
- <div>
27
- <h3 className="pb:text-sm pb:font-medium pb:text-black pb:uppercase pb:tracking-wider pb:border-b pb:pb-1 pb:mb-4">
28
- Extended Accent Colors
29
- </h3>
30
- <div className="pb:grid pb:grid-cols-2 pb:md:grid-cols-3 pb:lg:grid-cols-4 pb:gap-4">
31
- <ColorItem name="Accent HC" variable="var(--pb-color-accent-hc)" />
32
- <ColorItem name="Accent Two" variable="var(--pb-color-accent-two)" />
33
- <ColorItem
34
- name="Accent Two HC"
35
- variable="var(--pb-color-accent-two-hc)"
36
- />
37
- <ColorItem name="Accent Three" variable="var(--pb-color-accent-three)" />
38
- </div>
39
- </div>
40
-
41
- <div>
42
- <h3 className="pb:text-sm pb:font-medium pb:text-black pb:uppercase pb:tracking-wider pb:border-b pb:pb-1 pb:mb-4">
43
- UI Elements
44
- </h3>
45
- <div className="pb:grid pb:grid-cols-2 pb:md:grid-cols-3 pb:lg:grid-cols-4 pb:gap-4">
46
- <ColorItem name="Sidebar BG" variable="var(--pb-sidebar-bg)" />
47
- <ColorItem name="Dark Primary" variable="var(--pb-color-dark-primary)" />
48
- </div>
49
- </div>
50
- </div>
51
- ),
52
- };
53
-
54
- function ColorItem({ name, variable }: { name: string; variable: string }) {
55
- return (
56
- <div className="pb:flex pb:flex-col pb:gap-2">
57
- <div
58
- className="pb:h-20 pb:w-full pb:rounded-md pb:shadow-inner pb:border pb:border-gray-100"
59
- style={{ backgroundColor: variable }}
60
- />
61
- <div className="pb:flex pb:flex-col">
62
- <span className="pb:text-sm pb:font-bold pb:text-gray-900">{name}</span>
63
- <code className="pb:text-xs pb:text-gray-500">{variable}</code>
64
- </div>
65
- </div>
66
- );
67
- }
@@ -1,42 +0,0 @@
1
- import React from "react";
2
- import { Popover as BasePopover } from "@base-ui/react";
3
- import { cn } from "./utils";
4
-
5
- export interface PopoverProps {
6
- trigger: React.ReactNode;
7
- children: React.ReactNode;
8
- side?: "top" | "right" | "bottom" | "left";
9
- align?: "start" | "center" | "end";
10
- className?: string;
11
- open?: boolean;
12
- onOpenChange?: (open: boolean) => void;
13
- }
14
-
15
- export function Popover({
16
- trigger,
17
- children,
18
- side = "bottom",
19
- align = "center",
20
- className,
21
- open,
22
- onOpenChange,
23
- }: PopoverProps) {
24
- return (
25
- <BasePopover.Root open={open} onOpenChange={onOpenChange}>
26
- <BasePopover.Trigger>{trigger}</BasePopover.Trigger>
27
- <BasePopover.Portal>
28
- <BasePopover.Positioner side={side} align={align} sideOffset={5}>
29
- <BasePopover.Popup
30
- className={cn(
31
- "pb:z-50 pb:w-72 pb:rounded-md pb:border pb:bg-white pb:p-4 pb:shadow-md pb:outline-none pb:data-[state=open]:animate-in pb:data-[state=closed]:animate-out pb:data-[state=closed]:fade-out-0 pb:data-[state=open]:fade-in-0 pb:data-[state=closed]:zoom-out-95 pb:data-[state=open]:zoom-in-95",
32
- className,
33
- )}
34
- >
35
- {children}
36
- <BasePopover.Arrow className="pb:fill-white pb:stroke-gray-200" />
37
- </BasePopover.Popup>
38
- </BasePopover.Positioner>
39
- </BasePopover.Portal>
40
- </BasePopover.Root>
41
- );
42
- }
@@ -1,43 +0,0 @@
1
- import { Meta, StoryObj } from "@storybook/react";
2
- import { Skeleton } from "./Skeleton";
3
-
4
- const meta: Meta<typeof Skeleton> = {
5
- title: "UI/Skeleton",
6
- component: Skeleton,
7
- tags: ["autodocs"],
8
- parameters: {
9
- layout: "centered",
10
- },
11
- };
12
-
13
- export default meta;
14
- type Story = StoryObj<typeof Skeleton>;
15
-
16
- export const Default: Story = {
17
- args: {
18
- className: "w-[250px] h-4",
19
- },
20
- };
21
-
22
- export const Variations: Story = {
23
- render: () => (
24
- <div className="pb:flex pb:flex-col pb:space-y-3">
25
- {/* Circle Skeleton */}
26
- <Skeleton className="pb:h-12 pb:w-12 pb:rounded-full" />
27
-
28
- {/* Rectangular Skeletons */}
29
- <div className="pb:space-y-2">
30
- <Skeleton className="pb:h-4 pb:w-[250px]" />
31
- <Skeleton className="pb:h-4 pb:w-[200px]" />
32
- </div>
33
-
34
- <div className="pb:flex pb:items-center pb:space-x-4 pb:mt-6">
35
- <Skeleton className="pb:h-12 pb:w-12 pb:rounded-full" />
36
- <div className="pb:space-y-2">
37
- <Skeleton className="pb:h-4 pb:w-[250px]" />
38
- <Skeleton className="pb:h-4 pb:w-[200px]" />
39
- </div>
40
- </div>
41
- </div>
42
- ),
43
- };
@@ -1,101 +0,0 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import SliderWithNumberField from "./SliderWithNumberField";
3
- import React, { useState } from "react";
4
- import { Heading, Text } from "./Typography";
5
-
6
- const meta: Meta<typeof SliderWithNumberField> = {
7
- title: "UI/SliderWithNumberField",
8
- component: SliderWithNumberField,
9
- argTypes: {
10
- onChange: { action: "changed" },
11
- min: { control: { type: "number" } },
12
- max: { control: { type: "number" } },
13
- step: { control: { type: "number" } },
14
- disabled: { control: "boolean" },
15
- },
16
- };
17
-
18
- export default meta;
19
- type Story = StoryObj<typeof SliderWithNumberField>;
20
-
21
- const InteractiveSliderWithNumberField = (
22
- props: React.ComponentProps<typeof SliderWithNumberField>,
23
- ) => {
24
- const [value, setValue] = useState(props.value || props.defaultValue || 0);
25
- return (
26
- <SliderWithNumberField
27
- {...props}
28
- value={value}
29
- onChange={(v) => {
30
- setValue(v);
31
- props.onChange?.(v as number, new Event("change")); // Match signature
32
- }}
33
- />
34
- );
35
- };
36
-
37
- export const Default: Story = {
38
- args: {
39
- min: 0,
40
- max: 100,
41
- defaultValue: 50,
42
- },
43
- render: (args) => (
44
- <div className="pb:w-80 pb:p-4">
45
- <InteractiveSliderWithNumberField
46
- {...(args as React.ComponentProps<typeof SliderWithNumberField>)}
47
- />
48
- </div>
49
- ),
50
- };
51
-
52
- export const Variations: Story = {
53
- render: () => (
54
- <div className="pb:flex pb:flex-col pb:gap-12 pb:p-4">
55
- <div className="pb:space-y-4">
56
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:uppercase">
57
- Responsive Layouts
58
- </Heading>
59
- <div className="pb:space-y-8 pb:max-w-lg">
60
- <div className="pb:space-y-2">
61
- <Text variant="small" className="pb:font-bold pb:underline">
62
- Flexible (Full width of container)
63
- </Text>
64
- <InteractiveSliderWithNumberField defaultValue={50} />
65
- </div>
66
-
67
- <div className="pb:space-y-2 pb:w-64 pb:border-l pb:border-r pb:border-dotted pb:px-2 pb:bg-gray-50 pb:py-4">
68
- <Text variant="small" className="pb:font-bold pb:underline">
69
- Narrow Container (w-64)
70
- </Text>
71
- <InteractiveSliderWithNumberField defaultValue={50} />
72
- </div>
73
-
74
- <div className="pb:space-y-2 pb:w-48 pb:border-l pb:border-r pb:border-dotted pb:px-2 pb:bg-gray-50 pb:py-4">
75
- <Text variant="small" className="pb:font-bold pb:underline">
76
- Very Narrow (w-48) - Wraps
77
- </Text>
78
- <InteractiveSliderWithNumberField defaultValue={50} />
79
- </div>
80
- </div>
81
- </div>
82
-
83
- <div className="pb:space-y-4">
84
- <Heading level={4} className="pb:text-sm pb:font-medium pb:text-black pb:uppercase">
85
- Configuration
86
- </Heading>
87
- <div className="pb:space-y-4 pb:max-w-sm">
88
- <div className="pb:space-y-1">
89
- <Text variant="small">Custom Step (0.5)</Text>
90
- <InteractiveSliderWithNumberField
91
- step={0.5}
92
- defaultValue={2.5}
93
- min={0}
94
- max={10}
95
- />
96
- </div>
97
- </div>
98
- </div>
99
- </div>
100
- ),
101
- };