@ember-eui/core 5.0.0-alpha.3 → 5.0.0-alpha.4
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/addon/components/eui-tabbed-content/index.hbs +14 -27
- package/addon/components/eui-tabbed-content/index.ts +134 -0
- package/docs/navigation/tabs-demo/demo1.md +46 -71
- package/docs/navigation/tabs-demo/demo2.md +45 -28
- package/docs/navigation/tabs-demo/demo3.md +57 -27
- package/docs/navigation/tabs-demo/demo4.md +17 -38
- package/docs/navigation/tabs-demo/demo5.md +86 -0
- package/package.json +2 -2
- package/addon/helpers/get-tab-id.ts +0 -23
- package/app/helpers/get-tab-id.js +0 -1
|
@@ -1,45 +1,32 @@
|
|
|
1
|
-
{{#let
|
|
2
|
-
(unique-id)
|
|
3
|
-
(optional @onTabClick)
|
|
4
|
-
(arg-or-default @autoFocus 'initial')
|
|
5
|
-
(use-state
|
|
6
|
-
(get-tab-id
|
|
7
|
-
(arg-or-default (or @selectedTab @initialSelectedTab) (object-at 0 @tabs))
|
|
8
|
-
)
|
|
9
|
-
)
|
|
10
|
-
as |id onTabClick autoFocus selectedTab|
|
|
11
|
-
}}
|
|
1
|
+
{{#let (unique-id) as |rootId|}}
|
|
12
2
|
<div class={{@className}} ...attributes>
|
|
13
3
|
<EuiTabs
|
|
14
|
-
@selectedTab={{selectedTab.value}}
|
|
15
4
|
@expand={{@expand}}
|
|
16
5
|
@display={{@display}}
|
|
17
6
|
@size={{@size}}
|
|
18
|
-
|
|
7
|
+
{{on "focus" this.initializeFocus}}
|
|
8
|
+
{{did-insert this.setTabsRef}}
|
|
19
9
|
>
|
|
20
10
|
{{#each @tabs as |tab|}}
|
|
21
11
|
<EuiTab
|
|
22
12
|
@id={{tab.id}}
|
|
23
|
-
aria-controls={{
|
|
24
|
-
@
|
|
25
|
-
@onClick={{pipe selectedTab.setState (fn onTabClick tab)}}
|
|
26
|
-
@focusFn={{selectedTab.setState}}
|
|
13
|
+
aria-controls={{rootId}}
|
|
14
|
+
@isSelected={{eq tab.id this.selectedTab.id}}
|
|
27
15
|
@disabled={{tab.disabled}}
|
|
16
|
+
{{on "click" (fn this.onTabClick tab)}}
|
|
28
17
|
>
|
|
29
18
|
{{tab.name}}
|
|
30
19
|
</EuiTab>
|
|
31
20
|
{{/each}}
|
|
32
21
|
</EuiTabs>
|
|
33
|
-
{{#let (find-by "id" selectedTab.
|
|
34
|
-
{{
|
|
35
|
-
|
|
36
|
-
{{
|
|
37
|
-
|
|
38
|
-
{{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
</div>
|
|
42
|
-
{{/if}}
|
|
22
|
+
{{#let (find-by "id" this.selectedTab.id @tabs) as |currentTab|}}
|
|
23
|
+
<div role="tabpanel" id={{rootId}} aria-labelledby={{currentTab.id}}>
|
|
24
|
+
{{#if (has-block "selectedTabContent")}}
|
|
25
|
+
{{yield currentTab to="selectedTabContent"}}
|
|
26
|
+
{{else}}
|
|
27
|
+
{{currentTab.content}}
|
|
28
|
+
{{/if}}
|
|
29
|
+
</div>
|
|
43
30
|
{{/let}}
|
|
44
31
|
</div>
|
|
45
32
|
{{/let}}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { scheduleOnce } from '@ember/runloop';
|
|
2
|
+
import Component from '@glimmer/component';
|
|
3
|
+
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import { CommonArgs } from '../common';
|
|
5
|
+
|
|
6
|
+
export interface EuiTabbedContentTab {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
content: Component;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type EuiTabbedContentArgs = CommonArgs & {
|
|
13
|
+
/**
|
|
14
|
+
* When tabbing into the tabs, set the focus on `initial` for the first tab,
|
|
15
|
+
* or `selected` for the currently selected tab. Best use case is for inside of
|
|
16
|
+
* overlay content like popovers or flyouts.
|
|
17
|
+
*/
|
|
18
|
+
autoFocus?: 'initial' | 'selected';
|
|
19
|
+
/**
|
|
20
|
+
* Choose `default` or alternative `condensed` display styles
|
|
21
|
+
*/
|
|
22
|
+
display?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Evenly stretches each tab to fill the horizontal space
|
|
25
|
+
*/
|
|
26
|
+
expand?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Use this prop to set the initially selected tab while letting the tabbed content component
|
|
29
|
+
* control selection state internally
|
|
30
|
+
*/
|
|
31
|
+
initialSelectedTab?: EuiTabbedContentTab;
|
|
32
|
+
onTabClick?: (selectedTab: EuiTabbedContentTab) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Use this prop if you want to control selection state within the owner component
|
|
35
|
+
*/
|
|
36
|
+
selectedTab?: EuiTabbedContentTab;
|
|
37
|
+
size?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Each tab needs id and content properties, so we can associate it with its panel for accessibility.
|
|
40
|
+
* The name property (a node) is also required to display to the user.
|
|
41
|
+
*/
|
|
42
|
+
tabs: EuiTabbedContentTab[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default class EuiTabbedContentComponent extends Component<EuiTabbedContentArgs> {
|
|
46
|
+
@tracked selectedTabId;
|
|
47
|
+
@tracked inFocus: boolean = false;
|
|
48
|
+
tabsRef?: Element;
|
|
49
|
+
|
|
50
|
+
get autoFocus() {
|
|
51
|
+
return this.args.autoFocus || 'initial';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor(owner: unknown, args: EuiTabbedContentArgs) {
|
|
55
|
+
super(owner, args);
|
|
56
|
+
|
|
57
|
+
const { initialSelectedTab, selectedTab, tabs } = this.args;
|
|
58
|
+
|
|
59
|
+
// Only track selection state if it's not controlled externally.
|
|
60
|
+
if (!selectedTab) {
|
|
61
|
+
this.selectedTabId =
|
|
62
|
+
(initialSelectedTab && initialSelectedTab.id) || tabs[0].id;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get selectedTab() {
|
|
67
|
+
const { selectedTab: externalSelectedTab, tabs } = this.args;
|
|
68
|
+
return (
|
|
69
|
+
externalSelectedTab ||
|
|
70
|
+
tabs.find((tab: EuiTabbedContentTab) => tab.id === this.selectedTabId)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
setTabsRef = (element: Element) => {
|
|
75
|
+
this.tabsRef = element;
|
|
76
|
+
// Current short-term solution for event listener (see https://github.com/elastic/eui/pull/2717)
|
|
77
|
+
this.tabsRef.addEventListener('focusout' as 'blur', this.removeFocus);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
willDestroy(): void {
|
|
81
|
+
super.willDestroy();
|
|
82
|
+
if (this.tabsRef) {
|
|
83
|
+
this.tabsRef.removeEventListener('focusout' as 'blur', this.removeFocus);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
removeFocus = (blurEvent: FocusEvent) => {
|
|
88
|
+
// only set inFocus to false if the wrapping div doesn't contain the now-focusing element
|
|
89
|
+
const currentTarget = blurEvent.currentTarget! as HTMLElement;
|
|
90
|
+
const relatedTarget = blurEvent.relatedTarget! as HTMLElement;
|
|
91
|
+
if (currentTarget.contains(relatedTarget) === false) {
|
|
92
|
+
this.inFocus = true;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
onTabClick = (selectedTab: EuiTabbedContentTab) => {
|
|
97
|
+
const { onTabClick, selectedTab: externalSelectedTab } = this.args;
|
|
98
|
+
|
|
99
|
+
if (onTabClick) {
|
|
100
|
+
onTabClick(selectedTab);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Only track selection state if it's not controlled externally.
|
|
104
|
+
if (!externalSelectedTab) {
|
|
105
|
+
this.selectedTabId = selectedTab.id;
|
|
106
|
+
const focusTab = () => {
|
|
107
|
+
this.focusTab();
|
|
108
|
+
};
|
|
109
|
+
scheduleOnce('afterRender', this, focusTab);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
focusTab = () => {
|
|
114
|
+
if (this.tabsRef) {
|
|
115
|
+
const targetTab: HTMLDivElement | null = this.tabsRef.querySelector(
|
|
116
|
+
`#${this.selectedTabId}`
|
|
117
|
+
);
|
|
118
|
+
targetTab!.focus();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
initializeFocus = () => {
|
|
123
|
+
if (!this.inFocus && this.autoFocus === 'selected') {
|
|
124
|
+
// Must wait for setState to finish before calling `.focus()`
|
|
125
|
+
// as the focus call triggers a blur on the first tab
|
|
126
|
+
this.inFocus = true;
|
|
127
|
+
|
|
128
|
+
const focusTab = () => {
|
|
129
|
+
this.focusTab();
|
|
130
|
+
};
|
|
131
|
+
scheduleOnce('afterRender', this, focusTab);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -1,36 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
order:
|
|
2
|
+
order: 1
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Tab sizes
|
|
6
5
|
|
|
7
6
|
<EuiText>
|
|
8
|
-
<p><strong>EuiTabs</strong>
|
|
9
|
-
<p>You can also use the <EuiCode>expand</EuiCode> prop to evenly stretch each tab horizontally.</p>
|
|
7
|
+
<p><strong>EuiTabs</strong> is a wrapping component that requires <strong>EuiTab</strong> components as direct children. You control the displayed contents and current state through props on EuiTab like <EuiCode>isSelected</EuiCode> and <EuiCode>onClick</EuiCode>.</p><p>Use the <EuiCode>prepend</EuiCode> and <EuiCode>append</EuiCode> tab props to add content before and after the tab label respectively.</p>
|
|
10
8
|
</EuiText>
|
|
11
9
|
|
|
12
10
|
```hbs template
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</EuiButton>
|
|
28
|
-
</:button>
|
|
29
|
-
<:content>
|
|
30
|
-
<EuiTabbedContent @tabs={{this.tabsItems1}} />
|
|
31
|
-
</:content>
|
|
32
|
-
</EuiPopover>
|
|
33
|
-
</div>
|
|
11
|
+
<EuiTabs>
|
|
12
|
+
{{#each this.tabs as |tab|}}
|
|
13
|
+
<EuiTab
|
|
14
|
+
@isSelected={{eq tab.id this.selectedTab.id}}
|
|
15
|
+
{{on 'click' (set this 'selectedTab' tab)}}
|
|
16
|
+
>
|
|
17
|
+
{{tab.name}}
|
|
18
|
+
</EuiTab>
|
|
19
|
+
{{/each}}
|
|
20
|
+
</EuiTabs>
|
|
21
|
+
<EuiSpacer />
|
|
22
|
+
<EuiText>
|
|
23
|
+
{{this.selectedTab.content}}
|
|
24
|
+
</EuiText>
|
|
34
25
|
```
|
|
35
26
|
|
|
36
27
|
```js component
|
|
@@ -39,54 +30,38 @@ import { action } from '@ember/object';
|
|
|
39
30
|
import { tracked } from '@glimmer/tracking';
|
|
40
31
|
|
|
41
32
|
export default class DemoTabsComponent extends Component {
|
|
42
|
-
@tracked
|
|
43
|
-
|
|
33
|
+
@tracked selectedTab = 0;
|
|
34
|
+
@tracked tabs = [
|
|
35
|
+
{
|
|
36
|
+
id: 'cobalt--id',
|
|
37
|
+
name: 'Cobalt',
|
|
38
|
+
content:
|
|
39
|
+
' Cobalt is a chemical element with symbol Co and atomic number 27. Like nickel, cobalt is found in the Earth’s crust only in chemically combined form, save for small deposits found in alloys of natural meteoric iron. The free element, produced by reductive smelting, is a hard, lustrous, silver-gray metal.'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'dextrose--id',
|
|
43
|
+
name: 'Dextrose',
|
|
44
|
+
content:
|
|
45
|
+
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'hydrogen--id',
|
|
49
|
+
name: 'Hydrogen',
|
|
50
|
+
prepend: 'heatmap',
|
|
51
|
+
disabled: true,
|
|
52
|
+
content:
|
|
53
|
+
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'monosodium_glutammate--id',
|
|
57
|
+
name: 'Monosodium Glutamate',
|
|
58
|
+
content:
|
|
59
|
+
' Monosodium glutamate (MSG, also known as sodium glutamate) is the sodium salt of glutamic acid, one of the most abundant naturally occurring non-essential amino acids. Monosodium glutamate is found naturally in tomatoes, cheese and other foods.'
|
|
60
|
+
}
|
|
61
|
+
];
|
|
44
62
|
constructor() {
|
|
45
63
|
super(...arguments);
|
|
46
|
-
|
|
47
|
-
this.tabsItems1 = [
|
|
48
|
-
{
|
|
49
|
-
id: 'example1',
|
|
50
|
-
name: 'Example 1',
|
|
51
|
-
content: 'Example 1 content.'
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
id: 'example2',
|
|
55
|
-
name: 'Example 2',
|
|
56
|
-
content: 'Example 2 content.'
|
|
57
|
-
}
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
this.tabsItems2 = [
|
|
61
|
-
{
|
|
62
|
-
id: 'one',
|
|
63
|
-
name: 'Click me 1!',
|
|
64
|
-
content: "Same ol' 1 content."
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: 'two',
|
|
68
|
-
name: 'Click me 2!',
|
|
69
|
-
content: "Same ol' 2 content."
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: 'three',
|
|
73
|
-
name: 'Click me 3!',
|
|
74
|
-
content: "Same ol' 3 content."
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
sayMyName(tab) {
|
|
80
|
-
alert(`I am ${tab.name || tab.id}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@action
|
|
84
|
-
cycleTabs() {
|
|
85
|
-
this.tabsIndex2++;
|
|
86
|
-
|
|
87
|
-
if (this.tabsIndex2 >= this.tabsItems2.length) {
|
|
88
|
-
this.tabsIndex2 = 0;
|
|
89
|
-
}
|
|
64
|
+
this.selectedTab = this.tabs[0];
|
|
90
65
|
}
|
|
91
66
|
}
|
|
92
67
|
```
|
|
@@ -1,15 +1,46 @@
|
|
|
1
1
|
---
|
|
2
|
-
order:
|
|
2
|
+
order: 2
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Tab sizes
|
|
6
6
|
|
|
7
7
|
<EuiText>
|
|
8
|
-
<p><strong>
|
|
8
|
+
<p><strong>EuiTabs</strong> allow a <EuiCode>size</EuiCode> prop. In general you should always use the default (medium) size. The small size is best for when placing inside popovers or other small containers. Reserve using the large size for when using as primary page navigation, like inside of <a href="#/layout/page-header"><strong>EuiPageHeader</strong></a>.</p><p>You can also use the <EuiCode>expand</EuiCode> prop to evenly stretch each tab horizontally.</p>
|
|
9
9
|
</EuiText>
|
|
10
10
|
|
|
11
11
|
```hbs template
|
|
12
|
-
<
|
|
12
|
+
<div>
|
|
13
|
+
<EuiPopover
|
|
14
|
+
@ownFocus={{true}}
|
|
15
|
+
@isOpen={{this.popover}}
|
|
16
|
+
@anchorPosition='downLeft'
|
|
17
|
+
@closePopover={{set this 'popover' false}}
|
|
18
|
+
>
|
|
19
|
+
<:button>
|
|
20
|
+
<EuiButton
|
|
21
|
+
@iconType='arrowDown'
|
|
22
|
+
@iconSide='right'
|
|
23
|
+
{{on 'click' (set this 'popover' true)}}
|
|
24
|
+
>
|
|
25
|
+
Show Popover
|
|
26
|
+
</EuiButton>
|
|
27
|
+
</:button>
|
|
28
|
+
<:content>
|
|
29
|
+
<EuiTabs>
|
|
30
|
+
{{#each this.tabs as |tab|}}
|
|
31
|
+
<EuiTab
|
|
32
|
+
@isSelected={{eq this.selectedTab.id tab.id}}
|
|
33
|
+
{{on 'click' (set this 'selectedTab' tab)}}
|
|
34
|
+
>
|
|
35
|
+
{{tab.name}}
|
|
36
|
+
</EuiTab>
|
|
37
|
+
{{/each}}
|
|
38
|
+
</EuiTabs>
|
|
39
|
+
<EuiSpacer />
|
|
40
|
+
{{this.selectedTab.content}}
|
|
41
|
+
</:content>
|
|
42
|
+
</EuiPopover>
|
|
43
|
+
</div>
|
|
13
44
|
```
|
|
14
45
|
|
|
15
46
|
```js component
|
|
@@ -18,39 +49,25 @@ import { action } from '@ember/object';
|
|
|
18
49
|
import { tracked } from '@glimmer/tracking';
|
|
19
50
|
|
|
20
51
|
export default class DemoTabsComponent extends Component {
|
|
21
|
-
@tracked
|
|
52
|
+
@tracked selectedTab;
|
|
22
53
|
|
|
23
54
|
constructor() {
|
|
24
55
|
super(...arguments);
|
|
25
56
|
|
|
26
|
-
this.
|
|
57
|
+
this.tabs = [
|
|
27
58
|
{
|
|
28
|
-
id: '
|
|
29
|
-
name: '
|
|
30
|
-
content:
|
|
31
|
-
' Cobalt is a chemical element with symbol Co and atomic number 27. Like nickel, cobalt is found in the Earth’s crust only in chemically combined form, save for small deposits found in alloys of natural meteoric iron. The free element, produced by reductive smelting, is a hard, lustrous, silver-gray metal.'
|
|
59
|
+
id: 'example1',
|
|
60
|
+
name: 'Example 1',
|
|
61
|
+
content: 'Example 1 content.'
|
|
32
62
|
},
|
|
33
63
|
{
|
|
34
|
-
id: '
|
|
35
|
-
name: '
|
|
36
|
-
content:
|
|
37
|
-
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: 'hydrogen--id',
|
|
41
|
-
name: 'Hydrogen',
|
|
42
|
-
prepend: 'heatmap',
|
|
43
|
-
disabled: true,
|
|
44
|
-
content:
|
|
45
|
-
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
id: 'monosodium_glutammate--id',
|
|
49
|
-
name: 'Monosodium Glutamate',
|
|
50
|
-
content:
|
|
51
|
-
' Monosodium glutamate (MSG, also known as sodium glutamate) is the sodium salt of glutamic acid, one of the most abundant naturally occurring non-essential amino acids. Monosodium glutamate is found naturally in tomatoes, cheese and other foods.'
|
|
64
|
+
id: 'example2',
|
|
65
|
+
name: 'Example 2',
|
|
66
|
+
content: 'Example 2 content.'
|
|
52
67
|
}
|
|
53
68
|
];
|
|
69
|
+
|
|
70
|
+
this.selectedTab = this.tabs[0];
|
|
54
71
|
}
|
|
55
72
|
}
|
|
56
73
|
```
|
|
@@ -1,25 +1,54 @@
|
|
|
1
1
|
---
|
|
2
|
-
order:
|
|
2
|
+
order: 3
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Bottom border
|
|
6
6
|
|
|
7
7
|
<EuiText>
|
|
8
|
-
<p>
|
|
8
|
+
<p>The <EuiCode>bottomBorder</EuiCode> helps to separate the tab group from the content below and is on by default. However, some components like <a href="/docs/core/docs/layout/flyout">flyouts</a> already provide borders which can act as the divider. In this case you can turn the border off with <EuiCode>bottomBorder<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span></EuiCode>.</p>
|
|
9
9
|
</EuiText>
|
|
10
10
|
|
|
11
11
|
```hbs template
|
|
12
|
-
<EuiButton
|
|
13
|
-
|
|
12
|
+
<EuiButton {{on 'click' this.openFlyout}}>
|
|
13
|
+
Show tabs flyout header
|
|
14
14
|
</EuiButton>
|
|
15
|
-
|
|
16
|
-
{{
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<
|
|
15
|
+
{{#if this.flyoutOpen}}
|
|
16
|
+
<EuiFlyout @onClose={{this.closeFlyout}}>
|
|
17
|
+
<EuiFlyoutHeader @hasBorder={{true}}>
|
|
18
|
+
<EuiTitle @size='m'>
|
|
19
|
+
<h2>Flyout header</h2>
|
|
20
|
+
</EuiTitle>
|
|
21
|
+
<EuiSpacer @size='s' />
|
|
22
|
+
<EuiText @color='subdued'>
|
|
23
|
+
Put navigation items in the header, and cross tab actions in a footer.
|
|
24
|
+
</EuiText>
|
|
25
|
+
<EuiSpacer @size='s' />
|
|
26
|
+
<EuiTabs @bottomBorder={{false}} style='margin-bottom: -24px;'>
|
|
27
|
+
{{#each this.tabs as |tab|}}
|
|
28
|
+
<EuiTab
|
|
29
|
+
{{on 'click' (set this 'selectedTab' tab)}}
|
|
30
|
+
@isSelected={{eq this.selectedTab.id tab.id}}
|
|
31
|
+
>
|
|
32
|
+
{{tab.name}}
|
|
33
|
+
</EuiTab>
|
|
34
|
+
{{/each}}
|
|
35
|
+
</EuiTabs>
|
|
36
|
+
</EuiFlyoutHeader>
|
|
37
|
+
<EuiFlyoutBody>
|
|
38
|
+
{{this.selectedTab.content}}
|
|
39
|
+
</EuiFlyoutBody>
|
|
40
|
+
<EuiFlyoutFooter>
|
|
41
|
+
<EuiFlexGroup @justifyContent='spaceBetween' @gutterSize='s'>
|
|
42
|
+
<EuiButton {{on 'click' this.closeFlyout}}>
|
|
43
|
+
Cancel
|
|
44
|
+
</EuiButton>
|
|
45
|
+
<EuiButton @fill={{true}} {{on 'click' this.closeFlyout}}>
|
|
46
|
+
Send
|
|
47
|
+
</EuiButton>
|
|
48
|
+
</EuiFlexGroup>
|
|
49
|
+
</EuiFlyoutFooter>
|
|
50
|
+
</EuiFlyout>
|
|
51
|
+
{{/if}}
|
|
23
52
|
```
|
|
24
53
|
|
|
25
54
|
```js component
|
|
@@ -28,12 +57,24 @@ import { action } from '@ember/object';
|
|
|
28
57
|
import { tracked } from '@glimmer/tracking';
|
|
29
58
|
|
|
30
59
|
export default class DemoTabsComponent extends Component {
|
|
31
|
-
@tracked
|
|
60
|
+
@tracked selectedTab;
|
|
61
|
+
|
|
62
|
+
@tracked flyoutOpen = false;
|
|
63
|
+
|
|
64
|
+
@action
|
|
65
|
+
openFlyout() {
|
|
66
|
+
this.flyoutOpen = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@action
|
|
70
|
+
closeFlyout(flyout) {
|
|
71
|
+
this.flyoutOpen = false;
|
|
72
|
+
}
|
|
32
73
|
|
|
33
74
|
constructor() {
|
|
34
75
|
super(...arguments);
|
|
35
76
|
|
|
36
|
-
this.
|
|
77
|
+
this.tabs = [
|
|
37
78
|
{
|
|
38
79
|
id: 'cobalt--id',
|
|
39
80
|
name: 'Cobalt',
|
|
@@ -61,19 +102,8 @@ export default class DemoTabsComponent extends Component {
|
|
|
61
102
|
' Monosodium glutamate (MSG, also known as sodium glutamate) is the sodium salt of glutamic acid, one of the most abundant naturally occurring non-essential amino acids. Monosodium glutamate is found naturally in tomatoes, cheese and other foods.'
|
|
62
103
|
}
|
|
63
104
|
];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
sayMyName(tab) {
|
|
67
|
-
alert(`I am ${tab.name || tab.id}`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@action
|
|
71
|
-
cycleTabs() {
|
|
72
|
-
this.tabsIndex2++;
|
|
73
105
|
|
|
74
|
-
|
|
75
|
-
this.tabsIndex2 = 0;
|
|
76
|
-
}
|
|
106
|
+
this.selectedTab = this.tabs[0];
|
|
77
107
|
}
|
|
78
108
|
}
|
|
79
109
|
```
|
|
@@ -1,36 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
order:
|
|
2
|
+
order: 4
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Tabbed content
|
|
6
6
|
|
|
7
7
|
<EuiText>
|
|
8
|
-
<p>
|
|
8
|
+
<p><strong>EuiTabbedContent</strong> makes it easier to associate tabs with content based on the selected tab. Use the <EuiCode>initialSelectedTab</EuiCode> prop to specify which tab to initially select.</p>
|
|
9
9
|
</EuiText>
|
|
10
10
|
|
|
11
11
|
```hbs template
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Cancel
|
|
26
|
-
</EuiButton>
|
|
27
|
-
<EuiButton @fill={{true}} {{on 'click' this.closeFlyout}}>
|
|
28
|
-
Send
|
|
29
|
-
</EuiButton>
|
|
30
|
-
</EuiFlexGroup>
|
|
31
|
-
</EuiFlyoutFooter>
|
|
32
|
-
</EuiFlyout>
|
|
33
|
-
{{/if}}
|
|
12
|
+
<EuiTabbedContent
|
|
13
|
+
@tabs={{this.tabs}}
|
|
14
|
+
@initialSelectedTab={{object-at this.tabs 1}}
|
|
15
|
+
@autoFocus='selected'
|
|
16
|
+
@onTabClick={{fn this.sayMyName}}
|
|
17
|
+
>
|
|
18
|
+
<:selectedTabContent as |selected|>
|
|
19
|
+
<EuiSpacer />
|
|
20
|
+
<EuiText>
|
|
21
|
+
{{selected.content}}
|
|
22
|
+
</EuiText>
|
|
23
|
+
</:selectedTabContent>
|
|
24
|
+
</EuiTabbedContent>
|
|
34
25
|
```
|
|
35
26
|
|
|
36
27
|
```js component
|
|
@@ -41,22 +32,10 @@ import { tracked } from '@glimmer/tracking';
|
|
|
41
32
|
export default class DemoTabsComponent extends Component {
|
|
42
33
|
@tracked tabsIndex2 = 0;
|
|
43
34
|
|
|
44
|
-
@tracked flyoutOpen = false;
|
|
45
|
-
|
|
46
|
-
@action
|
|
47
|
-
openFlyout() {
|
|
48
|
-
this.flyoutOpen = true;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@action
|
|
52
|
-
closeFlyout(flyout) {
|
|
53
|
-
this.flyoutOpen = false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
35
|
constructor() {
|
|
57
36
|
super(...arguments);
|
|
58
37
|
|
|
59
|
-
this.
|
|
38
|
+
this.tabs = [
|
|
60
39
|
{
|
|
61
40
|
id: 'cobalt--id',
|
|
62
41
|
name: 'Cobalt',
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
order: 5
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Controlled tabbed content
|
|
6
|
+
|
|
7
|
+
<EuiText>
|
|
8
|
+
<p>You can also use the <code class="euiCode" data-code-language="text">selectedTab</code> and <code class="euiCode" data-code-language="text">onTabClick</code> props to take complete control over tab selection. This can be useful if you want to change tabs based on user interaction with another part of the UI.</p>
|
|
9
|
+
</EuiText>
|
|
10
|
+
|
|
11
|
+
```hbs template
|
|
12
|
+
<EuiButton
|
|
13
|
+
@color='primary'
|
|
14
|
+
{{on 'click' this.cycleTabs}}
|
|
15
|
+
@iconType='arrowRight'
|
|
16
|
+
@iconSide='right'
|
|
17
|
+
>
|
|
18
|
+
Cycle through tabs
|
|
19
|
+
</EuiButton>
|
|
20
|
+
Outer selected tab:
|
|
21
|
+
{{this.selectedTab.name}}
|
|
22
|
+
<EuiTabbedContent @tabs={{this.tabs}} @selectedTab={{this.selectedTab}}>
|
|
23
|
+
<:selectedTabContent as |selected|>
|
|
24
|
+
<EuiSpacer />
|
|
25
|
+
<EuiText>
|
|
26
|
+
{{selected.content}}
|
|
27
|
+
</EuiText>
|
|
28
|
+
</:selectedTabContent>
|
|
29
|
+
</EuiTabbedContent>
|
|
30
|
+
|
|
31
|
+
<EuiSpacer />
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```js component
|
|
35
|
+
import Component from '@ember/component';
|
|
36
|
+
import { action } from '@ember/object';
|
|
37
|
+
import { tracked } from '@glimmer/tracking';
|
|
38
|
+
|
|
39
|
+
export default class DemoTabsComponent extends Component {
|
|
40
|
+
@tracked selectedTab;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super(...arguments);
|
|
44
|
+
|
|
45
|
+
this.tabs = [
|
|
46
|
+
{
|
|
47
|
+
id: 'cobalt--id',
|
|
48
|
+
name: 'Cobalt',
|
|
49
|
+
content:
|
|
50
|
+
' Cobalt is a chemical element with symbol Co and atomic number 27. Like nickel, cobalt is found in the Earth’s crust only in chemically combined form, save for small deposits found in alloys of natural meteoric iron. The free element, produced by reductive smelting, is a hard, lustrous, silver-gray metal.'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'dextrose--id',
|
|
54
|
+
name: 'Dextrose',
|
|
55
|
+
content:
|
|
56
|
+
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'hydrogen--id',
|
|
60
|
+
name: 'Hydrogen',
|
|
61
|
+
prepend: 'heatmap',
|
|
62
|
+
|
|
63
|
+
content:
|
|
64
|
+
'Intravenous sugar solution, also known as dextrose solution, is a mixture of dextrose (glucose) and water. It is used to treat low blood sugar or water loss without electrolyte loss.'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'monosodium_glutammate--id',
|
|
68
|
+
name: 'Monosodium Glutamate',
|
|
69
|
+
content:
|
|
70
|
+
' Monosodium glutamate (MSG, also known as sodium glutamate) is the sodium salt of glutamic acid, one of the most abundant naturally occurring non-essential amino acids. Monosodium glutamate is found naturally in tomatoes, cheese and other foods.'
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
this.selectedTab = this.tabs[0];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@action
|
|
78
|
+
cycleTabs() {
|
|
79
|
+
const tabs = this.tabs;
|
|
80
|
+
const selectedTabIndex = tabs.indexOf(this.selectedTab);
|
|
81
|
+
const nextTabIndex =
|
|
82
|
+
selectedTabIndex < tabs.length - 1 ? selectedTabIndex + 1 : 0;
|
|
83
|
+
this.selectedTab = tabs[nextTabIndex];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ember-eui/core",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.4",
|
|
4
4
|
"description": "Ember Components for Elastic UI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon",
|
|
@@ -182,5 +182,5 @@
|
|
|
182
182
|
"volta": {
|
|
183
183
|
"extends": "../../package.json"
|
|
184
184
|
},
|
|
185
|
-
"gitHead": "
|
|
185
|
+
"gitHead": "1b88258ed3a11388d0e4f8557f5744b91ede144e"
|
|
186
186
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { helper } from '@ember/component/helper';
|
|
2
|
-
import { assert } from '@ember/debug';
|
|
3
|
-
|
|
4
|
-
export function getTabId([tabOrId]: [Tab | string | number]):
|
|
5
|
-
| string
|
|
6
|
-
| number
|
|
7
|
-
| undefined {
|
|
8
|
-
if (tabOrId === undefined) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (typeof tabOrId === 'string' || typeof tabOrId === 'number') {
|
|
13
|
-
return tabOrId;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
assert(
|
|
17
|
-
'The passed `tab` object needs to have the `id` property',
|
|
18
|
-
tabOrId.id !== undefined
|
|
19
|
-
);
|
|
20
|
-
return tabOrId.id;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default helper(getTabId);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default, getTabId } from '@ember-eui/core/helpers/get-tab-id';
|