Skip to content

Commit

Permalink
Improve API docs for menu button component (#2027)
Browse files Browse the repository at this point in the history
# Pull Request

## 🀨 Rationale

As part of #824 we want to improve the accuracy and comprehensiveness of
our storybook API documentation.

## πŸ‘©β€πŸ’» Implementation

Apply the following patterns to the menu button docs:

1. create sections in the args table for attributes, slots, and events.
(We'd also add methods for components that expose interesting ones)
2. Ensure the title and description are accurate for each member
3. link to shared docs about component APIs. 

Other minor bug fixes:
1. hide the "patterns" page from public storybook
2. hide text from βœ… icon mapping in component status table

### Possible follow up work

1. update doc templates and the docs for other existing components
similarly
1. more detailed API overview docs
- explanation of event patterns in web components and how they map to
frameworks
    - using forms instead of change events
1. see if we can remove the type annotation from control descriptions
2. [wait for further feedback] more curated examples and highlight most
important APIs for each component
1. [out of scope] I wish I could hide the Default column since we don't
bother populating it but that doesn't seem to be possible
storybookjs/storybook#15780


## πŸ§ͺ Testing

Manual storybook interaction

## βœ… Checklist

<!--- Review the list and put an x in the boxes that apply or ~~strike
through~~ around items that don't (along with an explanation). -->

- [x] I have updated the project documentation to reflect my changes or
determined no changes are needed.
  • Loading branch information
jattasNI authored Apr 24, 2024
1 parent 97d92f6 commit 1b7dd15
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "Storybook documentation improvements",
"packageName": "@ni/nimble-components",
"email": "[email protected]",
"dependentChangeType": "none"
}
7 changes: 4 additions & 3 deletions packages/nimble-components/.storybook/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ addons.setConfig({
filters: {
patterns: item => {
const isPublicSite = window.location.hostname === 'nimble.ni.dev';
const isItemInternal = item.title.startsWith('Tests/')
|| item.title.startsWith('Internal/')
|| item.title.startsWith('Patterns/');
const title = item.title.toLowerCase();
const isItemInternal = title.startsWith('tests/')
|| title.startsWith('internal/')
|| title.startsWith('patterns/');
const shouldHideInSidebar = isPublicSite && isItemInternal;
return !shouldHideInSidebar;
}
Expand Down
1 change: 1 addition & 0 deletions packages/nimble-components/.storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const parameters = {
expanded: true
},
docs: {
controls: { sort: 'alpha' },
source: {
transform: transformSource
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Controls, Canvas, Meta, Title } from '@storybook/blocks';
import ContentHiddenDocs from '../../patterns/button/tests/content-hidden-docs.mdx';
import StylingDocs from '../../patterns/button/tests/styling-docs.mdx';
import ComponentApisLink from '../../patterns/docs/component-apis-link.mdx';
import { menuButtonTag } from '..';
import * as menuButtonStories from './menu-button.stories';

Expand All @@ -11,8 +12,13 @@ Per [W3C](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/), a menu button
often styled as a typical push button with a downward pointing arrow or triangle to hint that activating the button will display a menu.

<Canvas of={menuButtonStories.outlineButton} />

## API

<Controls of={menuButtonStories.outlineButton} />

<ComponentApisLink />

<StylingDocs components={{ Button: menuButtonTag }} />

{/* ## Usage */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { html, when } from '@microsoft/fast-element';
import { withActions } from '@storybook/addon-actions/decorator';
import type { HtmlRenderer, Meta, StoryObj } from '@storybook/html';
import {
apiCategory,
createUserSelectedThemeStory,
disableStorybookZoomTransform
} from '../../utilities/tests/storybook';
Expand All @@ -17,26 +18,27 @@ import { menuTag } from '../../menu';
import { menuItemTag } from '../../menu-item';
import {
appearanceDescription,
appearanceVariantDescription
appearanceVariantDescription,
contentHiddenDescription,
endIconDescription,
iconDescription
} from '../../patterns/button/tests/doc-strings';

interface MenuButtonArgs {
label: string;
icon: boolean;
endIcon: boolean;
menu: () => void;
appearance: keyof typeof ButtonAppearance;
appearanceVariant: keyof typeof ButtonAppearanceVariant;
open: boolean;
disabled: boolean;
icon: boolean;
contentHidden: boolean;
endIcon: boolean;
menuPosition: string;
toggle: () => void;
beforetoggle: () => void;
}

const endIconDescription = `When including an icon after the text content, set \`slot="end"\` on the icon to ensure proper styling.
This icon will be hidden when \`contentHidden\` is set to \`true\`
.`;

const metadata: Meta<MenuButtonArgs> = {
title: 'Components/Menu Button',
decorators: [withActions<HtmlRenderer>],
Expand All @@ -49,27 +51,73 @@ const metadata: Meta<MenuButtonArgs> = {
}
},
argTypes: {
label: {
name: 'default',
description:
'The text content of the button. This will be hidden when `content-hidden` is set but should always be provided; see the `Accessibility` section for more info.',
table: { category: apiCategory.slots }
},
icon: {
name: 'start',
description: iconDescription,
table: { category: apiCategory.slots }
},
endIcon: {
name: 'end',
description: endIconDescription,
table: { category: apiCategory.slots }
},
menu: {
description:
'The [nimble-menu](./?path=/docs/components-menu--docs) to be displayed when the button is toggled.',
table: { category: apiCategory.slots },
control: false
},
appearance: {
options: Object.keys(ButtonAppearance),
control: { type: 'radio' },
description: appearanceDescription
description: appearanceDescription,
table: { category: apiCategory.attributes }
},
appearanceVariant: {
name: 'appearance-variant',
options: Object.keys(ButtonAppearanceVariant),
control: { type: 'radio' },
description: appearanceVariantDescription
description: appearanceVariantDescription,
table: { category: apiCategory.attributes }
},
icon: {
description:
'When including an icon, set `slot="start"` on the icon to ensure proper styling.'
open: {
control: { type: 'boolean' },
description: 'Opens the menu.',
table: { category: apiCategory.attributes }
},
endIcon: {
description: endIconDescription
disabled: {
control: { type: 'boolean' },
description: 'Disables the button.',
table: { category: apiCategory.attributes }
},
contentHidden: {
name: 'content-hidden',
description: contentHiddenDescription,
table: { category: apiCategory.attributes }
},
menuPosition: {
name: 'menu-position',
description: 'The position of the menu relative to the button.',
options: Object.values(MenuButtonPosition),
control: { type: 'radio' }
control: { type: 'radio' },
table: { category: apiCategory.attributes }
},
toggle: {
description: 'Fires after the menu button is toggled.',
table: { category: apiCategory.events },
control: false
},
beforetoggle: {
description:
'Fires before the menu button is toggled. This can be used to populate the menu before it is opened.',
table: { category: apiCategory.events },
control: false
}
},
// prettier-ignore
Expand Down Expand Up @@ -105,8 +153,6 @@ const metadata: Meta<MenuButtonArgs> = {
</${menuButtonTag}>
`),
args: {
label: 'Menu Button',
appearance: 'outline',
appearanceVariant: 'default',
open: false,
disabled: false,
Expand All @@ -125,12 +171,21 @@ export const outlineButton: StoryObj<MenuButtonArgs> = {
appearance: ButtonAppearance.outline
}
};

export const ghostButton: StoryObj<MenuButtonArgs> = {
args: { label: 'Ghost Menu Button', appearance: ButtonAppearance.ghost }
args: {
label: 'Ghost Menu Button',
appearance: ButtonAppearance.ghost
}
};

export const blockButton: StoryObj<MenuButtonArgs> = {
args: { label: 'Block Menu Button', appearance: ButtonAppearance.block }
args: {
label: 'Block Menu Button',
appearance: ButtonAppearance.block
}
};

export const iconButton: StoryObj<MenuButtonArgs> = {
args: {
label: 'Icon Menu Button',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const appearanceVariantDescription = 'This attribute has no effect on but

export const contentHiddenDescription = 'When set, this attribute hides the text and end icon, leaving only the start icon visible.';

export const iconDescription = `When including an icon, set \`slot="start"\` on the icon to ensure proper styling.
export const iconDescription = `Set \`slot="start"\` to include an icon before the text content (or instead of the content when \`content-hidden\` is set).
<details>
<summary>Icon Usage</summary>
Expand All @@ -29,7 +29,5 @@ export const iconDescription = `When including an icon, set \`slot="start"\` on
</ul>
</details>`;

export const endIconDescription = `When including an icon after the text content, set \`slot="end"\` on the icon to ensure proper styling.
This icon will be hidden when \`contentHidden\` is set to \`true\`
.`;
// 'Set `slot="end"` to include an icon after the text content.'
export const endIconDescription = 'Set `slot="end"` to include an icon after the text content. This icon will be hidden when `content-hidden` is set to `true`.';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
For more information about the structure of Nimble APIs, see [Component APIs](?path=/docs/component-apis--docs).
91 changes: 91 additions & 0 deletions packages/nimble-components/src/tests/component-apis.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Meta } from '@storybook/addon-docs';

<Meta title="Component APIs" />

# Component APIs

This page describes common patterns for programmatically configuring Nimble components.

## Elements

Nimble components are [web component custom elements](https://developer.mozilla.org/en-US/docs/Web/API/Web_components).
Applications can use custom elements directly or use framework-specific APIs for [Angular](https://angular.io/)
or [Blazor](https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor).

Components follow a standard naming convention:

| Name | Purpose | Example |
| ---------------------- | --------------------------------------------------------- | ----------------------- |
| Custom element name | Add the component to HTML | `nimble-button` |
| JavaScript class name | Interact with the component from JavaScript or TypeScript | `NimbleButton` |
| Angular module name | Import the component in Angular | `NimbleButtonModule` |
| Angular directive name | Interact with the component from Angular | `NimbleButtonDirective` |
| Blazor component name | Use the component in Blazor template or C# class | `NimbleButton` |

## Slots

Component content can be configured by inserting it as a child of the component via
[slots](https://developer.mozilla.org/en-US/docs/Web/API/Element/slot).

Content can be inserted in the default slot:

```html
<nimble-button>Click me</nimble-button>
```

Or in a named slot:

```html
<nimble-button>
<nimble-icon-key slot="start"></nimble-icon-key>
Click me
</nimble-button>
```

## Attributes and Properties

Configure components from HTML using attributes or from code using properties. Attributes and properties typically
correspond to each other one-to-one; Nimble documentation refers to the attribute name.

### Attributes

Attributes have `kebab-case` names in HTML and Angular templates.

```html
<nimble-button appearance="outline">...</nimble-button>
```

### Boolean attributes

Boolean attributes don't need a value; they are `true` when present and `false` when absent.

```html
<nimble-button content-hidden>...</nimble-button>
```

### Properties

Properties have `camelCase` names in JavaScript, TypeScript, and Angular.

```ts
const button = document.querySelector('nimble-button');
button.appearance = ButtonAppearance.outline;
```

### Blazor

In Blazor, properties and attributes have `PascalCase` names. For values that are enumerations of strings, the type is a C# enum.

```
<NimbleButton Appearance="ButtonAppearance.Outline">...</NimbleButton>
```

## Methods

Some components expose methods for providing complex data or invoking operations. Methods are only available in code, not in HTML.

## Events

Components raise events to notify the application of changes or user interactions.
Prefer to use documented Nimble events when available rather than native DOM events as they cover more user interactions
(for example, `change` will be raised for both click and keyboard interactions).
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ const components = [
] as const;

const iconMappings = html`
<${mappingIconTag} key="${ComponentFrameworkStatus.ready}" text="Ready" icon="${iconCheckTag}" severity="success"></${mappingIconTag}>
<${mappingIconTag} key="${ComponentFrameworkStatus.ready}" text="Ready" icon="${iconCheckTag}" severity="success" text-hidden></${mappingIconTag}>
<${mappingIconTag} key="${ComponentFrameworkStatus.incubating}" text="Incubating" icon="${iconTriangleTag}" severity="warning"></${mappingIconTag}>
<${mappingIconTag} key="${ComponentFrameworkStatus.doesNotExist}" text="Does not exist" icon="${iconXmarkTag}" severity="error"></${mappingIconTag}>
`;
Expand Down
7 changes: 7 additions & 0 deletions packages/nimble-components/src/utilities/tests/storybook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,10 @@ export const disableStorybookZoomTransform = `
}
</style>
`;

export const apiCategory = {
attributes: 'Attributes',
events: 'Events',
methods: 'Methods',
slots: 'Slots'
} as const;

0 comments on commit 1b7dd15

Please sign in to comment.