Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs move intro storybook react ts #800

Merged
merged 2 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/composite-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'جمّع مكون مركب'
tocTitle: 'مكون مركب'
description: 'جمّع مكون مركب من مكونات بسيطة'
commit: '429780a'
commit: 'cfa25b6'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'اربط البيانات'
tocTitle: 'البياتات'
description: 'تعلم كيفية ربط البيانات مع مكون واجهة المستخدم'
commit: 'c70ec15'
commit: 'f9eaeef'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'أطلق ستوريبوك'
tocTitle: 'أطلق'
description: 'تعلم كيفية إطلاق ستوريبوك أونلاين'
commit: '59da1ac'
commit: '4531813'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'دروس ستوريبوك مع رياكت'
tocTitle: '!ابدأ'
description: 'جهّز ستوريبوك في بيئة التطوير الخاصة بك'
commit: 'bf3514f'
commit: '2407c3c'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'أنشئ واجهة'
tocTitle: 'واجهات'
description: 'أنشئ واجهة من المكونات'
commit: '2275632'
commit: '6262d7f'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/simple-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'قم ببناء مكون بسيط'
tocTitle: 'مكون بسيط'
description: 'قم ببناء مكون بسيط بشكل منعزل'
commit: '9b36e1a'
commit: 'bc897c5'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/ar/using-addons.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'الإضافات'
tocTitle: 'الإضافات'
description: 'تعلم كيفية دمج و استخدام إضافات ضبط مشهورة'
commit: 'f89cfe0'
commit: '17d3ab9'
---

<div style="direction: rtl">
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/de/composite-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Baue eine Komposition'
tocTitle: 'Komposition'
description: 'Setze eine Komposition aus einfachen Komponenten zusammen'
commit: '429780a'
commit: 'cfa25b6'
---

Im letzten Kapitel haben wir unsere erste Komponente entwickelt; in diesem Kapitel erweitern wir das Gelernte, um `TaskList` zu bauen, eine Liste von Aufgaben. Lass uns Komponenten miteinander kombinieren und sehen, was passiert, wenn mehr Komplexität ins Spiel kommt.
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/de/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Daten einbinden'
tocTitle: 'Daten'
description: 'Lerne, Daten in deine UI-Komponente einzubinden'
commit: 'c70ec15'
commit: 'f9eaeef'
---

Bisher haben wir isolierte, zustandslose Komponenten erstellt - perfekt für Storybook, aber letztlich nutzlos, bis wir ihnen einige Daten in unserer App zur Verfügung stellen.
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/de/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Storybook für React Tutorial'
tocTitle: 'Leg los'
description: 'Richte Storybook in deiner Entwicklungsumgebung ein'
commit: 'bf3514f'
commit: '2407c3c'
---

Storybook läuft parallel zu deiner App im Entwicklungs-Modus. Es hilft dir, UI-Komponenten unabhängig von Business-Logik und vom Kontext deiner App zu entwickeln. Diese Edition von "Lerne Storybook" ist für React; es gibt andere Editionen für [Vue](/intro-to-storybook/vue/en/get-started) und [Angular](/intro-to-storybook/angular/en/get-started).
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/de/screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Einen Screen erstellen'
tocTitle: 'Screens'
description: 'Stelle einen Screen aus Komponenten zusammen'
commit: '2275632'
commit: '6262d7f'
---

Bisher haben wir uns darauf konzentriert, UIs bottom-up zu bauen; klein starten und Komplexität hinzufügen. Das erlaubte uns, jede Komponente in Isolation zu entwickeln, ihre Anforderungen an Daten zu ermitteln und damit in Storybook herumzuspielen. All das, ohne einen Server aufzusetzen oder Screens zu erstellen.
Expand Down
2 changes: 1 addition & 1 deletion content/intro-to-storybook/react/de/simple-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Baue eine einfache Komponente'
tocTitle: 'Einfache Komponente'
description: 'Baue eine einfache Komponente in Isolation'
commit: '9b36e1a'
commit: 'bc897c5'
---

