-
Notifications
You must be signed in to change notification settings - Fork 1
feat(components): add TopBar component (DS-5242)
#444
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
db739ad
feat(TopBar): add initial draft implementation
KamilEmeleev f61245d
chore(TopBar): finalize responsive layout behavior
KamilEmeleev de900cc
Merge branch 'main' into feat/ds-5242
KamilEmeleev 315016e
fix(TopBar): resolve public API and data attribute conflicts
KamilEmeleev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| import { | ||
| Meta, | ||
| Story, | ||
| Props, | ||
| Status, | ||
| } from '../../../../../.storybook/components'; | ||
|
|
||
| import * as Stories from './TopBar.stories'; | ||
|
|
||
| <Meta of={Stories} /> | ||
|
|
||
| # TopBar | ||
|
|
||
| <Status variant="experimental" /> | ||
|
|
||
| TopBar is the bar at the top of a page. It shows the page title or the breadcrumbs on the start side | ||
| and the page actions on the end side. | ||
|
|
||
| ## Import | ||
|
|
||
| ```tsx | ||
| import { TopBar } from '@koobiq/react-components'; | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| <Story of={Stories.Base} /> | ||
|
|
||
| The bar holds one container per side. Render only the ones you need. | ||
|
|
||
| ```tsx | ||
| <TopBar> | ||
| <TopBar.Container placement="start"> | ||
| <TopBar.Title>Dashboards</TopBar.Title> | ||
| </TopBar.Container> | ||
|
|
||
| <TopBar.Container placement="end" aria-label="Page actions" isToolbar> | ||
| <Button>Create dashboard</Button> | ||
| </TopBar.Container> | ||
| </TopBar> | ||
| ``` | ||
|
|
||
| - `TopBar.Container` — one side of the bar. `placement="start"` grows and shrinks first, | ||
| `placement="end"` sticks to the opposite edge. | ||
| - `TopBar.Title` — the page heading. It renders an `h1` and cuts long text with an ellipsis. | ||
|
|
||
| By default, TopBar keeps at least `80px` between the two sides. Use `--kbq-top-bar-gap` to override | ||
| it. | ||
|
|
||
| ## Props | ||
|
|
||
| <Props of={Stories.Base} /> | ||
|
|
||
| ## Logo and counter | ||
|
|
||
| A logo and an object counter are plain content of the start container — TopBar has no slots for them. | ||
|
|
||
| <Story of={Stories.WithLogoAndCounter} /> | ||
|
|
||
| ## Position | ||
|
|
||
| Use `position` to choose how the bar sits on the page: | ||
|
|
||
| - `sticky` (default) — the bar pins to the top of the nearest scrolling ancestor. | ||
| - `static` — the bar stays in the flow. | ||
|
|
||
| The bar always stays in the flow, so the page content never needs a top offset. | ||
|
|
||
| <Story of={Stories.Position} /> | ||
|
|
||
| ## Shadow | ||
|
|
||
| The `hasShadow` prop only paints the bottom shadow. TopBar never listens to scrolling — watch the scroll | ||
| position yourself and pass the result in. | ||
|
|
||
| <Story of={Stories.Shadow} /> | ||
|
|
||
| ## Breadcrumbs | ||
|
|
||
| Put [Breadcrumbs](?path=/docs/components-breadcrumbs--docs) in the start container. They collapse on | ||
| their own — you do not need to add any logic around them. | ||
|
|
||
| <Story of={Stories.WithBreadcrumbs} /> | ||
|
|
||
| ## Collapsing actions | ||
|
|
||
| Use [useHideOverflowItems](?path=/docs/hooks-usehideoverflowitems--docs) and a `Menu` to collapse | ||
| overflowing actions under a "…" button. | ||
|
|
||
| <Story of={Stories.CollapsingActions} /> | ||
|
|
||
| The example reserves `160px` for the logo and collapsed Breadcrumbs. The `busy` value also includes | ||
| the container gap and TopBar inline padding, so Breadcrumbs collapse before the actions. | ||
|
|
||
| ## CSS variables | ||
|
|
||
| These optional variables override the component's internal values. | ||
|
|
||
| | Variable | Purpose | | ||
| | ----------------------------------------------- | --------------------------------------------------- | | ||
| | `--kbq-top-bar-background` | Background of the bar. | | ||
| | `--kbq-top-bar-padding-block` | Block padding. | | ||
| | `--kbq-top-bar-padding-inline` | Inline padding. | | ||
| | `--kbq-top-bar-border-radius` | Border radius. | | ||
| | `--kbq-top-bar-min-block-size` | Minimum block size of the bar. | | ||
| | `--kbq-top-bar-gap` | Minimum distance between the two sides. | | ||
| | `--kbq-top-bar-z-index` | Stack order while `sticky`. | | ||
| | `--kbq-top-bar-shadow` | Shadow shown by `hasShadow`. | | ||
| | `--kbq-top-bar-container-start-gap` | Gap between items in the start container. | | ||
| | `--kbq-top-bar-container-start-min-inline-size` | Width the start container keeps for itself. | | ||
| | `--kbq-top-bar-container-end-gap` | Gap between items in the end container. | | ||
| | `--kbq-top-bar-title-min-inline-size` | Smallest width of the title before the end shrinks. | | ||
|
|
||
| ## Accessibility | ||
|
|
||
| - TopBar renders a `header`. Use `as` when the bar is not the banner of the page. | ||
| - `TopBar.Title` renders an `h1`. Use `as` to fit the heading order of your page. | ||
| - Set `isToolbar` on the container with the actions. It adds `role="toolbar"` and lets the user move | ||
| between the actions with the arrow keys, so the whole group takes one Tab stop. | ||
| - Give a toolbar container an `aria-label`, for example `aria-label="Page actions"`. | ||
| - Give icon-only actions an `aria-label`. | ||
43 changes: 43 additions & 0 deletions
43
packages/components/src/components/TopBar/TopBar.module.css
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| .base { | ||
| --top-bar-background: var(--kbq-background-bg); | ||
| --top-bar-padding-block: var(--kbq-size-m); | ||
| --top-bar-padding-inline: var(--kbq-size-xxl); | ||
| --top-bar-border-radius: 0; | ||
| --top-bar-min-block-size: var(--kbq-size-6xl); | ||
| --top-bar-gap: 80px; | ||
| --top-bar-z-index: var(--kbq-layer-topbar); | ||
| --top-bar-shadow: var(--kbq-shadow-overflow-normal-bottom); | ||
| --top-bar-container-start-gap: 0; | ||
| --top-bar-container-start-min-inline-size: 0; | ||
| --top-bar-container-end-gap: var(--kbq-size-s); | ||
| --top-bar-title-min-inline-size: 4ch; | ||
|
|
||
| display: flex; | ||
| box-sizing: border-box; | ||
| align-items: center; | ||
| min-block-size: var( | ||
| --kbq-top-bar-min-block-size, | ||
| var(--top-bar-min-block-size) | ||
| ); | ||
| gap: var(--kbq-top-bar-gap, var(--top-bar-gap)); | ||
| padding-block: var(--kbq-top-bar-padding-block, var(--top-bar-padding-block)); | ||
| padding-inline: var( | ||
| --kbq-top-bar-padding-inline, | ||
| var(--top-bar-padding-inline) | ||
| ); | ||
| border-radius: var(--kbq-top-bar-border-radius, var(--top-bar-border-radius)); | ||
| background: var(--kbq-top-bar-background, var(--top-bar-background)); | ||
| transition: box-shadow var(--kbq-transition-slow); | ||
| } | ||
|
|
||
| /* position */ | ||
| .base[data-position='sticky'] { | ||
| position: sticky; | ||
| z-index: var(--kbq-top-bar-z-index, var(--top-bar-z-index)); | ||
| inset-block-start: 0; | ||
| } | ||
|
|
||
| /* shadow */ | ||
| .base[data-shadow='true'] { | ||
| box-shadow: var(--kbq-top-bar-shadow, var(--top-bar-shadow)); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.