diff --git a/packages/react-ui/src/components/Label/stories/Label.stories.tsx b/packages/react-ui/src/components/Label/stories/Label.stories.tsx new file mode 100644 index 000000000..a9e93a07b --- /dev/null +++ b/packages/react-ui/src/components/Label/stories/Label.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Label } from "../Label"; + +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Just a label", + required: false, + disabled: false, + className: "openui-label", + style: { color: "black" }, + }, + parameters: { + docs: { + description: { + story: "A basic label component.", + }, + }, + }, +}; + +export const Required: Story = { + args: { + children: "Required label", + required: true, + disabled: false, + }, + parameters: { + docs: { + description: { + story: "A label with a required indicator.", + }, + }, + }, +}; + +export const Disabled: Story = { + args: { + children: "Disabled label", + required: false, + disabled: true, + }, + parameters: { + docs: { + description: { + story: "A disabled label state.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/Label", + component: Label, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { Label } from '@openuidev/react-ui';\n```", + }, + }, + }, + argTypes: { + children: { + control: "text", + }, + required: { + control: "boolean", + table: { + category: "State", + defaultValue: { summary: "false" }, + }, + }, + disabled: { + control: "boolean", + table: { + category: "State", + defaultValue: { summary: "false" }, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/Modal/stories/Modal.stories.tsx b/packages/react-ui/src/components/Modal/stories/Modal.stories.tsx new file mode 100644 index 000000000..ca6c0b731 --- /dev/null +++ b/packages/react-ui/src/components/Modal/stories/Modal.stories.tsx @@ -0,0 +1,76 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { useState } from "react"; +import { Button } from "../../Button"; +import { Modal } from "../Modal"; + +type Story = StoryObj; + +export const Default: Story = { + args: { + title: "Modal title", + children: "This is the modal content.", + size: "md", + }, + render: (args) => { + const [open, setOpen] = useState(false); + + return ( + <> + + + + {args.children} + + + ); + }, + parameters: { + docs: { + description: { + story: "A basic modal component opened by a button.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/Modal", + component: Modal, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { Modal } from '@openuidev/react-ui';\n```", + }, + }, + controls: { + exclude: ["open", "onOpenChange"], + }, + }, + argTypes: { + title: { + control: "text", + }, + children: { + control: "text", + }, + size: { + control: "radio", + options: ["sm", "md", "lg"], + table: { + defaultValue: { summary: "md" }, + }, + }, + open: { + control: false, + table: { + disable: true, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/SectionBlock/stories/SectionBlock.stories.tsx b/packages/react-ui/src/components/SectionBlock/stories/SectionBlock.stories.tsx new file mode 100644 index 000000000..47607a9bc --- /dev/null +++ b/packages/react-ui/src/components/SectionBlock/stories/SectionBlock.stories.tsx @@ -0,0 +1,56 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { SectionV2 } from "../SectionV2"; + +type Story = StoryObj; + +export const Default: Story = { + args: { + trigger: "Section title", + children: "This is the section content.", + }, + parameters: { + docs: { + description: { + story: "A basic section block with a trigger and content.", + }, + }, + }, +}; + +export const WithLongContent: Story = { + args: { + trigger: "Details", + children: "This section can be used to group related content under a visual section heading.", + }, + parameters: { + docs: { + description: { + story: "A section block with longer content.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/SectionBlock", + component: SectionV2, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { SectionV2 } from '@openuidev/react-ui';\n```", + }, + }, + }, + argTypes: { + trigger: { + control: "text", + }, + children: { + control: "text", + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/ThemeProvider/stories/ThemeProvider.stories.tsx b/packages/react-ui/src/components/ThemeProvider/stories/ThemeProvider.stories.tsx new file mode 100644 index 000000000..28015f920 --- /dev/null +++ b/packages/react-ui/src/components/ThemeProvider/stories/ThemeProvider.stories.tsx @@ -0,0 +1,180 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Button } from "../../Button"; +import { Label } from "../../Label"; +import { ThemeProvider } from "../ThemeProvider"; + +type Story = StoryObj; + +export const Default: Story = { + args: { + mode: "light", + }, + render: (args) => ( + +
+ + + +
+
+ ), + parameters: { + docs: { + description: { + story: "A basic ThemeProvider example wrapping OpenUI components.", + }, + }, + }, +}; + +export const DarkMode: Story = { + args: { + mode: "dark", + }, + render: (args) => ( + +
+ + + +
+
+ ), + parameters: { + docs: { + description: { + story: "ThemeProvider rendered with dark mode enabled.", + }, + }, + }, +}; + +export const CustomTheme: Story = { + args: { + mode: "light", + }, + render: (args) => ( + +
+ + + +
+
+ ), + parameters: { + docs: { + description: { + story: "ThemeProvider with custom light theme token overrides.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/ThemeProvider", + component: ThemeProvider, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { ThemeProvider } from '@openuidev/react-ui';\n```", + }, + }, + controls: { + exclude: ["children", "lightTheme", "darkTheme", "theme", "cssSelector"], + }, + }, + argTypes: { + mode: { + control: "radio", + options: ["light", "dark"], + table: { + category: "Appearance", + defaultValue: { summary: "light" }, + }, + }, + children: { + control: false, + table: { + disable: true, + }, + }, + lightTheme: { + control: false, + table: { + disable: true, + }, + }, + darkTheme: { + control: false, + table: { + disable: true, + }, + }, + theme: { + control: false, + table: { + disable: true, + }, + }, + cssSelector: { + control: false, + table: { + disable: true, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/ToggleItem/stories/ToggleItem.stories.tsx b/packages/react-ui/src/components/ToggleItem/stories/ToggleItem.stories.tsx new file mode 100644 index 000000000..d15e0b78b --- /dev/null +++ b/packages/react-ui/src/components/ToggleItem/stories/ToggleItem.stories.tsx @@ -0,0 +1,105 @@ +import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"; +import type { Meta, StoryObj } from "@storybook/react"; +import { ToggleItem } from "../ToggleItem"; + +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Just a toggle", + value: "toggle", + disabled: false, + }, + render: (args) => ( + + + {args.children} + + + ), + parameters: { + docs: { + description: { + story: "A basic toggle item rendered inside a single-select toggle group.", + }, + }, + }, +}; + +export const Disabled: Story = { + args: { + children: "Disabled toggle", + value: "disabled", + disabled: true, + }, + render: (args) => ( + + + {args.children} + + + ), + parameters: { + docs: { + description: { + story: "A disabled toggle item.", + }, + }, + }, +}; + +export const Multiple: Story = { + render: () => ( + + Bold + Italic + Underline + + ), + parameters: { + docs: { + description: { + story: "Multiple toggle items rendered inside a multi-select toggle group.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/ToggleItem", + component: ToggleItem, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { ToggleItem } from '@openuidev/react-ui';\n```", + }, + }, + controls: { + exclude: ["className"], + }, + }, + argTypes: { + children: { + control: "text", + }, + value: { + control: "text", + description: "Unique value that identifies this item inside the toggle group.", + }, + disabled: { + control: "boolean", + table: { + category: "State", + }, + }, + className: { + table: { + disable: true, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/ToolCall/stories/ToolCall.stories.tsx b/packages/react-ui/src/components/ToolCall/stories/ToolCall.stories.tsx new file mode 100644 index 000000000..73192299f --- /dev/null +++ b/packages/react-ui/src/components/ToolCall/stories/ToolCall.stories.tsx @@ -0,0 +1,166 @@ +import type { ToolCall } from "@openuidev/react-headless"; +import type { Meta, StoryObj } from "@storybook/react"; +import { ToolCallComponent } from "../ToolCall"; + +type Story = StoryObj; + +const plainToolCall: ToolCall = { + id: "tool-call-1", + type: "function", + function: { + name: "search", + arguments: JSON.stringify( + { + query: "OpenUI Storybook components", + limit: 5, + }, + null, + 2, + ), + }, +}; + +const requestResponseToolCall: ToolCall = { + id: "tool-call-2", + type: "function", + function: { + name: "get_weather", + arguments: JSON.stringify( + { + _request: { + location: "Florianópolis, SC", + unit: "celsius", + }, + _response: { + temperature: 24, + condition: "Partly cloudy", + }, + }, + null, + 2, + ), + }, +}; + +const streamingToolCall: ToolCall = { + id: "tool-call-3", + type: "function", + function: { + name: "generate_report", + arguments: JSON.stringify( + { + _request: { + topic: "Weekly usage summary", + format: "markdown", + }, + }, + null, + 2, + ), + }, +}; + +export const Default: Story = { + args: { + toolCall: plainToolCall, + isStreaming: false, + toolsDone: true, + isLast: false, + }, + parameters: { + docs: { + description: { + story: "A basic tool call with plain function arguments.", + }, + }, + }, +}; + +export const WithRequestAndResponse: Story = { + args: { + toolCall: requestResponseToolCall, + isStreaming: false, + toolsDone: true, + isLast: false, + }, + parameters: { + docs: { + description: { + story: "A completed tool call displaying request and response payloads.", + }, + }, + }, +}; + +export const Streaming: Story = { + args: { + toolCall: streamingToolCall, + isStreaming: true, + toolsDone: false, + isLast: true, + }, + parameters: { + docs: { + description: { + story: "A running tool call while the tool response is still streaming.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/ToolCall", + component: ToolCallComponent, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { ToolCallComponent } from '@openuidev/react-ui';\n```", + }, + }, + controls: { + exclude: ["className"], + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + toolCall: { + control: "object", + table: { + category: "Data", + }, + }, + isStreaming: { + control: "boolean", + table: { + category: "State", + }, + }, + toolsDone: { + control: "boolean", + table: { + category: "State", + }, + }, + isLast: { + control: "boolean", + table: { + category: "State", + }, + }, + className: { + table: { + disable: true, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta; diff --git a/packages/react-ui/src/components/ToolResult/stories/ToolResult.stories.tsx b/packages/react-ui/src/components/ToolResult/stories/ToolResult.stories.tsx new file mode 100644 index 000000000..3d508bf2e --- /dev/null +++ b/packages/react-ui/src/components/ToolResult/stories/ToolResult.stories.tsx @@ -0,0 +1,118 @@ +import type { ToolMessage } from "@openuidev/react-headless"; +import type { Meta, StoryObj } from "@storybook/react"; +import { ToolResult } from "../ToolResult"; + +type Story = StoryObj; + +const successMessage = { + content: JSON.stringify( + { + temperature: 24, + condition: "Partly cloudy", + location: "Florianópolis, SC", + }, + null, + 2, + ), +} as ToolMessage; + +const errorMessage = { + content: JSON.stringify( + { + message: "Unable to fetch weather data.", + }, + null, + 2, + ), + error: "The weather service returned an unavailable response.", +} as ToolMessage; + +const plainMessage = { + content: "Tool completed successfully.", +} as ToolMessage; + +export const Default: Story = { + args: { + message: successMessage, + toolName: "get_weather", + }, + parameters: { + docs: { + description: { + story: "A successful tool result with formatted output.", + }, + }, + }, +}; + +export const Error: Story = { + args: { + message: errorMessage, + toolName: "get_weather", + }, + parameters: { + docs: { + description: { + story: "A tool result with an error message.", + }, + }, + }, +}; + +export const WithoutToolName: Story = { + args: { + message: plainMessage, + }, + parameters: { + docs: { + description: { + story: "A tool result without a resolved tool name.", + }, + }, + }, +}; + +const meta: Meta = { + title: "Components/ToolResult", + component: ToolResult, + parameters: { + layout: "centered", + docs: { + description: { + component: "```tsx\nimport { ToolResult } from '@openuidev/react-ui';\n```", + }, + }, + controls: { + exclude: ["className"], + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + message: { + control: "object", + table: { + category: "Data", + }, + }, + toolName: { + control: "text", + table: { + category: "Data", + }, + }, + className: { + table: { + disable: true, + }, + }, + }, + tags: ["autodocs", "!dev"], +}; + +export default meta;