@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Slider as BaseSlider } from "@base-ui/react";
|
|
3
|
-
import { cn } from "
|
|
3
|
+
import { cn } from "../utils";
|
|
4
4
|
|
|
5
|
-
export interface SliderProps {
|
|
5
|
+
export interface SliderProps extends React.AriaAttributes {
|
|
6
6
|
min?: number;
|
|
7
7
|
max?: number;
|
|
8
8
|
step?: number;
|
|
@@ -28,6 +28,7 @@ export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
|
|
|
28
28
|
onChange,
|
|
29
29
|
name,
|
|
30
30
|
icon,
|
|
31
|
+
"aria-label": ariaLabel,
|
|
31
32
|
...props
|
|
32
33
|
},
|
|
33
34
|
ref,
|
|
@@ -81,7 +82,10 @@ export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
|
|
|
81
82
|
<BaseSlider.Track className="pb:relative pb:bg-gray-200 pb:rounded-full pb:w-full pb:h-1.5 pb:overflow-hidden pb:transition-colors group-pb:hover:bg-gray-300">
|
|
82
83
|
<BaseSlider.Indicator className="pb:absolute pb:bg-primary pb:rounded-full pb:h-full" />
|
|
83
84
|
</BaseSlider.Track>
|
|
84
|
-
<BaseSlider.Thumb
|
|
85
|
+
<BaseSlider.Thumb
|
|
86
|
+
aria-label={ariaLabel || (name ? name : "Slider")}
|
|
87
|
+
className="pb:z-10 pb:block pb:w-4.5 pb:h-4.5 pb:bg-white pb:shadow-md pb:rounded-full pb:border-2 pb:border-primary focus:pb:outline-none focus:pb:ring-4 focus:pb:ring-primary/20 pb:cursor-grab active:pb:cursor-grabbing pb:hover:scale-110 active:pb:scale-95 pb:transition-transform"
|
|
88
|
+
/>
|
|
85
89
|
</BaseSlider.Control>
|
|
86
90
|
</BaseSlider.Root>
|
|
87
91
|
</div>
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import SliderWithNumberField from "./SliderWithNumberField";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import { Heading, Text } from "../foundations/Typography";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof SliderWithNumberField> = {
|
|
7
|
+
title: "Forms/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:p-6 pb:bg-white pb:rounded-2xl pb:border pb:border-gray-200 pb:shadow-xs pb:w-[420px] pb:space-y-2">
|
|
45
|
+
<div className="pb:flex pb:justify-between pb:items-center pb:mb-1">
|
|
46
|
+
<Text size="sm" weight="bold">Output Volume</Text>
|
|
47
|
+
<Text size="xs" color="muted">0 – 100%</Text>
|
|
48
|
+
</div>
|
|
49
|
+
<InteractiveSliderWithNumberField
|
|
50
|
+
aria-label="Output volume"
|
|
51
|
+
{...(args as React.ComponentProps<typeof SliderWithNumberField>)}
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const WithStepperButtons: Story = {
|
|
58
|
+
render: () => (
|
|
59
|
+
<div className="pb:p-6 pb:bg-white pb:rounded-2xl pb:border pb:border-gray-200 pb:shadow-xs pb:w-[460px] pb:space-y-2">
|
|
60
|
+
<div className="pb:flex pb:justify-between pb:items-center pb:mb-1">
|
|
61
|
+
<Text size="sm" weight="bold">Head Tilt Angle</Text>
|
|
62
|
+
<Text size="xs" color="muted">-45° to +45°</Text>
|
|
63
|
+
</div>
|
|
64
|
+
<InteractiveSliderWithNumberField
|
|
65
|
+
aria-label="Head tilt angle"
|
|
66
|
+
min={-45}
|
|
67
|
+
max={45}
|
|
68
|
+
defaultValue={0}
|
|
69
|
+
step={1}
|
|
70
|
+
showButtons={true}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const DecimalPrecision: Story = {
|
|
77
|
+
render: () => (
|
|
78
|
+
<div className="pb:p-6 pb:bg-white pb:rounded-2xl pb:border pb:border-gray-200 pb:shadow-xs pb:w-[420px] pb:space-y-2">
|
|
79
|
+
<div className="pb:flex pb:justify-between pb:items-center pb:mb-1">
|
|
80
|
+
<Text size="sm" weight="bold">Speaking Pitch Multiplier</Text>
|
|
81
|
+
<Text size="xs" color="muted">0.5x – 2.0x (step 0.05)</Text>
|
|
82
|
+
</div>
|
|
83
|
+
<InteractiveSliderWithNumberField
|
|
84
|
+
aria-label="Speaking pitch multiplier"
|
|
85
|
+
min={0.5}
|
|
86
|
+
max={2.0}
|
|
87
|
+
step={0.05}
|
|
88
|
+
defaultValue={1.0}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
),
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const Variations: Story = {
|
|
95
|
+
render: () => (
|
|
96
|
+
<div className="pb:flex pb:flex-col pb:gap-8 pb:p-4 pb:max-w-lg">
|
|
97
|
+
<div className="pb:space-y-4">
|
|
98
|
+
<span className="pb:text-xs pb:font-bold pb:text-gray-700 pb:uppercase pb:tracking-wider pb:block">
|
|
99
|
+
Robot Motor & Audio Settings
|
|
100
|
+
</span>
|
|
101
|
+
<div className="pb:space-y-6 pb:p-6 pb:bg-gray-50 pb:rounded-2xl pb:border pb:border-gray-200">
|
|
102
|
+
<div className="pb:space-y-1.5">
|
|
103
|
+
<Text size="xs" weight="bold">Motor Sensitivity</Text>
|
|
104
|
+
<InteractiveSliderWithNumberField
|
|
105
|
+
aria-label="Motor sensitivity"
|
|
106
|
+
min={1}
|
|
107
|
+
max={10}
|
|
108
|
+
defaultValue={7}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div className="pb:space-y-1.5">
|
|
113
|
+
<Text size="xs" weight="bold">Eye Blink Frequency (Hz)</Text>
|
|
114
|
+
<InteractiveSliderWithNumberField
|
|
115
|
+
aria-label="Eye blink frequency"
|
|
116
|
+
min={0.1}
|
|
117
|
+
max={5.0}
|
|
118
|
+
step={0.1}
|
|
119
|
+
defaultValue={1.2}
|
|
120
|
+
showButtons={true}
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div className="pb:space-y-1.5">
|
|
125
|
+
<Text size="xs" weight="bold" color="muted">Disabled Axis (Locked)</Text>
|
|
126
|
+
<InteractiveSliderWithNumberField
|
|
127
|
+
aria-label="Locked axis"
|
|
128
|
+
disabled
|
|
129
|
+
defaultValue={0}
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
),
|
|
136
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Slider } from "./Slider";
|
|
3
3
|
import { NumberField } from "./NumberField";
|
|
4
|
-
import { cn } from "
|
|
4
|
+
import { cn } from "../utils";
|
|
5
5
|
|
|
6
|
-
export interface SliderWithNumberFieldProps {
|
|
6
|
+
export interface SliderWithNumberFieldProps extends React.AriaAttributes {
|
|
7
7
|
min?: number;
|
|
8
8
|
max?: number;
|
|
9
9
|
step?: number;
|
|
@@ -13,6 +13,7 @@ export interface SliderWithNumberFieldProps {
|
|
|
13
13
|
onChange?: (value: number, event: Event) => void;
|
|
14
14
|
className?: string;
|
|
15
15
|
inputWidth?: string;
|
|
16
|
+
showButtons?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const SliderWithNumberField = React.forwardRef<
|
|
@@ -29,7 +30,9 @@ export const SliderWithNumberField = React.forwardRef<
|
|
|
29
30
|
defaultValue,
|
|
30
31
|
disabled,
|
|
31
32
|
onChange,
|
|
32
|
-
inputWidth
|
|
33
|
+
inputWidth,
|
|
34
|
+
showButtons = false,
|
|
35
|
+
"aria-label": ariaLabel,
|
|
33
36
|
...props
|
|
34
37
|
},
|
|
35
38
|
ref,
|
|
@@ -41,16 +44,23 @@ export const SliderWithNumberField = React.forwardRef<
|
|
|
41
44
|
}
|
|
42
45
|
};
|
|
43
46
|
|
|
47
|
+
const defaultWidth = showButtons ? "pb:w-28" : "pb:w-20";
|
|
48
|
+
const widthClass = inputWidth
|
|
49
|
+
? inputWidth.startsWith("pb:")
|
|
50
|
+
? inputWidth
|
|
51
|
+
: `pb:${inputWidth}`
|
|
52
|
+
: defaultWidth;
|
|
53
|
+
|
|
44
54
|
return (
|
|
45
55
|
<div
|
|
46
56
|
ref={ref}
|
|
47
57
|
className={cn(
|
|
48
|
-
"pb:flex pb:
|
|
58
|
+
"pb:flex pb:items-center pb:gap-3 pb:w-full pb:min-w-0",
|
|
49
59
|
className,
|
|
50
60
|
)}
|
|
51
61
|
{...props}
|
|
52
62
|
>
|
|
53
|
-
<div className="pb:flex-
|
|
63
|
+
<div className="pb:flex-1 pb:min-w-0">
|
|
54
64
|
<Slider
|
|
55
65
|
min={min}
|
|
56
66
|
max={max}
|
|
@@ -58,11 +68,12 @@ export const SliderWithNumberField = React.forwardRef<
|
|
|
58
68
|
value={value}
|
|
59
69
|
defaultValue={defaultValue}
|
|
60
70
|
disabled={disabled}
|
|
71
|
+
aria-label={ariaLabel ? `${ariaLabel} slider` : "Slider value"}
|
|
61
72
|
onChange={handleChange}
|
|
62
73
|
className="pb:w-full"
|
|
63
74
|
/>
|
|
64
75
|
</div>
|
|
65
|
-
<div className={cn(
|
|
76
|
+
<div className={cn(widthClass, "pb:shrink-0")}>
|
|
66
77
|
<NumberField
|
|
67
78
|
value={value}
|
|
68
79
|
defaultValue={defaultValue}
|
|
@@ -70,12 +81,13 @@ export const SliderWithNumberField = React.forwardRef<
|
|
|
70
81
|
max={max}
|
|
71
82
|
step={step}
|
|
72
83
|
disabled={disabled}
|
|
84
|
+
aria-label={ariaLabel ? `${ariaLabel} input` : "Numeric input"}
|
|
73
85
|
onChange={(val, event) => {
|
|
74
86
|
if (val !== null) {
|
|
75
87
|
handleChange(val, event);
|
|
76
88
|
}
|
|
77
89
|
}}
|
|
78
|
-
showButtons={
|
|
90
|
+
showButtons={showButtons}
|
|
79
91
|
/>
|
|
80
92
|
</div>
|
|
81
93
|
</div>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { Switch } from "./Switch";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
-
import { Heading, Text } from "
|
|
4
|
+
import { Heading, Text } from "../foundations/Typography";
|
|
5
5
|
|
|
6
6
|
const meta: Meta<typeof Switch> = {
|
|
7
|
-
title: "
|
|
7
|
+
title: "Forms/Switch",
|
|
8
8
|
component: Switch,
|
|
9
9
|
tags: ["autodocs"],
|
|
10
10
|
argTypes: {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { TabRadio, TabRadioOption } from "./TabRadio";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
-
import { Icon } from "
|
|
5
|
-
import { Heading, Text } from "
|
|
4
|
+
import { Icon } from "../foundations/Icon";
|
|
5
|
+
import { Heading, Text } from "../foundations/Typography";
|
|
6
6
|
import React from "react";
|
|
7
7
|
|
|
8
8
|
const meta = {
|
|
9
|
-
title: "
|
|
9
|
+
title: "Forms/TabRadio",
|
|
10
10
|
component: TabRadio,
|
|
11
11
|
parameters: {
|
|
12
12
|
layout: "centered",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { TextArea } from "./TextArea";
|
|
3
|
-
import { Heading, Text } from "
|
|
3
|
+
import { Heading, Text } from "../foundations/Typography";
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof TextArea> = {
|
|
6
|
-
title: "
|
|
6
|
+
title: "Forms/TextArea",
|
|
7
7
|
component: TextArea,
|
|
8
8
|
tags: ["autodocs"],
|
|
9
9
|
argTypes: {},
|
|
@@ -30,13 +30,14 @@ export const Variations: Story = {
|
|
|
30
30
|
<Text variant="small" className="pb:font-bold">
|
|
31
31
|
With Predefined Value
|
|
32
32
|
</Text>
|
|
33
|
-
<TextArea defaultValue="This is some predefined text in the textarea." />
|
|
33
|
+
<TextArea aria-label="Predefined message" defaultValue="This is some predefined text in the textarea." />
|
|
34
34
|
</div>
|
|
35
35
|
<div className="pb:space-y-1">
|
|
36
36
|
<Text variant="small" className="pb:font-bold">
|
|
37
37
|
Large (10 rows)
|
|
38
38
|
</Text>
|
|
39
39
|
<TextArea
|
|
40
|
+
aria-label="Extended description"
|
|
40
41
|
rows={10}
|
|
41
42
|
placeholder="A larger textarea for more content..."
|
|
42
43
|
/>
|
|
@@ -53,6 +54,7 @@ export const Variations: Story = {
|
|
|
53
54
|
Disabled
|
|
54
55
|
</Text>
|
|
55
56
|
<TextArea
|
|
57
|
+
aria-label="Disabled message"
|
|
56
58
|
disabled
|
|
57
59
|
placeholder="Cannot type here"
|
|
58
60
|
defaultValue="Read only content"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./Button";
|
|
2
|
+
export * from "./Input";
|
|
3
|
+
export * from "./Select";
|
|
4
|
+
export * from "./Slider";
|
|
5
|
+
export * from "./SliderWithNumberField";
|
|
6
|
+
export * from "./Dropdown";
|
|
7
|
+
export * from "./Switch";
|
|
8
|
+
export * from "./Label";
|
|
9
|
+
export * from "./TabRadio";
|
|
10
|
+
export * from "./NumberField";
|
|
11
|
+
export * from "./Field";
|
|
12
|
+
export * from "./TextArea";
|
|
13
|
+
export * from "./Checkbox";
|
|
14
|
+
export * from "./PeerbotsColorSelector";
|
|
15
|
+
export * from "./ChipGroup";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Anchor } from "./Anchor";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Anchor> = {
|
|
6
|
+
title: "Foundations/Anchor",
|
|
7
|
+
component: Anchor,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "centered",
|
|
10
|
+
},
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof Anchor>;
|
|
17
|
+
|
|
18
|
+
export const Default: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
children: "Learn more about Peerbots",
|
|
21
|
+
href: "https://peerbots.org",
|
|
22
|
+
target: "_blank",
|
|
23
|
+
color: "teal",
|
|
24
|
+
underline: "hover",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Variations: Story = {
|
|
29
|
+
render: () => (
|
|
30
|
+
<div className="pb:flex pb:flex-col pb:gap-4 pb:p-6 pb:bg-white pb:max-w-md">
|
|
31
|
+
<Anchor href="#" color="default">Default Link</Anchor>
|
|
32
|
+
<Anchor href="#" color="teal">Teal Brand Link</Anchor>
|
|
33
|
+
<Anchor href="#" color="pink">Pink Brand Link</Anchor>
|
|
34
|
+
<Anchor href="#" color="muted">Muted Help Link</Anchor>
|
|
35
|
+
<Anchor href="#" color="teal" underline="always">Always Underlined Link</Anchor>
|
|
36
|
+
<Anchor href="#" color="default" variant="ghost">Ghost Interactive Link</Anchor>
|
|
37
|
+
</div>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "../utils";
|
|
3
|
+
import { ComponentColor } from "../types";
|
|
4
|
+
|
|
5
|
+
export interface AnchorProps
|
|
6
|
+
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
7
|
+
/**
|
|
8
|
+
* Palette color or semantic intent.
|
|
9
|
+
* @default "default"
|
|
10
|
+
*/
|
|
11
|
+
color?: ComponentColor | "muted" | "default";
|
|
12
|
+
/**
|
|
13
|
+
* Underline text decoration control.
|
|
14
|
+
* @default "hover"
|
|
15
|
+
*/
|
|
16
|
+
underline?: "hover" | "always" | "none";
|
|
17
|
+
/**
|
|
18
|
+
* Interaction style variant.
|
|
19
|
+
* @default "default"
|
|
20
|
+
*/
|
|
21
|
+
variant?: "default" | "ghost";
|
|
22
|
+
/** Polymorphic component wrapper (e.g. react-router Link, Next.js Link) */
|
|
23
|
+
as?: React.ElementType;
|
|
24
|
+
/** Custom render prop */
|
|
25
|
+
render?: (
|
|
26
|
+
props: React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
27
|
+
) => React.ReactElement;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type LinkProps = AnchorProps;
|
|
31
|
+
|
|
32
|
+
const colorClasses: Record<string, string> = {
|
|
33
|
+
default: "pb:text-gray-900 pb:hover:text-peerbots-darkteal",
|
|
34
|
+
neutral: "pb:text-gray-700 pb:hover:text-gray-950",
|
|
35
|
+
muted: "pb:text-gray-600 pb:hover:text-gray-900",
|
|
36
|
+
teal: "pb:text-peerbots-darkteal pb:hover:text-teal-950 pb:font-semibold",
|
|
37
|
+
pink: "pb:text-rose-800 pb:hover:text-rose-950 pb:font-semibold",
|
|
38
|
+
primary: "pb:text-dark-primary pb:hover:text-teal-950 pb:font-semibold",
|
|
39
|
+
darkteal: "pb:text-peerbots-darkteal pb:hover:text-teal-950 pb:font-semibold",
|
|
40
|
+
darkblue: "pb:text-peerbots-darkblue pb:hover:text-teal-900 pb:font-semibold",
|
|
41
|
+
danger: "pb:text-red-700 pb:hover:text-red-900 pb:font-semibold",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const underlineClasses = {
|
|
45
|
+
hover: "pb:hover:underline pb:underline-offset-4 pb:decoration-current",
|
|
46
|
+
always: "pb:underline pb:underline-offset-4 pb:decoration-current",
|
|
47
|
+
none: "pb:no-underline",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const Anchor = React.forwardRef<HTMLAnchorElement, AnchorProps>(
|
|
51
|
+
(
|
|
52
|
+
{
|
|
53
|
+
className,
|
|
54
|
+
href,
|
|
55
|
+
target,
|
|
56
|
+
color = "default",
|
|
57
|
+
underline = "hover",
|
|
58
|
+
variant = "default",
|
|
59
|
+
as: Component = "a",
|
|
60
|
+
render,
|
|
61
|
+
children,
|
|
62
|
+
...props
|
|
63
|
+
},
|
|
64
|
+
ref,
|
|
65
|
+
) => {
|
|
66
|
+
const commonClass = cn(
|
|
67
|
+
"pb:transition-colors pb:duration-150 pb:cursor-pointer pb:font-medium pb:inline-flex pb:items-center pb:gap-1",
|
|
68
|
+
colorClasses[color] || colorClasses.default,
|
|
69
|
+
underlineClasses[underline],
|
|
70
|
+
variant === "ghost" && "pb:px-2 pb:py-1 pb:rounded-lg pb:hover:bg-gray-100",
|
|
71
|
+
className,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const anchorProps = {
|
|
75
|
+
href,
|
|
76
|
+
target,
|
|
77
|
+
className: commonClass,
|
|
78
|
+
...props,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (render) {
|
|
82
|
+
return render(anchorProps);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Component ref={ref} {...anchorProps}>
|
|
87
|
+
{children}
|
|
88
|
+
</Component>
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
Anchor.displayName = "Anchor";
|
|
94
|
+
|
|
95
|
+
export const Link = Anchor;
|
|
96
|
+
export { Anchor };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { CodeBlock } from "./CodeBlock";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof CodeBlock> = {
|
|
6
|
+
title: "Foundations/CodeBlock",
|
|
7
|
+
component: CodeBlock,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "centered",
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof CodeBlock>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
code: "npm install @peerbots/core",
|
|
20
|
+
language: "bash",
|
|
21
|
+
variant: "default",
|
|
22
|
+
showLineNumbers: false,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const WindowVariant: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
code: `import { Button, Card, Heading } from "@peerbots/core";
|
|
29
|
+
|
|
30
|
+
export function WelcomeCard() {
|
|
31
|
+
return (
|
|
32
|
+
<Card variant="elevated" padding="lg">
|
|
33
|
+
<Heading level={2} variant="marketing-teal">Welcome to Peerbots</Heading>
|
|
34
|
+
<Button variant="marketing-teal">Get Started</Button>
|
|
35
|
+
</Card>
|
|
36
|
+
);
|
|
37
|
+
}`,
|
|
38
|
+
language: "tsx",
|
|
39
|
+
fileName: "WelcomeCard.tsx",
|
|
40
|
+
variant: "window",
|
|
41
|
+
showLineNumbers: true,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const MultiLineWithNumbers: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
code: `const config = {
|
|
48
|
+
apiKey: process.env.PEERBOTS_API_KEY,
|
|
49
|
+
endpoint: "https://api.peerbots.org/v1",
|
|
50
|
+
timeout: 5000,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default config;`,
|
|
54
|
+
language: "typescript",
|
|
55
|
+
variant: "default",
|
|
56
|
+
showLineNumbers: true,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const Variations: Story = {
|
|
61
|
+
render: () => (
|
|
62
|
+
<div className="pb:w-[540px] pb:space-y-6">
|
|
63
|
+
<div>
|
|
64
|
+
<h4 className="pb:text-xs pb:font-bold pb:text-gray-500 pb:uppercase pb:mb-2">
|
|
65
|
+
Standard Clean CodeBlock (Default)
|
|
66
|
+
</h4>
|
|
67
|
+
<CodeBlock
|
|
68
|
+
code="git clone https://github.com/peerbots/peerbots-core.git"
|
|
69
|
+
language="bash"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div>
|
|
74
|
+
<h4 className="pb:text-xs pb:font-bold pb:text-gray-500 pb:uppercase pb:mb-2">
|
|
75
|
+
Window / File Box Variant
|
|
76
|
+
</h4>
|
|
77
|
+
<CodeBlock
|
|
78
|
+
code="echo 'Running robot face session...'"
|
|
79
|
+
language="bash"
|
|
80
|
+
fileName="start.sh"
|
|
81
|
+
variant="window"
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
),
|
|
86
|
+
};
|