@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.
- package/.changeset/config.json +1 -1
- package/.github/workflows/storybook.yml +9 -1
- package/CHANGELOG.md +94 -0
- package/dist/index.d.mts +643 -131
- package/dist/index.d.ts +643 -131
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -3
- package/src/charts/DistributionBarChart.tsx +10 -4
- package/src/charts/DistributionHistogram.tsx +13 -5
- package/src/charts/LineGraph.stories.tsx +60 -0
- package/src/charts/LineGraph.tsx +216 -0
- package/src/charts/index.ts +2 -0
- package/src/docs/DesignSystem.mdx +241 -25
- package/src/styles/theme.css +8 -0
- package/src/ui/feedback/Alert.stories.tsx +56 -0
- package/src/ui/feedback/Alert.tsx +168 -0
- package/src/ui/{Dialog.stories.tsx → feedback/Dialog.stories.tsx} +2 -2
- package/src/ui/{Dialog.tsx → feedback/Dialog.tsx} +2 -2
- package/src/ui/feedback/EmptyState.stories.tsx +57 -0
- package/src/ui/feedback/EmptyState.tsx +123 -0
- package/src/ui/feedback/Popover.stories.tsx +130 -0
- package/src/ui/feedback/Popover.tsx +135 -0
- package/src/ui/feedback/Skeleton.stories.tsx +88 -0
- package/src/ui/{Skeleton.tsx → feedback/Skeleton.tsx} +2 -2
- package/src/ui/feedback/Spinner.stories.tsx +77 -0
- package/src/ui/feedback/Spinner.tsx +62 -0
- package/src/ui/{Tooltip.stories.tsx → feedback/Tooltip.stories.tsx} +3 -3
- package/src/ui/{Tooltip.tsx → feedback/Tooltip.tsx} +2 -2
- package/src/ui/feedback/index.ts +7 -0
- package/src/ui/forms/Button.stories.tsx +181 -0
- package/src/ui/forms/Button.tsx +323 -0
- package/src/ui/{Checkbox.stories.tsx → forms/Checkbox.stories.tsx} +2 -2
- package/src/ui/{Checkbox.tsx → forms/Checkbox.tsx} +2 -2
- package/src/ui/forms/ChipGroup.stories.tsx +118 -0
- package/src/ui/forms/ChipGroup.tsx +239 -0
- package/src/ui/{Dropdown.tsx → forms/Dropdown.tsx} +1 -1
- package/src/ui/{Field.stories.tsx → forms/Field.stories.tsx} +3 -3
- package/src/ui/{Field.tsx → forms/Field.tsx} +1 -1
- package/src/ui/{Input.stories.tsx → forms/Input.stories.tsx} +6 -6
- package/src/ui/{Input.tsx → forms/Input.tsx} +1 -1
- package/src/ui/{Label.stories.tsx → forms/Label.stories.tsx} +2 -2
- package/src/ui/{Label.tsx → forms/Label.tsx} +2 -2
- package/src/ui/{NumberField.stories.tsx → forms/NumberField.stories.tsx} +2 -2
- package/src/ui/{NumberField.tsx → forms/NumberField.tsx} +8 -9
- package/src/ui/forms/PeerbotsColorSelector.stories.tsx +49 -0
- package/src/ui/forms/PeerbotsColorSelector.tsx +100 -0
- package/src/ui/{Select.stories.tsx → forms/Select.stories.tsx} +2 -2
- package/src/ui/{Select.tsx → forms/Select.tsx} +5 -3
- package/src/ui/{Slider.stories.tsx → forms/Slider.stories.tsx} +6 -4
- package/src/ui/{Slider.tsx → forms/Slider.tsx} +7 -3
- package/src/ui/forms/SliderWithNumberField.stories.tsx +136 -0
- package/src/ui/{SliderWithNumberField.tsx → forms/SliderWithNumberField.tsx} +19 -7
- package/src/ui/{Switch.stories.tsx → forms/Switch.stories.tsx} +2 -2
- package/src/ui/{Switch.tsx → forms/Switch.tsx} +1 -1
- package/src/ui/{TabRadio.stories.tsx → forms/TabRadio.stories.tsx} +3 -3
- package/src/ui/{TabRadio.tsx → forms/TabRadio.tsx} +1 -1
- package/src/ui/{TextArea.stories.tsx → forms/TextArea.stories.tsx} +5 -3
- package/src/ui/{TextArea.tsx → forms/TextArea.tsx} +1 -1
- package/src/ui/forms/index.ts +15 -0
- package/src/ui/foundations/Anchor.stories.tsx +39 -0
- package/src/ui/foundations/Anchor.tsx +96 -0
- package/src/ui/foundations/CodeBlock.stories.tsx +86 -0
- package/src/ui/foundations/CodeBlock.tsx +148 -0
- package/src/ui/foundations/Colors.stories.tsx +80 -0
- package/src/ui/{Icon.stories.tsx → foundations/Icon.stories.tsx} +1 -1
- package/src/ui/{Icon.tsx → foundations/Icon.tsx} +1 -1
- package/src/ui/{IconRegistry.tsx → foundations/IconRegistry.tsx} +261 -57
- package/src/ui/foundations/SocialLinks.stories.tsx +38 -0
- package/src/ui/foundations/SocialLinks.tsx +117 -0
- package/src/ui/foundations/Typography.stories.tsx +58 -0
- package/src/ui/foundations/Typography.tsx +163 -0
- package/src/ui/foundations/index.ts +6 -0
- package/src/ui/index.ts +7 -27
- package/src/ui/layout/Accordion.stories.tsx +86 -0
- package/src/ui/layout/Accordion.tsx +205 -0
- package/src/ui/layout/Card.stories.tsx +151 -0
- package/src/ui/layout/Card.tsx +124 -0
- package/src/ui/layout/Collapsible.stories.tsx +54 -0
- package/src/ui/layout/Collapsible.tsx +54 -0
- package/src/ui/{Separator.stories.tsx → layout/Separator.stories.tsx} +2 -2
- package/src/ui/{Separator.tsx → layout/Separator.tsx} +1 -1
- package/src/ui/{SettingsPanel.stories.tsx → layout/SettingsPanel.stories.tsx} +5 -5
- package/src/ui/{SettingsPanel.tsx → layout/SettingsPanel.tsx} +33 -29
- package/src/ui/layout/index.ts +5 -0
- package/src/ui/media/Avatar.stories.tsx +89 -0
- package/src/ui/media/Avatar.tsx +122 -0
- package/src/ui/media/Dropzone.stories.tsx +95 -0
- package/src/ui/media/Dropzone.tsx +328 -0
- package/src/ui/media/FileUpload.stories.tsx +62 -0
- package/src/ui/media/FileUpload.tsx +175 -0
- package/src/ui/media/index.ts +3 -0
- package/src/ui/{AuthFormUI.stories.tsx → patterns/AuthFormUI.stories.tsx} +1 -1
- package/src/ui/{AuthFormUI.tsx → patterns/AuthFormUI.tsx} +24 -23
- package/src/ui/patterns/CopyButton.stories.tsx +77 -0
- package/src/ui/patterns/CopyButton.tsx +93 -0
- package/src/ui/patterns/SearchInput.stories.tsx +51 -0
- package/src/ui/patterns/SearchInput.tsx +93 -0
- package/src/ui/patterns/Stepper.stories.tsx +129 -0
- package/src/ui/patterns/Stepper.tsx +295 -0
- package/src/ui/{TabSelection.stories.tsx → patterns/TabSelection.stories.tsx} +1 -1
- package/src/ui/{TabSelection.tsx → patterns/TabSelection.tsx} +2 -2
- package/src/ui/patterns/index.ts +6 -0
- package/src/ui/patterns/useClipboard.ts +75 -0
- package/src/ui/types.ts +48 -0
- package/src/ui/Alert.stories.tsx +0 -41
- package/src/ui/Alert.tsx +0 -72
- package/src/ui/Anchor.stories.tsx +0 -25
- package/src/ui/Anchor.tsx +0 -32
- package/src/ui/Button.stories.tsx +0 -108
- package/src/ui/Button.tsx +0 -121
- package/src/ui/Collapsible.stories.tsx +0 -91
- package/src/ui/Collapsible.tsx +0 -52
- package/src/ui/Colors.stories.tsx +0 -67
- package/src/ui/Popover.tsx +0 -42
- package/src/ui/Skeleton.stories.tsx +0 -43
- package/src/ui/SliderWithNumberField.stories.tsx +0 -101
- package/src/ui/Typography.stories.tsx +0 -87
- package/src/ui/Typography.tsx +0 -80
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { Button as BaseButton } from "@base-ui/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { cn } from "../utils";
|
|
4
|
+
import {
|
|
5
|
+
ComponentColor,
|
|
6
|
+
FillVariant,
|
|
7
|
+
ComponentSize,
|
|
8
|
+
ComponentRadius,
|
|
9
|
+
} from "../types";
|
|
10
|
+
|
|
11
|
+
export type ButtonVariant =
|
|
12
|
+
| FillVariant
|
|
13
|
+
| "primary"
|
|
14
|
+
| "secondary"
|
|
15
|
+
| "danger"
|
|
16
|
+
| "ghostly-danger"
|
|
17
|
+
| "marketing-teal"
|
|
18
|
+
| "marketing-pink"
|
|
19
|
+
| "teal"
|
|
20
|
+
| "pink";
|
|
21
|
+
|
|
22
|
+
export interface ButtonProps
|
|
23
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {
|
|
24
|
+
/**
|
|
25
|
+
* Visual fill style / treatment or legacy variant.
|
|
26
|
+
* @default "solid"
|
|
27
|
+
*/
|
|
28
|
+
variant?: ButtonVariant;
|
|
29
|
+
/**
|
|
30
|
+
* Palette color or semantic intent.
|
|
31
|
+
* @default "primary"
|
|
32
|
+
*/
|
|
33
|
+
color?: ComponentColor;
|
|
34
|
+
/**
|
|
35
|
+
* Button scale / padding.
|
|
36
|
+
* @default "md"
|
|
37
|
+
*/
|
|
38
|
+
size?: ComponentSize;
|
|
39
|
+
/**
|
|
40
|
+
* Border radius geometry.
|
|
41
|
+
* @default "md" (rounded-xl)
|
|
42
|
+
*/
|
|
43
|
+
radius?: ComponentRadius;
|
|
44
|
+
/** Loading spinner indicator state */
|
|
45
|
+
isLoading?: boolean;
|
|
46
|
+
/** Icon placed before children */
|
|
47
|
+
leftIcon?: React.ReactNode;
|
|
48
|
+
/** Icon placed after children */
|
|
49
|
+
rightIcon?: React.ReactNode;
|
|
50
|
+
render?: BaseButton.Props["render"];
|
|
51
|
+
nativeButton?: boolean;
|
|
52
|
+
isIconOnly?: boolean;
|
|
53
|
+
href?: string;
|
|
54
|
+
target?: string;
|
|
55
|
+
rel?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const variantColorMap: Record<FillVariant, Record<string, string>> = {
|
|
59
|
+
solid: {
|
|
60
|
+
primary:
|
|
61
|
+
"pb:bg-primary pb:text-gray-900 pb:hover:bg-dark-primary pb:hover:text-white pb:shadow-xs pb:font-bold",
|
|
62
|
+
neutral:
|
|
63
|
+
"pb:bg-gray-100 pb:text-gray-900 pb:hover:bg-gray-200 pb:border pb:border-gray-300 pb:font-medium",
|
|
64
|
+
teal: "pb:bg-peerbots-teal pb:text-gray-900 pb:hover:bg-peerbots-darkteal pb:hover:text-white pb:shadow-md pb:font-bold",
|
|
65
|
+
pink: "pb:bg-peerbots-pink pb:text-gray-950 pb:hover:bg-rose-700 pb:hover:text-white pb:shadow-md pb:font-bold",
|
|
66
|
+
darkblue:
|
|
67
|
+
"pb:bg-peerbots-darkblue pb:text-white pb:hover:opacity-90 pb:shadow-md pb:font-bold",
|
|
68
|
+
danger:
|
|
69
|
+
"pb:bg-red-600 pb:text-white pb:hover:bg-red-700 pb:shadow-xs pb:font-bold",
|
|
70
|
+
success:
|
|
71
|
+
"pb:bg-emerald-700 pb:text-white pb:hover:bg-emerald-800 pb:shadow-xs pb:font-bold",
|
|
72
|
+
warning:
|
|
73
|
+
"pb:bg-amber-500 pb:text-gray-900 pb:hover:bg-amber-600 pb:shadow-xs pb:font-bold",
|
|
74
|
+
},
|
|
75
|
+
soft: {
|
|
76
|
+
primary:
|
|
77
|
+
"pb:bg-primary/20 pb:text-teal-950 pb:hover:bg-primary/30 pb:font-bold",
|
|
78
|
+
neutral:
|
|
79
|
+
"pb:bg-gray-100 pb:text-gray-800 pb:hover:bg-gray-200 pb:font-medium",
|
|
80
|
+
teal: "pb:bg-peerbots-teal/20 pb:text-teal-950 pb:hover:bg-peerbots-teal/30 pb:font-bold",
|
|
81
|
+
pink: "pb:bg-peerbots-pink/20 pb:text-rose-950 pb:hover:bg-peerbots-pink/30 pb:font-bold",
|
|
82
|
+
darkblue:
|
|
83
|
+
"pb:bg-peerbots-darkblue/15 pb:text-peerbots-darkblue pb:hover:bg-peerbots-darkblue/25 pb:font-bold",
|
|
84
|
+
danger:
|
|
85
|
+
"pb:bg-red-50 pb:text-red-800 pb:hover:bg-red-100 pb:font-bold",
|
|
86
|
+
success:
|
|
87
|
+
"pb:bg-emerald-50 pb:text-emerald-800 pb:hover:bg-emerald-100 pb:font-bold",
|
|
88
|
+
warning:
|
|
89
|
+
"pb:bg-amber-50 pb:text-amber-900 pb:hover:bg-amber-100 pb:font-bold",
|
|
90
|
+
},
|
|
91
|
+
outline: {
|
|
92
|
+
primary:
|
|
93
|
+
"pb:bg-transparent pb:border-2 pb:border-teal-700 pb:text-teal-900 pb:hover:bg-primary/10 pb:font-bold",
|
|
94
|
+
neutral:
|
|
95
|
+
"pb:bg-transparent pb:border-2 pb:border-gray-300 pb:text-gray-800 pb:hover:border-gray-400 pb:hover:bg-gray-50 pb:font-medium",
|
|
96
|
+
teal: "pb:bg-transparent pb:border-2 pb:border-peerbots-darkteal pb:text-peerbots-darkteal pb:hover:bg-peerbots-teal/10 pb:font-bold",
|
|
97
|
+
pink: "pb:bg-transparent pb:border-2 pb:border-rose-700 pb:text-rose-800 pb:hover:bg-peerbots-pink/10 pb:font-bold",
|
|
98
|
+
darkblue:
|
|
99
|
+
"pb:bg-transparent pb:border-2 pb:border-peerbots-darkblue pb:text-peerbots-darkblue pb:hover:bg-peerbots-darkblue/10 pb:font-bold",
|
|
100
|
+
danger:
|
|
101
|
+
"pb:bg-transparent pb:border-2 pb:border-red-600 pb:text-red-700 pb:hover:bg-red-50 pb:font-bold",
|
|
102
|
+
success:
|
|
103
|
+
"pb:bg-transparent pb:border-2 pb:border-emerald-600 pb:text-emerald-700 pb:hover:bg-emerald-50 pb:font-bold",
|
|
104
|
+
warning:
|
|
105
|
+
"pb:bg-transparent pb:border-2 pb:border-amber-600 pb:text-amber-900 pb:hover:bg-amber-50 pb:font-bold",
|
|
106
|
+
},
|
|
107
|
+
ghost: {
|
|
108
|
+
primary:
|
|
109
|
+
"pb:bg-transparent pb:text-teal-900 pb:hover:bg-primary/10 pb:font-bold",
|
|
110
|
+
neutral:
|
|
111
|
+
"pb:bg-transparent pb:text-gray-800 pb:hover:bg-gray-100 pb:hover:text-gray-900 pb:font-medium",
|
|
112
|
+
teal: "pb:bg-transparent pb:text-peerbots-darkteal pb:hover:bg-peerbots-teal/10 pb:font-bold",
|
|
113
|
+
pink: "pb:bg-transparent pb:text-rose-800 pb:hover:bg-peerbots-pink/10 pb:font-bold",
|
|
114
|
+
darkblue:
|
|
115
|
+
"pb:bg-transparent pb:text-peerbots-darkblue pb:hover:bg-peerbots-darkblue/10 pb:font-bold",
|
|
116
|
+
danger:
|
|
117
|
+
"pb:bg-transparent pb:text-red-700 pb:hover:bg-red-50 pb:font-bold",
|
|
118
|
+
success:
|
|
119
|
+
"pb:bg-transparent pb:text-emerald-700 pb:hover:bg-emerald-50 pb:font-bold",
|
|
120
|
+
warning:
|
|
121
|
+
"pb:bg-transparent pb:text-amber-900 pb:hover:bg-amber-50 pb:font-bold",
|
|
122
|
+
},
|
|
123
|
+
link: {
|
|
124
|
+
primary:
|
|
125
|
+
"pb:bg-transparent pb:p-0 pb:text-teal-800 pb:hover:underline pb:font-medium",
|
|
126
|
+
neutral:
|
|
127
|
+
"pb:bg-transparent pb:p-0 pb:text-gray-700 pb:hover:text-gray-900 pb:hover:underline pb:font-medium",
|
|
128
|
+
teal: "pb:bg-transparent pb:p-0 pb:text-peerbots-darkteal pb:hover:underline pb:font-medium",
|
|
129
|
+
pink: "pb:bg-transparent pb:p-0 pb:text-rose-800 pb:hover:underline pb:font-medium",
|
|
130
|
+
darkblue:
|
|
131
|
+
"pb:bg-transparent pb:p-0 pb:text-peerbots-darkblue pb:hover:underline pb:font-medium",
|
|
132
|
+
danger:
|
|
133
|
+
"pb:bg-transparent pb:p-0 pb:text-red-600 pb:hover:underline pb:font-medium",
|
|
134
|
+
success:
|
|
135
|
+
"pb:bg-transparent pb:p-0 pb:text-emerald-600 pb:hover:underline pb:font-medium",
|
|
136
|
+
warning:
|
|
137
|
+
"pb:bg-transparent pb:p-0 pb:text-amber-600 pb:hover:underline pb:font-medium",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const radiusClasses: Record<ComponentRadius, string> = {
|
|
142
|
+
none: "pb:rounded-none",
|
|
143
|
+
sm: "pb:rounded-md",
|
|
144
|
+
md: "pb:rounded-xl",
|
|
145
|
+
lg: "pb:rounded-2xl",
|
|
146
|
+
"2xl": "pb:rounded-2xl",
|
|
147
|
+
pill: "pb:rounded-full",
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const Button = React.forwardRef<
|
|
151
|
+
HTMLButtonElement | HTMLAnchorElement,
|
|
152
|
+
ButtonProps
|
|
153
|
+
>(
|
|
154
|
+
(
|
|
155
|
+
{
|
|
156
|
+
className,
|
|
157
|
+
variant = "solid",
|
|
158
|
+
color,
|
|
159
|
+
size = "md",
|
|
160
|
+
radius = "md",
|
|
161
|
+
isLoading = false,
|
|
162
|
+
leftIcon,
|
|
163
|
+
rightIcon,
|
|
164
|
+
children,
|
|
165
|
+
disabled,
|
|
166
|
+
render,
|
|
167
|
+
nativeButton,
|
|
168
|
+
isIconOnly,
|
|
169
|
+
href,
|
|
170
|
+
target,
|
|
171
|
+
rel,
|
|
172
|
+
...props
|
|
173
|
+
},
|
|
174
|
+
ref,
|
|
175
|
+
) => {
|
|
176
|
+
// Resolve legacy variants to orthogonal (FillVariant, ComponentColor, ComponentRadius)
|
|
177
|
+
let resolvedVariant: FillVariant = "solid";
|
|
178
|
+
let resolvedColor: ComponentColor = color || "primary";
|
|
179
|
+
let resolvedRadius: ComponentRadius = radius;
|
|
180
|
+
|
|
181
|
+
if (variant === "secondary") {
|
|
182
|
+
resolvedVariant = "solid";
|
|
183
|
+
resolvedColor = color || "neutral";
|
|
184
|
+
} else if (variant === "danger") {
|
|
185
|
+
resolvedVariant = "solid";
|
|
186
|
+
resolvedColor = color || "danger";
|
|
187
|
+
} else if (variant === "ghostly-danger") {
|
|
188
|
+
resolvedVariant = "ghost";
|
|
189
|
+
resolvedColor = color || "danger";
|
|
190
|
+
} else if (variant === "marketing-teal" || variant === "teal") {
|
|
191
|
+
resolvedVariant = "solid";
|
|
192
|
+
resolvedColor = color || "teal";
|
|
193
|
+
resolvedRadius = radius === "md" ? "pill" : radius;
|
|
194
|
+
} else if (variant === "marketing-pink" || variant === "pink") {
|
|
195
|
+
resolvedVariant = "solid";
|
|
196
|
+
resolvedColor = color || "pink";
|
|
197
|
+
resolvedRadius = radius === "md" ? "pill" : radius;
|
|
198
|
+
} else if (
|
|
199
|
+
variant === "solid" ||
|
|
200
|
+
variant === "soft" ||
|
|
201
|
+
variant === "outline" ||
|
|
202
|
+
variant === "ghost" ||
|
|
203
|
+
variant === "link"
|
|
204
|
+
) {
|
|
205
|
+
resolvedVariant = variant;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const isActuallyIconOnly =
|
|
209
|
+
isIconOnly || (!children && (!!leftIcon || !!rightIcon));
|
|
210
|
+
|
|
211
|
+
const sizes: Record<ComponentSize, string> = {
|
|
212
|
+
xs: isActuallyIconOnly
|
|
213
|
+
? "pb:p-1 pb:text-xs"
|
|
214
|
+
: "pb:px-2.5 pb:py-1 pb:text-xs",
|
|
215
|
+
sm: isActuallyIconOnly
|
|
216
|
+
? "pb:p-1.5 pb:text-xs"
|
|
217
|
+
: "pb:px-3.5 pb:py-1.5 pb:text-xs",
|
|
218
|
+
md: isActuallyIconOnly
|
|
219
|
+
? "pb:p-2 pb:text-sm"
|
|
220
|
+
: "pb:px-4.5 pb:py-2.5 pb:text-sm",
|
|
221
|
+
lg: isActuallyIconOnly
|
|
222
|
+
? "pb:p-3 pb:text-base"
|
|
223
|
+
: "pb:px-6 pb:py-3.5 pb:text-base sm:pb:text-lg",
|
|
224
|
+
xl: isActuallyIconOnly
|
|
225
|
+
? "pb:p-3.5 pb:text-lg"
|
|
226
|
+
: "pb:px-8 pb:py-4 pb:text-lg sm:pb:text-xl",
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const variantStyles =
|
|
230
|
+
variantColorMap[resolvedVariant]?.[resolvedColor] ||
|
|
231
|
+
variantColorMap[resolvedVariant]?.primary ||
|
|
232
|
+
variantColorMap.solid.primary;
|
|
233
|
+
|
|
234
|
+
const commonClasses = cn(
|
|
235
|
+
"pb:inline-flex pb:items-center pb:justify-center pb:transition-all pb:duration-150 pb:focus:outline-none pb:focus-visible:ring-2 pb:focus-visible:ring-peerbots-teal pb:focus-visible:ring-offset-2 pb:disabled:cursor-not-allowed pb:disabled:opacity-50 pb:cursor-pointer pb:font-medium",
|
|
236
|
+
radiusClasses[resolvedRadius],
|
|
237
|
+
variantStyles,
|
|
238
|
+
sizes[size],
|
|
239
|
+
className,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const content = (
|
|
243
|
+
<>
|
|
244
|
+
{isLoading && (
|
|
245
|
+
<svg
|
|
246
|
+
className={cn(
|
|
247
|
+
"pb:animate-spin pb:h-4 pb:w-4",
|
|
248
|
+
!isActuallyIconOnly && "pb:mr-2 pb:-ml-1",
|
|
249
|
+
)}
|
|
250
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
251
|
+
fill="none"
|
|
252
|
+
viewBox="0 0 24 24"
|
|
253
|
+
>
|
|
254
|
+
<circle
|
|
255
|
+
className="pb:opacity-25"
|
|
256
|
+
cx="12"
|
|
257
|
+
cy="12"
|
|
258
|
+
r="10"
|
|
259
|
+
stroke="currentColor"
|
|
260
|
+
strokeWidth="4"
|
|
261
|
+
></circle>
|
|
262
|
+
<path
|
|
263
|
+
className="pb:opacity-75"
|
|
264
|
+
fill="currentColor"
|
|
265
|
+
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"
|
|
266
|
+
></path>
|
|
267
|
+
</svg>
|
|
268
|
+
)}
|
|
269
|
+
{!isLoading && leftIcon && (
|
|
270
|
+
<span
|
|
271
|
+
className={cn(
|
|
272
|
+
"pb:inline-flex pb:items-center pb:justify-center",
|
|
273
|
+
!isActuallyIconOnly && "pb:mr-2 pb:-ml-1",
|
|
274
|
+
)}
|
|
275
|
+
>
|
|
276
|
+
{leftIcon}
|
|
277
|
+
</span>
|
|
278
|
+
)}
|
|
279
|
+
{children}
|
|
280
|
+
{!isLoading && rightIcon && (
|
|
281
|
+
<span
|
|
282
|
+
className={cn(
|
|
283
|
+
"pb:inline-flex pb:items-center pb:justify-center",
|
|
284
|
+
!isActuallyIconOnly && "pb:ml-2 pb:-mr-1",
|
|
285
|
+
)}
|
|
286
|
+
>
|
|
287
|
+
{rightIcon}
|
|
288
|
+
</span>
|
|
289
|
+
)}
|
|
290
|
+
</>
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
if (href) {
|
|
294
|
+
return (
|
|
295
|
+
<a
|
|
296
|
+
href={href}
|
|
297
|
+
target={target}
|
|
298
|
+
rel={rel}
|
|
299
|
+
className={commonClasses}
|
|
300
|
+
ref={ref as React.Ref<HTMLAnchorElement>}
|
|
301
|
+
{...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}
|
|
302
|
+
>
|
|
303
|
+
{content}
|
|
304
|
+
</a>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<BaseButton
|
|
310
|
+
ref={ref as React.Ref<HTMLButtonElement>}
|
|
311
|
+
render={render}
|
|
312
|
+
nativeButton={nativeButton}
|
|
313
|
+
className={commonClasses}
|
|
314
|
+
disabled={disabled || isLoading}
|
|
315
|
+
{...(props as React.ButtonHTMLAttributes<HTMLButtonElement>)}
|
|
316
|
+
>
|
|
317
|
+
{content}
|
|
318
|
+
</BaseButton>
|
|
319
|
+
);
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
Button.displayName = "Button";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { Checkbox } from "./Checkbox";
|
|
3
|
-
import { Heading } from "
|
|
3
|
+
import { Heading } from "../foundations/Typography";
|
|
4
4
|
import React from "react";
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Checkbox> = {
|
|
7
|
-
title: "
|
|
7
|
+
title: "Forms/Checkbox",
|
|
8
8
|
component: Checkbox,
|
|
9
9
|
tags: ["autodocs"],
|
|
10
10
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Checkbox as BaseCheckbox } from "@base-ui/react";
|
|
2
2
|
import React, { ComponentPropsWithoutRef } from "react";
|
|
3
|
-
import { cn } from "
|
|
4
|
-
import { Icon } from "
|
|
3
|
+
import { cn } from "../utils";
|
|
4
|
+
import { Icon } from "../foundations/Icon";
|
|
5
5
|
|
|
6
6
|
export type CheckboxProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
7
7
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { ChipGroup } from "./ChipGroup";
|
|
3
|
+
import { Icon } from "../foundations/Icon";
|
|
4
|
+
import { Heading, Text } from "../foundations/Typography";
|
|
5
|
+
import React, { useState } from "react";
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof ChipGroup> = {
|
|
8
|
+
title: "Forms/ChipGroup",
|
|
9
|
+
component: ChipGroup,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "centered",
|
|
12
|
+
},
|
|
13
|
+
tags: ["autodocs"],
|
|
14
|
+
argTypes: {
|
|
15
|
+
variant: {
|
|
16
|
+
control: "select",
|
|
17
|
+
options: ["soft", "solid", "outline"],
|
|
18
|
+
},
|
|
19
|
+
color: {
|
|
20
|
+
control: "select",
|
|
21
|
+
options: ["teal", "pink", "primary", "neutral", "danger"],
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
control: "select",
|
|
25
|
+
options: ["xs", "sm", "md", "lg", "xl"],
|
|
26
|
+
},
|
|
27
|
+
radius: {
|
|
28
|
+
control: "select",
|
|
29
|
+
options: ["none", "sm", "md", "lg", "pill"],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof ChipGroup>;
|
|
36
|
+
|
|
37
|
+
const sampleOptions = [
|
|
38
|
+
{ value: "all", label: "All Bots" },
|
|
39
|
+
{ value: "moddy", label: "Moddy Face", badge: "New" },
|
|
40
|
+
{ value: "eva", label: "EVA Head" },
|
|
41
|
+
{ value: "buddy", label: "Buddy v2" },
|
|
42
|
+
{ value: "biped", label: "Biped 3D", badge: "Soon", disabled: true },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
options: sampleOptions,
|
|
48
|
+
defaultValue: "moddy",
|
|
49
|
+
color: "teal",
|
|
50
|
+
variant: "soft",
|
|
51
|
+
size: "md",
|
|
52
|
+
radius: "pill",
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const MultiSelectFilter: Story = {
|
|
57
|
+
render: () => {
|
|
58
|
+
const [selected, setSelected] = useState<string[]>(["audio", "video"]);
|
|
59
|
+
return (
|
|
60
|
+
<div className="pb:flex pb:flex-col pb:gap-3 pb:p-6 pb:bg-white pb:rounded-2xl pb:max-w-xl">
|
|
61
|
+
<Heading level={4} className="pb:text-sm pb:font-bold">
|
|
62
|
+
Capabilities Filter (Multi-Select)
|
|
63
|
+
</Heading>
|
|
64
|
+
<ChipGroup
|
|
65
|
+
multiple
|
|
66
|
+
values={selected}
|
|
67
|
+
onMultipleChange={setSelected}
|
|
68
|
+
color="pink"
|
|
69
|
+
variant="soft"
|
|
70
|
+
options={[
|
|
71
|
+
{ value: "audio", label: "Audio Output", icon: <Icon name="speakerWave" className="pb:w-3.5 pb:h-3.5 pb:mr-1" /> },
|
|
72
|
+
{ value: "video", label: "Camera Vision", icon: <Icon name="camera" className="pb:w-3.5 pb:h-3.5 pb:mr-1" /> },
|
|
73
|
+
{ value: "motors", label: "Servos & Motors" },
|
|
74
|
+
{ value: "leds", label: "RGB Matrix" },
|
|
75
|
+
{ value: "imu", label: "Gyro/IMU", disabled: true, badge: "Experimental" },
|
|
76
|
+
]}
|
|
77
|
+
/>
|
|
78
|
+
<Text size="xs" color="muted">
|
|
79
|
+
Selected: {selected.join(", ") || "None"}
|
|
80
|
+
</Text>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const VariantsAndColors: Story = {
|
|
87
|
+
render: () => (
|
|
88
|
+
<div className="pb:flex pb:flex-col pb:gap-6 pb:p-6 pb:bg-gray-50 pb:rounded-2xl pb:max-w-2xl">
|
|
89
|
+
<div>
|
|
90
|
+
<Text size="xs" weight="bold" color="muted" className="pb:uppercase pb:mb-2">
|
|
91
|
+
Teal Soft (Default)
|
|
92
|
+
</Text>
|
|
93
|
+
<ChipGroup options={sampleOptions} defaultValue="moddy" color="teal" variant="soft" />
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div>
|
|
97
|
+
<Text size="xs" weight="bold" color="muted" className="pb:uppercase pb:mb-2">
|
|
98
|
+
Pink Solid Pill
|
|
99
|
+
</Text>
|
|
100
|
+
<ChipGroup options={sampleOptions} defaultValue="eva" color="pink" variant="solid" />
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div>
|
|
104
|
+
<Text size="xs" weight="bold" color="muted" className="pb:uppercase pb:mb-2">
|
|
105
|
+
Primary Electric Outline
|
|
106
|
+
</Text>
|
|
107
|
+
<ChipGroup options={sampleOptions} defaultValue="all" color="primary" variant="outline" />
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div>
|
|
111
|
+
<Text size="xs" weight="bold" color="muted" className="pb:uppercase pb:mb-2">
|
|
112
|
+
Rounded Rect (radius="md")
|
|
113
|
+
</Text>
|
|
114
|
+
<ChipGroup options={sampleOptions} defaultValue="buddy" color="teal" radius="md" />
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
),
|
|
118
|
+
};
|