Beim Bauen unserer UI werden wir nach der [Component-Driven Development](https://www.componentdriven.org/) (CDD) Methodik vorgehen. Das it ein Vorgehen, in dem UIs "bottom up" entwickelt werden. Man beginnt mit Komponenten und endet mit Screens. CDD hilft dabei, die Komplexität zu begrenzen, mit der man beim Bauen einer UI konfrontiert wird.
Expand Down
151 changes: 59 additions & 92 deletions content/intro-to-storybook/react/en/composite-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Assemble a composite component'
tocTitle: 'Composite component'
description: 'Assemble a composite component out of simpler components'
commit: '429780a'
commit: 'cfa25b6'
---

Last chapter, we built our first component; this chapter extends what we learned to make TaskList, a list of Tasks. Let’s combine components together and see what happens when we introduce more complexity.
Expand All @@ -19,14 +19,32 @@ Since `Task` data can be sent asynchronously, we **also** need a loading state t

## Get set up

A composite component isn’t much different from the basic components it contains. Create a `TaskList` component and an accompanying story file: `src/components/TaskList.jsx` and `src/components/TaskList.stories.jsx`.
A composite component isn’t much different from the basic components it contains. Create a `TaskList` component and an accompanying story file: `src/components/TaskList.tsx` and `src/components/TaskList.stories.tsx`.

Start with a rough implementation of the `TaskList`. You’ll need to import the `Task` component from earlier and pass in the attributes and actions as inputs.

```jsx:title=src/components/TaskList.jsx
```tsx:title=src/components/TaskList.tsx
import type { TaskData } from '../types';

import Task from './Task';

export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {
type TaskListProps = {
/** Checks if it's in loading state */
loading?: boolean;
/** The list of tasks */
tasks: TaskData[];
/** Event to change the task to pinned */
onPinTask: (id: string) => void;
/** Event to change the task to archived */
onArchiveTask: (id: string) => void;
};

export default function TaskList({
loading = false,
tasks,
onPinTask,
onArchiveTask,
}: TaskListProps) {
const events = {
onPinTask,
onArchiveTask,
Expand All @@ -42,7 +60,7 @@ export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {

return (
<div className="list-items">
{tasks.map(task => (
{tasks.map((task) => (
<Task key={task.id} task={task} {...events} />
))}
</div>
Expand All @@ -52,25 +70,30 @@ export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {

Next, create `Tasklist`’s test states in the story file.

```jsx:title=src/components/TaskList.stories.jsx
```tsx:title=src/components/TaskList.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';

import TaskList from './TaskList';

import * as TaskStories from './Task.stories';

export default {
const meta = {
component: TaskList,
title: 'TaskList',
decorators: [(story) => <div style={{ margin: '3rem' }}>{story()}</div>],
tags: ['autodocs'],
tags: ["autodocs"],
args: {
...TaskStories.ActionsData,
},
};
} satisfies Meta<typeof TaskList>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default = {
export const Default: Story = {
args: {
// Shaping the stories through args composition.
// The data was inherited from the Default story in Task.stories.jsx.
// The data was inherited from the Default story in Task.stories.tsx.
tasks: [
{ ...TaskStories.Default.args.task, id: '1', title: 'Task 1' },
{ ...TaskStories.Default.args.task, id: '2', title: 'Task 2' },
Expand All @@ -82,7 +105,7 @@ export const Default = {
},
};

export const WithPinnedTasks = {
export const WithPinnedTasks: Story = {
args: {
tasks: [
...Default.args.tasks.slice(0, 5),
Expand All @@ -91,14 +114,14 @@ export const WithPinnedTasks = {
},
};

export const Loading = {
export const Loading: Story = {
args: {
tasks: [],
loading: true,
},
};

export const Empty = {
export const Empty: Story = {
args: {
// Shaping the stories through args composition.
// Inherited data coming from the Loading story.
Expand Down Expand Up @@ -129,10 +152,28 @@ Now check Storybook for the new `TaskList` stories.

Our component is still rough, but now we have an idea of the stories to work toward. You might be thinking that the `.list-items` wrapper is overly simplistic. You're right – in most cases, we wouldn’t create a new component just to add a wrapper. But the **real complexity** of the `TaskList` component is revealed in the edge cases `withPinnedTasks`, `loading`, and `empty`.

```jsx:title=src/components/TaskList.jsx
```tsx:title=src/components/TaskList.tsx
import type { TaskData } from '../types';

import Task from './Task';

export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {
type TaskListProps = {
/** Checks if it's in loading state */
loading?: boolean;
/** The list of tasks */
tasks: TaskData[];
/** Event to change the task to pinned */
onPinTask: (id: string) => void;
/** Event to change the task to archived */
onArchiveTask: (id: string) => void;
};

export default function TaskList({
loading = false,
tasks,
onPinTask,
onArchiveTask,
}: TaskListProps) {
const events = {
onPinTask,
onArchiveTask,
Expand Down Expand Up @@ -170,8 +211,8 @@ export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {
}

const tasksInOrder = [
...tasks.filter((t) => t.state === 'TASK_PINNED'),
...tasks.filter((t) => t.state !== 'TASK_PINNED'),
...tasks.filter((t) => t.state === "TASK_PINNED"),
...tasks.filter((t) => t.state !== "TASK_PINNED"),
];
return (
<div className="list-items">
Expand All @@ -194,80 +235,6 @@ The added markup results in the following UI:

Note the position of the pinned item in the list. We want the pinned item to render at the top of the list to make it a priority for our users.

## Data requirements and props

As the component grows, so do input requirements. Define the prop requirements of `TaskList`. Because `Task` is a child component, make sure to provide data in the right shape to render it. To save time and headache, reuse the `propTypes` you defined in `Task` earlier.

```diff:title=src/components/TaskList.jsx
+ import PropTypes from 'prop-types';

import Task from './Task';

export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {
const events = {
onPinTask,
onArchiveTask,
};
const LoadingRow = (
<div className="loading-item">
<span className="glow-checkbox" />
<span className="glow-text">
<span>Loading</span> <span>cool</span> <span>state</span>
</span>
</div>
);
if (loading) {
return (
<div className="list-items" data-testid="loading" key={"loading"}>
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
</div>
);
}
if (tasks.length === 0) {
return (
<div className="list-items" key={"empty"} data-testid="empty">
<div className="wrapper-message">
<span className="icon-check" />
<p className="title-message">You have no tasks</p>
<p className="subtitle-message">Sit back and relax</p>
</div>
</div>
);
}

const tasksInOrder = [
...tasks.filter((t) => t.state === 'TASK_PINNED'),
...tasks.filter((t) => t.state !== 'TASK_PINNED'),
];
return (
<div className="list-items">
{tasksInOrder.map((task) => (
<Task key={task.id} task={task} {...events} />
))}
</div>
);
}

+ TaskList.propTypes = {
+ /** Checks if it's in loading state */
+ loading: PropTypes.bool,
+ /** The list of tasks */
+ tasks: PropTypes.arrayOf(Task.propTypes.task).isRequired,
+ /** Event to change the task to pinned */
+ onPinTask: PropTypes.func,
+ /** Event to change the task to archived */
+ onArchiveTask: PropTypes.func,
+ };
+ TaskList.defaultProps = {
+ loading: false,
+ };
```

<div class="aside">
💡 Don't forget to commit your changes with git!
</div>
Loading
Loading