@boostdev/design-system-components 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +25 -4
- package/dist/client.cjs +58 -54
- package/dist/client.css +503 -525
- package/dist/client.js +58 -54
- package/dist/index.cjs +58 -54
- package/dist/index.css +503 -525
- package/dist/index.js +58 -54
- package/dist/web-components/{chunk-6MH5UWUD.js → chunk-2FGATTGT.js} +5 -0
- package/dist/web-components/{chunk-5IPHEONG.js → chunk-6I2DBFQ7.js} +1 -0
- package/dist/web-components/{chunk-DI46Q2EA.js → chunk-OCODKRVZ.js} +57 -82
- package/dist/web-components/index.d.ts +571 -1
- package/dist/web-components/index.js +1501 -4
- package/dist/web-components/interaction/bds-collapsible.js +1 -1
- package/dist/web-components/interaction/bds-drawer.js +1 -1
- package/dist/web-components/interaction/form/bds-segmented-control.js +1 -1
- package/package.json +1 -1
- package/src/components/interaction/Drawer/Drawer.module.css +37 -62
- package/src/components/interaction/Drawer/Drawer.tsx +21 -17
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.mdx +8 -4
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +13 -6
- package/src/stories/Introduction.mdx +2 -1
- package/src/web-components/index.ts +12 -0
- package/src/web-components/interaction/BdsAccordion.mdx +80 -28
- package/src/web-components/interaction/BdsAccordion.stories.tsx +67 -58
- package/src/web-components/interaction/BdsCollapsible.mdx +93 -23
- package/src/web-components/interaction/BdsCollapsible.stories.tsx +29 -48
- package/src/web-components/interaction/BdsDialog.mdx +88 -27
- package/src/web-components/interaction/BdsDialog.stories.tsx +129 -47
- package/src/web-components/interaction/BdsDrawer.mdx +85 -27
- package/src/web-components/interaction/BdsDrawer.stories.tsx +161 -31
- package/src/web-components/interaction/BdsDropdownMenu.mdx +108 -0
- package/src/web-components/interaction/BdsDropdownMenu.stories.tsx +91 -0
- package/src/web-components/interaction/BdsSkipLink.mdx +72 -16
- package/src/web-components/interaction/BdsSkipLink.stories.tsx +47 -34
- package/src/web-components/interaction/BdsTabs.mdx +97 -27
- package/src/web-components/interaction/BdsTabs.stories.tsx +69 -55
- package/src/web-components/interaction/BdsTooltip.mdx +84 -18
- package/src/web-components/interaction/BdsTooltip.stories.tsx +49 -30
- package/src/web-components/interaction/bds-collapsible.ts +1 -0
- package/src/web-components/interaction/bds-drawer.ts +59 -82
- package/src/web-components/interaction/bds-dropdown-menu-item.ts +124 -0
- package/src/web-components/interaction/bds-dropdown-menu.spec.ts +102 -0
- package/src/web-components/interaction/bds-dropdown-menu.ts +200 -0
- package/src/web-components/interaction/form/BdsCheckbox.mdx +57 -20
- package/src/web-components/interaction/form/BdsCheckbox.stories.tsx +35 -36
- package/src/web-components/interaction/form/BdsCheckboxGroup.mdx +70 -0
- package/src/web-components/interaction/form/BdsCheckboxGroup.stories.tsx +81 -0
- package/src/web-components/interaction/form/BdsCombobox.mdx +52 -33
- package/src/web-components/interaction/form/BdsCombobox.stories.tsx +55 -53
- package/src/web-components/interaction/form/BdsFileInput.mdx +59 -24
- package/src/web-components/interaction/form/BdsFileInput.stories.tsx +38 -53
- package/src/web-components/interaction/form/BdsFormInput.mdx +98 -0
- package/src/web-components/interaction/form/BdsFormInput.stories.tsx +139 -0
- package/src/web-components/interaction/form/BdsNumberInput.mdx +51 -22
- package/src/web-components/interaction/form/BdsNumberInput.stories.tsx +24 -46
- package/src/web-components/interaction/form/BdsRadio.mdx +53 -22
- package/src/web-components/interaction/form/BdsRadio.stories.tsx +19 -51
- package/src/web-components/interaction/form/BdsRadioGroup.mdx +73 -0
- package/src/web-components/interaction/form/BdsRadioGroup.stories.tsx +88 -0
- package/src/web-components/interaction/form/BdsSegmentedControl.mdx +76 -23
- package/src/web-components/interaction/form/BdsSegmentedControl.stories.tsx +64 -54
- package/src/web-components/interaction/form/BdsSelect.mdx +59 -21
- package/src/web-components/interaction/form/BdsSelect.stories.tsx +47 -56
- package/src/web-components/interaction/form/BdsSlider.mdx +55 -27
- package/src/web-components/interaction/form/BdsSlider.stories.tsx +23 -44
- package/src/web-components/interaction/form/BdsSwitch.mdx +53 -20
- package/src/web-components/interaction/form/BdsSwitch.stories.tsx +22 -37
- package/src/web-components/interaction/form/BdsTextarea.mdx +54 -22
- package/src/web-components/interaction/form/BdsTextarea.stories.tsx +35 -44
- package/src/web-components/interaction/form/bds-checkbox-group.spec.ts +55 -0
- package/src/web-components/interaction/form/bds-checkbox-group.ts +117 -0
- package/src/web-components/interaction/form/bds-form-input.spec.ts +83 -0
- package/src/web-components/interaction/form/bds-form-input.ts +268 -0
- package/src/web-components/interaction/form/bds-radio-group.spec.ts +62 -0
- package/src/web-components/interaction/form/bds-radio-group.ts +142 -0
- package/src/web-components/interaction/form/bds-segmented-control.ts +5 -0
- package/src/web-components/ui/BdsAvatar.mdx +29 -20
- package/src/web-components/ui/BdsAvatar.stories.tsx +14 -28
- package/src/web-components/ui/BdsBreadcrumb.mdx +22 -19
- package/src/web-components/ui/BdsBreadcrumb.stories.tsx +11 -21
- package/src/web-components/ui/BdsButtonGroup.mdx +69 -0
- package/src/web-components/ui/BdsButtonGroup.stories.tsx +66 -0
- package/src/web-components/ui/BdsCalendar.mdx +93 -0
- package/src/web-components/ui/BdsCalendar.stories.tsx +63 -0
- package/src/web-components/ui/BdsCard.mdx +30 -25
- package/src/web-components/ui/BdsCard.stories.tsx +19 -42
- package/src/web-components/ui/BdsCarousel.mdx +83 -0
- package/src/web-components/ui/BdsCarousel.stories.tsx +96 -0
- package/src/web-components/ui/BdsDescriptionList.mdx +13 -16
- package/src/web-components/ui/BdsDescriptionList.stories.tsx +34 -49
- package/src/web-components/ui/BdsIconWrapper.mdx +20 -20
- package/src/web-components/ui/BdsIconWrapper.stories.tsx +46 -41
- package/src/web-components/ui/BdsLink.mdx +21 -17
- package/src/web-components/ui/BdsLink.stories.tsx +19 -20
- package/src/web-components/ui/BdsLoading.mdx +9 -13
- package/src/web-components/ui/BdsLoading.stories.tsx +8 -10
- package/src/web-components/ui/BdsNotificationBanner.mdx +32 -37
- package/src/web-components/ui/BdsNotificationBanner.stories.tsx +38 -47
- package/src/web-components/ui/BdsPagination.mdx +74 -0
- package/src/web-components/ui/BdsPagination.stories.tsx +36 -0
- package/src/web-components/ui/BdsProgress.mdx +24 -17
- package/src/web-components/ui/BdsProgress.stories.tsx +55 -29
- package/src/web-components/ui/BdsProgressCircle.mdx +24 -18
- package/src/web-components/ui/BdsProgressCircle.stories.tsx +17 -29
- package/src/web-components/ui/BdsRating.mdx +22 -22
- package/src/web-components/ui/BdsRating.stories.tsx +19 -13
- package/src/web-components/ui/BdsSectionHeader.mdx +31 -28
- package/src/web-components/ui/BdsSectionHeader.stories.tsx +21 -23
- package/src/web-components/ui/BdsSeparator.mdx +22 -8
- package/src/web-components/ui/BdsSeparator.stories.tsx +27 -19
- package/src/web-components/ui/BdsSkeleton.mdx +20 -26
- package/src/web-components/ui/BdsSkeleton.stories.tsx +23 -23
- package/src/web-components/ui/BdsTable.mdx +81 -0
- package/src/web-components/ui/BdsTable.stories.tsx +83 -0
- package/src/web-components/ui/BdsTypography.mdx +20 -29
- package/src/web-components/ui/BdsTypography.stories.tsx +19 -18
- package/src/web-components/ui/bds-button-group.spec.ts +40 -0
- package/src/web-components/ui/bds-button-group.ts +78 -0
- package/src/web-components/ui/bds-calendar.spec.ts +91 -0
- package/src/web-components/ui/bds-calendar.ts +427 -0
- package/src/web-components/ui/bds-carousel.spec.ts +64 -0
- package/src/web-components/ui/bds-carousel.ts +296 -0
- package/src/web-components/ui/bds-pagination.spec.ts +67 -0
- package/src/web-components/ui/bds-pagination.ts +197 -0
- package/src/web-components/ui/bds-table.spec.ts +45 -0
- package/src/web-components/ui/bds-table.ts +96 -0
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../index';
|
|
3
|
+
import '../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// Thin React wrapper so Storybook controls work with the custom element's props
|
|
6
|
+
function BdsSkipLink({
|
|
7
|
+
href = '#main',
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
href?: string;
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
}) {
|
|
13
|
+
return React.createElement(
|
|
14
|
+
'bds-skip-link',
|
|
15
|
+
{ href },
|
|
16
|
+
children,
|
|
17
|
+
);
|
|
7
18
|
}
|
|
8
19
|
|
|
9
20
|
const meta = {
|
|
@@ -11,45 +22,47 @@ const meta = {
|
|
|
11
22
|
component: BdsSkipLink,
|
|
12
23
|
tags: ['!stable', 'experimental'],
|
|
13
24
|
parameters: { layout: 'padded' },
|
|
25
|
+
argTypes: {
|
|
26
|
+
href: { control: 'text' },
|
|
27
|
+
},
|
|
14
28
|
} satisfies Meta<typeof BdsSkipLink>;
|
|
15
29
|
|
|
16
30
|
export default meta;
|
|
17
31
|
type Story = StoryObj<typeof meta>;
|
|
18
32
|
|
|
19
33
|
export const Default: Story = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
</div>
|
|
36
|
-
),
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const CustomLabel: Story = {
|
|
40
|
-
render: () => (
|
|
41
|
-
<div style={{ position: 'relative', minHeight: '80px' }}>
|
|
42
|
-
<BdsSkipLink href="#content">Jump to content</BdsSkipLink>
|
|
43
|
-
</div>
|
|
44
|
-
),
|
|
34
|
+
args: { href: '#main' },
|
|
35
|
+
// Hint to the viewer that the link is visually hidden until focused
|
|
36
|
+
decorators: [
|
|
37
|
+
(Story) => (
|
|
38
|
+
<div>
|
|
39
|
+
<p style={{ marginBottom: '0.5rem', fontSize: '0.875rem', color: 'var(--bds-color_on-bg, #333)' }}>
|
|
40
|
+
Tab into the preview to see the skip link appear.
|
|
41
|
+
</p>
|
|
42
|
+
<Story />
|
|
43
|
+
<main id="main" style={{ marginTop: '1rem', padding: '1rem', border: '1px dashed currentcolor' }}>
|
|
44
|
+
Main content area
|
|
45
|
+
</main>
|
|
46
|
+
</div>
|
|
47
|
+
),
|
|
48
|
+
],
|
|
45
49
|
};
|
|
46
50
|
|
|
47
|
-
export const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
|
|
51
|
+
export const WithCustomLabel: Story = {
|
|
52
|
+
args: { href: '#content' },
|
|
53
|
+
render: (args) => (
|
|
54
|
+
<div>
|
|
55
|
+
<p style={{ marginBottom: '0.5rem', fontSize: '0.875rem', color: 'var(--bds-color_on-bg, #333)' }}>
|
|
56
|
+
Tab into the preview to see the skip link appear.
|
|
57
|
+
</p>
|
|
58
|
+
{React.createElement(
|
|
59
|
+
'bds-skip-link',
|
|
60
|
+
{ href: args.href },
|
|
61
|
+
'Skip to main content',
|
|
62
|
+
)}
|
|
63
|
+
<main id="content" style={{ marginTop: '1rem', padding: '1rem', border: '1px dashed currentcolor' }}>
|
|
64
|
+
Main content area
|
|
65
|
+
</main>
|
|
53
66
|
</div>
|
|
54
67
|
),
|
|
55
68
|
};
|
|
@@ -3,45 +3,115 @@ import * as Stories from './BdsTabs.stories';
|
|
|
3
3
|
|
|
4
4
|
<Meta of={Stories} />
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# <bds-tabs>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Framework-agnostic Tabs custom element. Coordinates `<bds-tab>` and `<bds-tab-panel>` children by DOM order, with full keyboard navigation.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or in HTML without a bundler:
|
|
11
19
|
|
|
12
20
|
```html
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<bds-tab-panel slot="panel">
|
|
17
|
-
<p>Overview content.</p>
|
|
18
|
-
</bds-tab-panel>
|
|
19
|
-
<bds-tab-panel slot="panel">
|
|
20
|
-
<p>Details content.</p>
|
|
21
|
-
</bds-tab-panel>
|
|
22
|
-
</bds-tabs>
|
|
21
|
+
<script type="module">
|
|
22
|
+
import '@boostdev/components/web-components';
|
|
23
|
+
</script>
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## When to use
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| `disabled` | `boolean` | `false` | Prevents selecting this tab |
|
|
28
|
+
- Organising related content into sections when only one section is shown at a time
|
|
29
|
+
- Switching between views at the same level of hierarchy
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## When not to use
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
| `ArrowLeft` | Move to previous tab |
|
|
36
|
-
| `ArrowRight`| Move to next tab |
|
|
37
|
-
| `Home` | Move to first tab |
|
|
38
|
-
| `End` | Move to last tab |
|
|
33
|
+
- For navigation between pages — use `<a>` links or a router
|
|
34
|
+
- When all sections should be visible at once — use an accordion or separate sections
|
|
39
35
|
|
|
40
|
-
##
|
|
36
|
+
## Examples
|
|
41
37
|
|
|
38
|
+
### Default
|
|
42
39
|
<Canvas of={Stories.Default} />
|
|
43
|
-
<Canvas of={Stories.AllVariants} />
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
### With disabled tab
|
|
42
|
+
<Canvas of={Stories.WithDisabledTab} />
|
|
43
|
+
|
|
44
|
+
### Many tabs
|
|
45
|
+
<Canvas of={Stories.ManyTabs} />
|
|
46
|
+
|
|
47
|
+
## Props
|
|
46
48
|
|
|
47
49
|
<ArgTypes of={Stories} />
|
|
50
|
+
|
|
51
|
+
## Attributes — `<bds-tabs>`
|
|
52
|
+
|
|
53
|
+
`<bds-tabs>` has no configurable attributes. Tab state and active index are managed internally.
|
|
54
|
+
|
|
55
|
+
## Attributes — `<bds-tab>`
|
|
56
|
+
|
|
57
|
+
| Attribute | Type | Default | Description |
|
|
58
|
+
|-----------|------|---------|-------------|
|
|
59
|
+
| `disabled` | boolean | `false` | Prevents the tab from being selected; tab is skipped during keyboard navigation |
|
|
60
|
+
| `selected` | boolean | `false` | Set by the parent `<bds-tabs>`; do not set manually |
|
|
61
|
+
|
|
62
|
+
## Slots
|
|
63
|
+
|
|
64
|
+
### `<bds-tabs>`
|
|
65
|
+
|
|
66
|
+
| Slot | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `tab` | `<bds-tab>` elements — rendered in the tab list |
|
|
69
|
+
| `panel` | `<bds-tab-panel>` elements — rendered below the tab list |
|
|
70
|
+
|
|
71
|
+
### `<bds-tab>`
|
|
72
|
+
|
|
73
|
+
| Slot | Description |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `(default)` | Tab label text |
|
|
76
|
+
|
|
77
|
+
### `<bds-tab-panel>`
|
|
78
|
+
|
|
79
|
+
| Slot | Description |
|
|
80
|
+
|------|-------------|
|
|
81
|
+
| `(default)` | Panel content displayed when the corresponding tab is selected |
|
|
82
|
+
|
|
83
|
+
## Events
|
|
84
|
+
|
|
85
|
+
| Event | Fired by | Bubbles | Description |
|
|
86
|
+
|-------|----------|---------|-------------|
|
|
87
|
+
| `bds-tab-select` | `<bds-tab>` | Yes | Fired when a tab is clicked; handled internally by `<bds-tabs>` |
|
|
88
|
+
|
|
89
|
+
## Usage in plain HTML
|
|
90
|
+
|
|
91
|
+
Tabs and panels are matched by DOM order (first tab → first panel, etc.):
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<bds-tabs>
|
|
95
|
+
<bds-tab slot="tab">Overview</bds-tab>
|
|
96
|
+
<bds-tab slot="tab">Details</bds-tab>
|
|
97
|
+
<bds-tab slot="tab" disabled>Disabled</bds-tab>
|
|
98
|
+
|
|
99
|
+
<bds-tab-panel slot="panel">
|
|
100
|
+
<p>Overview content</p>
|
|
101
|
+
</bds-tab-panel>
|
|
102
|
+
<bds-tab-panel slot="panel">
|
|
103
|
+
<p>Details content</p>
|
|
104
|
+
</bds-tab-panel>
|
|
105
|
+
<bds-tab-panel slot="panel">
|
|
106
|
+
<p>Disabled tab content (unreachable)</p>
|
|
107
|
+
</bds-tab-panel>
|
|
108
|
+
</bds-tabs>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Accessibility
|
|
112
|
+
|
|
113
|
+
- The tab list container has `role="tablist"`
|
|
114
|
+
- Each `<bds-tab>` renders a `<button role="tab">` with `aria-selected` and the correct `tabindex` (0 for active, -1 for others)
|
|
115
|
+
- Each `<bds-tab-panel>` receives `hidden` when not active
|
|
116
|
+
- Keyboard navigation: ArrowRight / ArrowLeft cycles through enabled tabs; Home / End jumps to first / last enabled tab
|
|
117
|
+
- Disabled tabs are excluded from keyboard navigation
|
|
@@ -1,80 +1,94 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import '../index';
|
|
3
|
+
import '../index'; // auto-registers all custom elements
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Thin React wrapper so Storybook controls work with the custom element's props
|
|
6
|
+
function BdsTabs({
|
|
7
|
+
tabs = ['Overview', 'Details', 'Settings'],
|
|
8
|
+
panels = ['Overview content.', 'Details content.', 'Settings content.'],
|
|
9
|
+
}: {
|
|
10
|
+
tabs?: string[];
|
|
11
|
+
panels?: string[];
|
|
12
|
+
}) {
|
|
6
13
|
return React.createElement(
|
|
7
14
|
'bds-tabs',
|
|
8
15
|
null,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
withDisabled
|
|
12
|
-
? React.createElement('bds-tab', { slot: 'tab', disabled: true }, 'Disabled')
|
|
13
|
-
: React.createElement('bds-tab', { slot: 'tab' }, 'Settings'),
|
|
14
|
-
React.createElement(
|
|
15
|
-
'bds-tab-panel',
|
|
16
|
-
{ slot: 'panel' },
|
|
17
|
-
React.createElement('p', { style: { margin: 0 } }, 'Overview content — general information about this item.'),
|
|
18
|
-
),
|
|
19
|
-
React.createElement(
|
|
20
|
-
'bds-tab-panel',
|
|
21
|
-
{ slot: 'panel' },
|
|
22
|
-
React.createElement('p', { style: { margin: 0 } }, 'Details content — technical specifications and metadata.'),
|
|
16
|
+
...tabs.map(label =>
|
|
17
|
+
React.createElement('bds-tab', { key: label, slot: 'tab' }, label),
|
|
23
18
|
),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
...panels.map((content, i) =>
|
|
20
|
+
React.createElement(
|
|
21
|
+
'bds-tab-panel',
|
|
22
|
+
{ key: i, slot: 'panel' },
|
|
23
|
+
React.createElement('p', { style: { margin: 0 } }, content),
|
|
24
|
+
),
|
|
30
25
|
),
|
|
31
26
|
);
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
// Thin wrapper so Storybook controls work
|
|
35
|
-
function BdsTabs({ withDisabled }: { withDisabled?: boolean }) {
|
|
36
|
-
return React.createElement(TabsDemo, { withDisabled });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
29
|
const meta = {
|
|
40
30
|
title: 'Web Components/Interaction/Tabs',
|
|
41
31
|
component: BdsTabs,
|
|
42
32
|
tags: ['!stable', 'experimental'],
|
|
43
33
|
parameters: { layout: 'padded' },
|
|
44
|
-
argTypes: {
|
|
45
|
-
withDisabled: { control: 'boolean' },
|
|
46
|
-
},
|
|
47
34
|
} satisfies Meta<typeof BdsTabs>;
|
|
48
35
|
|
|
49
36
|
export default meta;
|
|
50
37
|
type Story = StoryObj<typeof meta>;
|
|
51
38
|
|
|
52
|
-
export const Default: Story = {
|
|
53
|
-
|
|
39
|
+
export const Default: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
tabs: ['Overview', 'Details', 'Settings'],
|
|
42
|
+
panels: [
|
|
43
|
+
'Overview content. Use tabs to divide related content into sections.',
|
|
44
|
+
'Details content. Each tab maps to a panel by DOM order.',
|
|
45
|
+
'Settings content. Navigate with ArrowLeft / ArrowRight keys.',
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
54
49
|
|
|
55
|
-
export const
|
|
56
|
-
render: () =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
50
|
+
export const WithDisabledTab: Story = {
|
|
51
|
+
render: () =>
|
|
52
|
+
React.createElement(
|
|
53
|
+
'bds-tabs',
|
|
54
|
+
null,
|
|
55
|
+
React.createElement('bds-tab', { slot: 'tab' }, 'Active'),
|
|
56
|
+
React.createElement('bds-tab', { slot: 'tab', disabled: '' }, 'Disabled'),
|
|
57
|
+
React.createElement('bds-tab', { slot: 'tab' }, 'Another'),
|
|
58
|
+
React.createElement(
|
|
59
|
+
'bds-tab-panel',
|
|
60
|
+
{ slot: 'panel' },
|
|
61
|
+
React.createElement('p', { style: { margin: 0 } }, 'Content for the first tab.'),
|
|
62
|
+
),
|
|
63
|
+
React.createElement(
|
|
64
|
+
'bds-tab-panel',
|
|
65
|
+
{ slot: 'panel' },
|
|
66
|
+
React.createElement('p', { style: { margin: 0 } }, 'This panel is paired with the disabled tab.'),
|
|
67
|
+
),
|
|
68
|
+
React.createElement(
|
|
69
|
+
'bds-tab-panel',
|
|
70
|
+
{ slot: 'panel' },
|
|
71
|
+
React.createElement('p', { style: { margin: 0 } }, 'Content for the third tab.'),
|
|
72
|
+
),
|
|
73
|
+
),
|
|
68
74
|
};
|
|
69
75
|
|
|
70
|
-
export const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
export const ManyTabs: Story = {
|
|
77
|
+
render: () => {
|
|
78
|
+
const labels = ['Dashboard', 'Reports', 'Users', 'Billing', 'Integrations'];
|
|
79
|
+
return React.createElement(
|
|
80
|
+
'bds-tabs',
|
|
81
|
+
null,
|
|
82
|
+
...labels.map(label =>
|
|
83
|
+
React.createElement('bds-tab', { key: label, slot: 'tab' }, label),
|
|
84
|
+
),
|
|
85
|
+
...labels.map((label, i) =>
|
|
86
|
+
React.createElement(
|
|
87
|
+
'bds-tab-panel',
|
|
88
|
+
{ key: i, slot: 'panel' },
|
|
89
|
+
React.createElement('p', { style: { margin: 0 } }, `${label} content area.`),
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
},
|
|
80
94
|
};
|
|
@@ -3,36 +3,102 @@ import * as Stories from './BdsTooltip.stories';
|
|
|
3
3
|
|
|
4
4
|
<Meta of={Stories} />
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# <bds-tooltip>
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Framework-agnostic Tooltip custom element. Displays a small informational label on hover and keyboard focus using CSS-only visibility — no JavaScript positioning required.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **Status: experimental** — API may change before stable release.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import '@boostdev/components/web-components';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or in HTML without a bundler:
|
|
11
19
|
|
|
12
20
|
```html
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
</
|
|
21
|
+
<script type="module">
|
|
22
|
+
import '@boostdev/components/web-components';
|
|
23
|
+
</script>
|
|
16
24
|
```
|
|
17
25
|
|
|
18
|
-
##
|
|
26
|
+
## When to use
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
| `placement` | `"top" \| "bottom" \| "left" \| "right"` | `"top"` | Preferred tooltip placement |
|
|
28
|
+
- Labelling icon-only buttons that have no visible text
|
|
29
|
+
- Providing supplementary information for a UI element without cluttering the layout
|
|
30
|
+
- Short, non-interactive hints (a single sentence or less)
|
|
24
31
|
|
|
25
|
-
##
|
|
32
|
+
## When not to use
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
- For interactive content (links, buttons inside the tooltip) — use `<bds-popover>` instead
|
|
35
|
+
- For error messages or validation feedback — use an inline message
|
|
36
|
+
- For content longer than a short phrase — use `<bds-popover>` or a disclosure pattern
|
|
30
37
|
|
|
31
|
-
##
|
|
38
|
+
## Examples
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
### Default
|
|
41
|
+
<Canvas of={Stories.Default} />
|
|
42
|
+
|
|
43
|
+
### On a button
|
|
44
|
+
<Canvas of={Stories.OnButton} />
|
|
45
|
+
|
|
46
|
+
### Bottom placement
|
|
47
|
+
<Canvas of={Stories.Bottom} />
|
|
48
|
+
|
|
49
|
+
### Left placement
|
|
50
|
+
<Canvas of={Stories.Left} />
|
|
51
|
+
|
|
52
|
+
### Right placement
|
|
53
|
+
<Canvas of={Stories.Right} />
|
|
54
|
+
|
|
55
|
+
### All placements
|
|
34
56
|
<Canvas of={Stories.AllPlacements} />
|
|
35
57
|
|
|
36
|
-
##
|
|
58
|
+
## Props
|
|
37
59
|
|
|
38
60
|
<ArgTypes of={Stories} />
|
|
61
|
+
|
|
62
|
+
## Attributes
|
|
63
|
+
|
|
64
|
+
| Attribute | Type | Default | Description |
|
|
65
|
+
|-----------|------|---------|-------------|
|
|
66
|
+
| `content` | string | `""` | Text to display inside the tooltip |
|
|
67
|
+
| `placement` | `"top" \| "bottom" \| "left" \| "right"` | `"top"` | Where the tooltip appears relative to the trigger |
|
|
68
|
+
|
|
69
|
+
## Slots
|
|
70
|
+
|
|
71
|
+
| Slot | Description |
|
|
72
|
+
|------|-------------|
|
|
73
|
+
| `(default)` | The trigger element (button, icon, etc.) that the tooltip is anchored to |
|
|
74
|
+
|
|
75
|
+
## CSS Custom Properties
|
|
76
|
+
|
|
77
|
+
| Property | Description |
|
|
78
|
+
|----------|-------------|
|
|
79
|
+
| `--tooltip_bg` | Tooltip background colour (default: `var(--bds-color_on-bg)`) |
|
|
80
|
+
| `--tooltip_text` | Tooltip text colour (default: `var(--bds-color_bg)`) |
|
|
81
|
+
|
|
82
|
+
## Usage in plain HTML
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<bds-tooltip content="Save your changes" placement="top">
|
|
86
|
+
<button type="button">Save</button>
|
|
87
|
+
</bds-tooltip>
|
|
88
|
+
|
|
89
|
+
<!-- Icon-only button with tooltip label -->
|
|
90
|
+
<bds-tooltip content="Delete item" placement="bottom">
|
|
91
|
+
<button type="button" aria-label="Delete item">
|
|
92
|
+
<!-- icon SVG -->
|
|
93
|
+
</button>
|
|
94
|
+
</bds-tooltip>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Accessibility
|
|
98
|
+
|
|
99
|
+
- The tooltip panel has `role="tooltip"`
|
|
100
|
+
- Visibility is controlled by `:hover` and `:focus-within` — no JavaScript required
|
|
101
|
+
- The tooltip is rendered adjacent to the trigger inside the same shadow root, so screen readers can read it via proximity
|
|
102
|
+
- Note: `aria-describedby` cannot cross shadow DOM boundaries; if your project requires explicit ARIA association, use `<bds-popover>` instead
|
|
103
|
+
- `pointer-events: none` on the tooltip prevents it from interfering with mouse events
|
|
104
|
+
- Fade transition respects `prefers-reduced-motion`
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import type { TooltipPlacement } from './bds-tooltip';
|
|
4
|
-
import '../index';
|
|
4
|
+
import '../index'; // auto-registers all custom elements
|
|
5
5
|
|
|
6
|
+
// Thin React wrapper so Storybook controls work with the custom element's props
|
|
6
7
|
function BdsTooltip({
|
|
7
|
-
content,
|
|
8
|
-
placement,
|
|
8
|
+
content = 'Tooltip text',
|
|
9
|
+
placement = 'top',
|
|
9
10
|
children,
|
|
10
11
|
}: {
|
|
11
12
|
content?: string;
|
|
@@ -25,6 +26,7 @@ const meta = {
|
|
|
25
26
|
tags: ['!stable', 'experimental'],
|
|
26
27
|
parameters: { layout: 'centered' },
|
|
27
28
|
argTypes: {
|
|
29
|
+
content: { control: 'text' },
|
|
28
30
|
placement: { control: 'select', options: ['top', 'bottom', 'left', 'right'] },
|
|
29
31
|
},
|
|
30
32
|
} satisfies Meta<typeof BdsTooltip>;
|
|
@@ -32,37 +34,54 @@ const meta = {
|
|
|
32
34
|
export default meta;
|
|
33
35
|
type Story = StoryObj<typeof meta>;
|
|
34
36
|
|
|
35
|
-
export const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export const Right: Story = { args: { content: 'Tooltip on right', placement: 'right' } };
|
|
37
|
+
export const Default: Story = {
|
|
38
|
+
args: { content: 'Tooltip text', placement: 'top' },
|
|
39
|
+
};
|
|
39
40
|
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
export const OnButton: Story = {
|
|
42
|
+
args: { content: 'Save your changes', placement: 'top' },
|
|
43
|
+
render: (args) =>
|
|
44
|
+
React.createElement(
|
|
45
|
+
'bds-tooltip',
|
|
46
|
+
{ content: args.content, placement: args.placement },
|
|
47
|
+
React.createElement(
|
|
48
|
+
'button',
|
|
49
|
+
{ type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
|
|
50
|
+
'Save',
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Bottom: Story = {
|
|
56
|
+
args: { content: 'Appears below', placement: 'bottom' },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const Left: Story = {
|
|
60
|
+
args: { content: 'Appears to the left', placement: 'left' },
|
|
52
61
|
};
|
|
53
62
|
|
|
54
|
-
export const
|
|
63
|
+
export const Right: Story = {
|
|
64
|
+
args: { content: 'Appears to the right', placement: 'right' },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const AllPlacements: Story = {
|
|
55
68
|
render: () => (
|
|
56
|
-
<div style={{ display: '
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, auto)', gap: '4rem', padding: '3rem' }}>
|
|
70
|
+
{(['top', 'bottom', 'left', 'right'] as const).map(placement =>
|
|
71
|
+
React.createElement(
|
|
72
|
+
'div',
|
|
73
|
+
{ key: placement, style: { display: 'flex', justifyContent: 'center', alignItems: 'center' } },
|
|
74
|
+
React.createElement(
|
|
75
|
+
'bds-tooltip',
|
|
76
|
+
{ content: `Placement: ${placement}`, placement },
|
|
77
|
+
React.createElement(
|
|
78
|
+
'button',
|
|
79
|
+
{ type: 'button', style: { padding: '0.5rem 1rem', cursor: 'pointer' } },
|
|
80
|
+
placement,
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
)}
|
|
66
85
|
</div>
|
|
67
86
|
),
|
|
68
87
|
};
|
|
@@ -91,6 +91,7 @@ export class BdsCollapsible extends LitElement {
|
|
|
91
91
|
|
|
92
92
|
.content {
|
|
93
93
|
padding: var(--bds-space_m);
|
|
94
|
+
background-color: var(--collapsible_content-bg, var(--bds-color_bg));
|
|
94
95
|
color: var(--collapsible_on-color, var(--bds-color_on-bg));
|
|
95
96
|
font-size: var(--bds-font_size--body);
|
|
96
97
|
line-height: var(--bds-font_line-height--body);
|