Skip to content

Commit

Permalink
2nd draft with changes based on review
Browse files Browse the repository at this point in the history
  • Loading branch information
Aiden-Brine committed Nov 22, 2024
1 parent 5e58ea8 commit d82247c
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ For this example we are going to build a card that allows you to enter a topic
and then search for a related gif.

<Canvas>
<Story name="Composing Components">
<Story name="Gif Gift">
{() => {
const [topic, setTopic] = useState();
const [url, setURL] = useState();
Expand Down Expand Up @@ -183,3 +183,43 @@ The final part of our example defines the custom actions needed to power our
component. In this case the action when the user clicks on the **Search**
button. Here we call the `setURL` setter to show the `loadingGIF`. Then, we call
`setURL` awaiting the async response of `getGIF`.

## Types of Components in Atlantis and their Ability for Customization

#### 1. Primitive Components:

Examples: [Icon](..?path=/docs/components-images-and-icons-icon--docs),
[Avatar](..?path=/docs/components-images-and-icons-avatar--docs)

These components do not accept children and have minimal customization.

#### 2. Simple Components:

Examples: [Button](..?path=/docs/components-actions-button--docs),
[Link](..?path=/docs/components-text-and-typography-link--docs)

These allow basic customization through props or limited children, like
`ReactNode` or specific child types.

#### 3. Compound Components:

Examples: [Chip](..?path=/docs/components-selections-chip--docs),
[DataList](..?path=/docs/components-lists-and-tables-datalist--docs)

These are part of larger compositions and may validate their children types to
maintain internal consistency.

#### 4. Strict Complex Components:

Example:
[Autocomplete](..?path=/docs/components-forms-and-inputs-autocomplete--docs),

These have multiple UI pieces they are built out of but a strict APIs and
limited customization.

#### 5. Customizable Complex Components:

Example: [Combobox](..?path=/docs/components-selections-combobox--docs)

These also have multiple UI pieces they are built out of but offer options for
customization.
187 changes: 0 additions & 187 deletions docs/guides/create-composable-components.stories.mdx

This file was deleted.

77 changes: 77 additions & 0 deletions docs/guides/customizing-components.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Meta } from "@storybook/addon-docs";

<Meta title="Guides/Customizing Components" />

# Customizing Components

### Philosophy: Easy to Use, Flexible to Customize

Atlantis is designed to make building consistent, accessible, and visually
appealing user interfaces as effortless as possible. Our goal is to create
components that work out of the box, requiring minimal setup or configuration
from consumers.

While we strive to cover the most common design scenarios with thoughtful
defaults, we understand that unique use cases may require customization. For
these scenarios, we provide mechanisms to extend or modify our components in a
way that maintains flexibility without compromising the integrity of the
components.

We recommend using the default implementations wherever possible to benefit from
consistency, maintainability, and built in accessibility. However, if you choose
to customize, please note that the responsibility for ensuring proper
functionality and cohesion will rest with you.

Atlantis aims to strike a balance between simplicity, flexibility, and
consistency.

### Primary Customization Approach: Named Render Props

In Atlantis, our primary approach to enabling customization is through named
render props, using the `customRender____` pattern. This method allows consumers
to inject their own UI logic while retaining the default behaviors and
functionality of the component.

#### Example: customRenderItem

Here's an example of how to use a named render prop to customize the rendering
of items in a [List](..?path=/docs/components-lists-and-tables-list--docs)
component:

```tsx
const renderProductItem = item => (
<Flex template={["shrink", "grow"]} align="start">
<Text>{item.price}</Text>
<Heading level={4}>{item.name}</Heading>
</Flex>
);

export const CustomRenderExample = () => (
<List items={items} customRenderItem={renderProductItem} />
);
```

In this example, the default List behavior (such as the main list structure and
handling item interactions) is preserved. Only the presentation of individual
items is customized.

### Other Customization Approaches

While custom render functions are our primary approach it is not used in all
places. For simple cases where customization does not depend on internal state,
we have chosen to extend prop types to allow for a `ReactNode` to be passed in.

#### Example: Tab Component (see [Tabs](..?path=/docs/components-navigation-tabs--docs))

Instead of introducing `customRenderLabel`, the `Tab` component was updated to
allow the `label` prop to accept a `ReactNode`.

```tsx
<Tab label={<MyCustomLabel />} />
```

This approach was chosen to provide a simpler experience for those implementing
Atlantis components. Customizing the `label` didn’t require exposing or
interacting with the `Tab`’s internal state (e.g., active state styling). Once
the design becomes more complex a custom render function would become a better
fit.

0 comments on commit d82247c

Please sign in to comment.