@hashicorp/design-system-components 1.2.0 → 1.3.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/CHANGELOG.md +26 -0
- package/HOW-TO-TEST-A-COMPONENT-IN-CLOUD-UI.md +54 -0
- package/LICENSE.md +2 -0
- package/addon/components/hds/tabs/index.hbs +33 -0
- package/addon/components/hds/tabs/index.js +107 -0
- package/addon/components/hds/tabs/panel.hbs +11 -0
- package/addon/components/hds/tabs/panel.js +40 -0
- package/addon/components/hds/tabs/tab.hbs +25 -0
- package/addon/components/hds/tabs/tab.js +88 -0
- package/app/components/hds/tabs/index.js +1 -0
- package/app/components/hds/tabs/panel.js +1 -0
- package/app/components/hds/tabs/tab.js +1 -0
- package/app/styles/@hashicorp/design-system-components.scss +2 -2
- package/app/styles/components/alert.scss +1 -4
- package/app/styles/components/avatar.scss +1 -3
- package/app/styles/components/badge-count.scss +1 -3
- package/app/styles/components/badge.scss +1 -4
- package/app/styles/components/breadcrumb.scss +1 -3
- package/app/styles/components/button-set.scss +1 -3
- package/app/styles/components/button.scss +11 -2
- package/app/styles/components/card/container.scss +0 -4
- package/app/styles/components/disclosure.scss +0 -2
- package/app/styles/components/dropdown.scss +0 -2
- package/app/styles/components/empty-state.scss +4 -0
- package/app/styles/components/form/checkbox.scss +0 -2
- package/app/styles/components/form/error.scss +0 -2
- package/app/styles/components/form/field.scss +0 -2
- package/app/styles/components/form/group.scss +0 -2
- package/app/styles/components/form/helper-text.scss +0 -2
- package/app/styles/components/form/indicator.scss +0 -2
- package/app/styles/components/form/label.scss +0 -2
- package/app/styles/components/form/legend.scss +0 -2
- package/app/styles/components/form/radio-card.scss +3 -0
- package/app/styles/components/form/radio.scss +0 -2
- package/app/styles/components/form/select.scss +1 -2
- package/app/styles/components/form/text-input.scss +1 -2
- package/app/styles/components/form/textarea.scss +1 -2
- package/app/styles/components/form/toggle.scss +0 -2
- package/app/styles/components/icon-tile.scss +1 -4
- package/app/styles/components/link/index.scss +2 -0
- package/app/styles/components/link/inline.scss +0 -2
- package/app/styles/components/link/standalone.scss +0 -2
- package/app/styles/components/stepper/step-indicator.scss +0 -2
- package/app/styles/components/stepper/task-indicator.scss +0 -2
- package/app/styles/components/tabs.scss +113 -0
- package/app/styles/components/tag.scss +0 -3
- package/app/styles/components/toast.scss +1 -4
- package/blueprints/hds-component/files/app/styles/components/__name__.scss +0 -2
- package/package.json +22 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @hashicorp/design-system-components
|
|
2
2
|
|
|
3
|
+
## 1.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#663](https://github.com/hashicorp/design-system/pull/663) [`1397d52c`](https://github.com/hashicorp/design-system/commit/1397d52c4405bb768b8cf0e7db2e0503d48f8f00) Thanks [@nfagerlund](https://github.com/nfagerlund)! - Tabs::Panel: Regress modern helper syntax for 3.24 compatibility
|
|
8
|
+
|
|
9
|
+
## 1.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#548](https://github.com/hashicorp/design-system/pull/548) [`5d1e2cb4`](https://github.com/hashicorp/design-system/commit/5d1e2cb4f953bfbe55ae1fa8a675903712a66a1c) Thanks [@KristinLBradley](https://github.com/KristinLBradley)! - Add new Tabs component
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#618](https://github.com/hashicorp/design-system/pull/618) [`11d39410`](https://github.com/hashicorp/design-system/commit/11d39410c40725ff34a291e17eac3f8f8321c659) Thanks [@alex-ju](https://github.com/alex-ju)! - Update `ember` to `4.7.0`
|
|
18
|
+
|
|
19
|
+
* [#660](https://github.com/hashicorp/design-system/pull/660) [`4d0826a6`](https://github.com/hashicorp/design-system/commit/4d0826a6df220031b36f4918c5c5365012672c27) Thanks [@alex-ju](https://github.com/alex-ju)! - Update the `Hds::Button` style when rendered as a link
|
|
20
|
+
|
|
21
|
+
- [#638](https://github.com/hashicorp/design-system/pull/638) [`90182235`](https://github.com/hashicorp/design-system/commit/901822353453e98c914c8d57e523d64b32a23f75) Thanks [@Dhaulagiri](https://github.com/Dhaulagiri)! - explicitly add ember-style-modifiers as a dependency
|
|
22
|
+
|
|
23
|
+
* [#636](https://github.com/hashicorp/design-system/pull/636) [`27a283a5`](https://github.com/hashicorp/design-system/commit/27a283a52c2828b32c282401f91df9bd929f9dda) Thanks [@Dhaulagiri](https://github.com/Dhaulagiri)! - Add copyright notice to license file
|
|
24
|
+
|
|
25
|
+
* Updated dependencies [[`a079992f`](https://github.com/hashicorp/design-system/commit/a079992fbbed11812fcf4cdd4409a00fa2d246f1), [`11d39410`](https://github.com/hashicorp/design-system/commit/11d39410c40725ff34a291e17eac3f8f8321c659), [`27a283a5`](https://github.com/hashicorp/design-system/commit/27a283a52c2828b32c282401f91df9bd929f9dda), [`ecbe26df`](https://github.com/hashicorp/design-system/commit/ecbe26df6bdbaf7b4f00c70d016eead0da9168f0)]:
|
|
26
|
+
- @hashicorp/design-system-tokens@1.2.0
|
|
27
|
+
- @hashicorp/ember-flight-icons@3.0.1
|
|
28
|
+
|
|
3
29
|
## 1.2.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# How to test a component in Cloud UI
|
|
2
|
+
|
|
3
|
+
To test a new component (or a component that has been modified) using your local environment as source for the `@hashicorp/design-system-components` package, you have to follow a few steps.
|
|
4
|
+
|
|
5
|
+
## Prepare the Cloud UI project
|
|
6
|
+
|
|
7
|
+
For simplicity, you will need three CLI/terminal windows/tabs opened.
|
|
8
|
+
|
|
9
|
+
In in the first terminal window go the folder containing your local version of the https://github.com/hashicorp/cloud-ui/ codebase:
|
|
10
|
+
|
|
11
|
+
- go to the root of the project
|
|
12
|
+
- eg. `cd ~/path-to/your-local/hashicorp/cloud-ui`
|
|
13
|
+
- run `rm -fr node_modules/` to start from a blank slate
|
|
14
|
+
- run `yarn` to make sure all the packages are installed
|
|
15
|
+
|
|
16
|
+
## Replace the installed `@hashicorp/design-system-components` package in Cloud UI with the local one
|
|
17
|
+
|
|
18
|
+
In the second terminal window:
|
|
19
|
+
|
|
20
|
+
- run `cd ~/path-to/your-local/hashicorp/cloud-ui/node_modules/@hashicorp` to go in the folder containing the `@hashicorp` packages
|
|
21
|
+
- run `ls -la` to check that the folder `design-system-components` is present
|
|
22
|
+
- run `rm -fr design-system-components` to remove (recursively) the folder with the published version of the `@hashicorp/design-system-components` package
|
|
23
|
+
|
|
24
|
+
Now you have to create a symlink between the folder containing your local code for the `design-system-components` and the folder you have just removed:
|
|
25
|
+
|
|
26
|
+
In the third terminal window:
|
|
27
|
+
|
|
28
|
+
- go in the folder containing the https://github.com/hashicorp/design-system codebase
|
|
29
|
+
- eg. `cd ~/path-to/your-local/hashicorp/design-system/packages/components/`
|
|
30
|
+
- run `pwd` and copy the full path to this folder
|
|
31
|
+
- eg. `/Users/mynamesurname/src/hashicorp/design-system/packages/components`
|
|
32
|
+
|
|
33
|
+
Go back to the second terminal window:
|
|
34
|
+
|
|
35
|
+
- run `pwd` and make sure you're still in the `node_modules/@hashicorp` folder of the Cloud UI repo
|
|
36
|
+
- run `ln -s [full-path-to-your-local-components-folder] design-system-components` to create a symbolic link [**IMPORTANT**: you need to set `design-system-components` and not just `components` as target folder name, because that's the name expected by `yarn` (same as the folder you deleted one moment ago)]
|
|
37
|
+
- eg. `ln -s /Users/mynamesurname/src/hashicorp/design-system/packages/components design-system-components`
|
|
38
|
+
|
|
39
|
+
**IMPORTANT**: if you have a new version of the design tokens package that needs to be included as well for your component to work, you will need to do the same process to symlink the local folder of the **compiled** design tokens with the one expected in the Cloud UI `node_modules` folder
|
|
40
|
+
|
|
41
|
+
- eg. `rm -fr design-system-tokens` + `ln -s /Users/mynamesurname/src/hashicorp/design-system/packages/tokens design-system-tokens`
|
|
42
|
+
|
|
43
|
+
In the first terminal window (you should be be in the Cloud UI root):
|
|
44
|
+
- run `yarn start` to launch the compilation of the Cloud UI project and start the local webserver
|
|
45
|
+
- visit the URL that appears in the command line at the end of the build (typically http://localhost:4200/ but you can specify a different port using the command `yarn start --port NNNN`)
|
|
46
|
+
|
|
47
|
+
Everything should work and you should be able to do whatever you need to do in the Cloud UI codebase using your local HDS components (eg testing a new component, or checking the impact of a change in an existing one).
|
|
48
|
+
|
|
49
|
+
**Don't forget**: once you've finished, it is better to reset the state of the Cloud UI project, to make sure that if you're doing some other tests not involving HDS components, you're using the actual code that a user will see in production:
|
|
50
|
+
|
|
51
|
+
- go to the `node_modules/@hashicorp` folder of the Cloud UI repo
|
|
52
|
+
- run `rm design-system-components` (no need for the `-fr` option, it's a symlink file not a folder)
|
|
53
|
+
- go to the root of the Cloud UI project
|
|
54
|
+
- run `yarn` to reinstall all the missing packages (including `@hashicorp/design-system-components` from NPM)
|
package/LICENSE.md
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{{! template-lint-disable no-invalid-role }}
|
|
2
|
+
<div class="hds-tabs" {{did-insert this.didInsert}} ...attributes>
|
|
3
|
+
<div class="hds-tabs__tablist-wrapper">
|
|
4
|
+
<ul class="hds-tabs__tablist" role="tablist">
|
|
5
|
+
{{yield
|
|
6
|
+
(hash
|
|
7
|
+
Tab=(component
|
|
8
|
+
"hds/tabs/tab"
|
|
9
|
+
didInsertNode=this.didInsertTab
|
|
10
|
+
tabIds=this.tabIds
|
|
11
|
+
panelIds=this.panelIds
|
|
12
|
+
selectedTabIndex=this.selectedTabIndex
|
|
13
|
+
onClick=this.onClick
|
|
14
|
+
onKeyUp=this.onKeyUp
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
}}
|
|
18
|
+
<li class="hds-tabs__tab-indicator" role="presentation"></li>
|
|
19
|
+
</ul>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
{{yield
|
|
23
|
+
(hash
|
|
24
|
+
Panel=(component
|
|
25
|
+
"hds/tabs/panel"
|
|
26
|
+
didInsertNode=this.didInsertPanel
|
|
27
|
+
tabIds=this.tabIds
|
|
28
|
+
panelIds=this.panelIds
|
|
29
|
+
selectedTabIndex=this.selectedTabIndex
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
}}
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { action } from '@ember/object';
|
|
4
|
+
import { assert } from '@ember/debug';
|
|
5
|
+
|
|
6
|
+
export default class HdsTabsIndexComponent extends Component {
|
|
7
|
+
@tracked tabNodes = [];
|
|
8
|
+
@tracked tabIds = [];
|
|
9
|
+
@tracked panelNodes = [];
|
|
10
|
+
@tracked panelIds = [];
|
|
11
|
+
@tracked selectedTabIndex;
|
|
12
|
+
|
|
13
|
+
@action
|
|
14
|
+
didInsert() {
|
|
15
|
+
// default starting tab index
|
|
16
|
+
let initialTabIndex = 0;
|
|
17
|
+
let selectedCount = 0;
|
|
18
|
+
|
|
19
|
+
this.tabNodes.forEach((tabElement, index) => {
|
|
20
|
+
if (tabElement.hasAttribute('data-is-selected')) {
|
|
21
|
+
initialTabIndex = index;
|
|
22
|
+
selectedCount++;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this.selectedTabIndex = initialTabIndex;
|
|
26
|
+
this.setTabIndicator(initialTabIndex);
|
|
27
|
+
|
|
28
|
+
assert('Only one tab may use isSelected argument', selectedCount <= 1);
|
|
29
|
+
|
|
30
|
+
assert(
|
|
31
|
+
'The number of Tabs must be equal to the number of Panels',
|
|
32
|
+
this.tabNodes.length === this.panelNodes.length
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@action
|
|
37
|
+
didInsertTab(element) {
|
|
38
|
+
this.tabNodes = [...this.tabNodes, element];
|
|
39
|
+
this.tabIds = [...this.tabIds, element.id];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@action
|
|
43
|
+
didInsertPanel(panelId, element) {
|
|
44
|
+
this.panelNodes = [...this.panelNodes, element];
|
|
45
|
+
this.panelIds = [...this.panelIds, panelId];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@action
|
|
49
|
+
onClick(tabIndex, event) {
|
|
50
|
+
this.selectedTabIndex = tabIndex;
|
|
51
|
+
this.setTabIndicator(tabIndex);
|
|
52
|
+
|
|
53
|
+
// Scroll Tab into view if it's out of view
|
|
54
|
+
this.tabNodes[tabIndex].parentNode.scrollIntoView({
|
|
55
|
+
behavior: 'smooth',
|
|
56
|
+
block: 'nearest',
|
|
57
|
+
inline: 'nearest',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// invoke the callback function if it's provided as argument
|
|
61
|
+
if (typeof this.args.onClickTab === 'function') {
|
|
62
|
+
this.args.onClickTab(event);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@action
|
|
67
|
+
onKeyUp(tabIndex, e) {
|
|
68
|
+
const leftArrow = 37;
|
|
69
|
+
const rightArrow = 39;
|
|
70
|
+
const enterKey = 13;
|
|
71
|
+
const spaceKey = 32;
|
|
72
|
+
|
|
73
|
+
if (e.keyCode === rightArrow) {
|
|
74
|
+
const nextTabIndex = (tabIndex + 1) % this.tabIds.length;
|
|
75
|
+
this.focusTab(nextTabIndex, e);
|
|
76
|
+
} else if (e.keyCode === leftArrow) {
|
|
77
|
+
const prevTabIndex =
|
|
78
|
+
(tabIndex + this.tabIds.length - 1) % this.tabIds.length;
|
|
79
|
+
this.focusTab(prevTabIndex, e);
|
|
80
|
+
} else if (e.keyCode === enterKey || e.keyCode === spaceKey) {
|
|
81
|
+
this.selectedTabIndex = tabIndex;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Focus tab for keyboard & mouse navigation:
|
|
86
|
+
focusTab(tabIndex, e) {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
this.tabNodes[tabIndex].focus();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setSelectedPanelFocus(tabIndex, e) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
this.panelNodes[tabIndex].focus();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
setTabIndicator(tabIndex) {
|
|
97
|
+
const tabElem = this.tabNodes[tabIndex];
|
|
98
|
+
const tabsParentElem = tabElem.closest('.hds-tabs');
|
|
99
|
+
|
|
100
|
+
const tabLeftPos = tabElem.parentNode.offsetLeft;
|
|
101
|
+
const tabWidth = tabElem.parentNode.offsetWidth;
|
|
102
|
+
|
|
103
|
+
// Set CSS custom properties for indicator
|
|
104
|
+
tabsParentElem.style.setProperty('--indicator-left-pos', tabLeftPos + 'px');
|
|
105
|
+
tabsParentElem.style.setProperty('--indicator-width', tabWidth + 'px');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { cached } from '@glimmer/tracking';
|
|
3
|
+
import { guidFor } from '@ember/object/internals';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
|
|
6
|
+
export default class HdsTabsIndexComponent extends Component {
|
|
7
|
+
/**
|
|
8
|
+
* Generates a unique ID for the Panel
|
|
9
|
+
*
|
|
10
|
+
* @param panelId
|
|
11
|
+
*/
|
|
12
|
+
panelId = 'panel-' + guidFor(this);
|
|
13
|
+
|
|
14
|
+
@cached
|
|
15
|
+
get nodeIndex() {
|
|
16
|
+
return this.args.panelIds
|
|
17
|
+
? this.args.panelIds.indexOf(this.panelId)
|
|
18
|
+
: undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get tabId() {
|
|
22
|
+
return this.nodeIndex !== undefined
|
|
23
|
+
? this.args.tabIds[this.nodeIndex]
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get isSelected() {
|
|
28
|
+
return this.nodeIndex === this.args.selectedTabIndex;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@action
|
|
32
|
+
didInsertNode(element) {
|
|
33
|
+
let { didInsertNode } = this.args;
|
|
34
|
+
|
|
35
|
+
if (typeof didInsertNode === 'function') {
|
|
36
|
+
this.elementId = element.id;
|
|
37
|
+
didInsertNode(this.elementId, ...arguments);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{{! template-lint-disable require-context-role no-invalid-role }}
|
|
2
|
+
<li class={{this.classNames}} ...attributes role="presentation">
|
|
3
|
+
{{#if @icon}}
|
|
4
|
+
<FlightIcon @name={{@icon}} class="hds-tabs__tab-icon" />
|
|
5
|
+
{{/if}}
|
|
6
|
+
|
|
7
|
+
<button
|
|
8
|
+
class="hds-tabs__tab-button hds-typography-body-200 hds-font-weight-medium"
|
|
9
|
+
role="tab"
|
|
10
|
+
type="button"
|
|
11
|
+
id={{this.tabId}}
|
|
12
|
+
aria-selected={{this.isSelected}}
|
|
13
|
+
tabindex={{unless this.isSelected "-1"}}
|
|
14
|
+
data-is-selected={{this.isInitialTab}}
|
|
15
|
+
{{did-insert this.didInsertNode}}
|
|
16
|
+
{{on "click" this.onClick}}
|
|
17
|
+
{{on "keyup" this.onKeyUp}}
|
|
18
|
+
>
|
|
19
|
+
{{yield}}
|
|
20
|
+
</button>
|
|
21
|
+
|
|
22
|
+
{{#if @count}}
|
|
23
|
+
<Hds::BadgeCount @text={{@count}} @size="small" class="hds-tabs__tab-count" />
|
|
24
|
+
{{/if}}
|
|
25
|
+
</li>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { cached } from '@glimmer/tracking';
|
|
3
|
+
import { guidFor } from '@ember/object/internals';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
|
|
6
|
+
export default class HdsTabsIndexComponent extends Component {
|
|
7
|
+
/**
|
|
8
|
+
* Generates a unique ID for the Tab
|
|
9
|
+
*
|
|
10
|
+
* @param tabId
|
|
11
|
+
*/
|
|
12
|
+
tabId = 'tab-' + guidFor(this);
|
|
13
|
+
|
|
14
|
+
@cached
|
|
15
|
+
get nodeIndex() {
|
|
16
|
+
return this.args.tabIds ? this.args.tabIds.indexOf(this.tabId) : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get panelId() {
|
|
20
|
+
return this.nodeIndex !== undefined
|
|
21
|
+
? this.args.panelIds[this.nodeIndex]
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param isSelected
|
|
27
|
+
* @type {boolean}
|
|
28
|
+
* @default false (1st tab is selected by default)
|
|
29
|
+
* @description Determines if the tab is the selected tab
|
|
30
|
+
*/
|
|
31
|
+
get isSelected() {
|
|
32
|
+
return (
|
|
33
|
+
this.nodeIndex !== undefined &&
|
|
34
|
+
this.nodeIndex === this.args.selectedTabIndex
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get isInitialTab() {
|
|
39
|
+
let { isSelected } = this.args;
|
|
40
|
+
return isSelected;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@action
|
|
44
|
+
didInsertNode() {
|
|
45
|
+
let { didInsertNode } = this.args;
|
|
46
|
+
|
|
47
|
+
if (typeof didInsertNode === 'function') {
|
|
48
|
+
didInsertNode(...arguments);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@action
|
|
53
|
+
onClick() {
|
|
54
|
+
let { onClick } = this.args;
|
|
55
|
+
|
|
56
|
+
if (typeof onClick === 'function') {
|
|
57
|
+
onClick(this.nodeIndex, ...arguments);
|
|
58
|
+
} else {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@action
|
|
64
|
+
onKeyUp() {
|
|
65
|
+
let { onKeyUp } = this.args;
|
|
66
|
+
|
|
67
|
+
if (typeof onKeyUp === 'function') {
|
|
68
|
+
onKeyUp(this.nodeIndex, ...arguments);
|
|
69
|
+
} else {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get the class names to apply to the component.
|
|
76
|
+
* @method classNames
|
|
77
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
78
|
+
*/
|
|
79
|
+
get classNames() {
|
|
80
|
+
let classes = ['hds-tabs__tab'];
|
|
81
|
+
|
|
82
|
+
if (this.isSelected) {
|
|
83
|
+
classes.push(`hds-tabs__tab--is-selected`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return classes.join(' ');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/components/hds/tabs/index';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/components/hds/tabs/panel';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/components/hds/tabs/tab';
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
@use "../components/empty-state";
|
|
21
21
|
@use "../components/form"; // multiple components
|
|
22
22
|
@use "../components/icon-tile";
|
|
23
|
-
@use "../components/link
|
|
24
|
-
@use "../components/link/standalone";
|
|
23
|
+
@use "../components/link"; // multiple components
|
|
25
24
|
@use "../components/stepper";
|
|
25
|
+
@use "../components/tabs";
|
|
26
26
|
@use "../components/tag";
|
|
27
27
|
@use "../components/toast";
|
|
28
28
|
// END COMPONENT CSS FILES IMPORTS
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
//
|
|
2
|
-
// BREADCRUMB
|
|
2
|
+
// BREADCRUMB COMPONENT
|
|
3
3
|
//
|
|
4
|
-
// properties within each class are sorted alphabetically
|
|
5
4
|
// notice: pseudo-classes for the states *must* follow the order link > visited > hover > focus > active
|
|
6
5
|
//
|
|
7
|
-
//
|
|
8
6
|
|
|
9
7
|
@use "../mixins/focus-ring" as *;
|
|
10
8
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
//
|
|
2
2
|
// BUTTON COMPONENT
|
|
3
3
|
//
|
|
4
|
-
// properties within each class are sorted alphabetically
|
|
5
4
|
// notice: pseudo-classes for the states *must* follow the order link > visited > hover > focus > active
|
|
6
5
|
//
|
|
7
|
-
//
|
|
8
6
|
|
|
9
7
|
$hds-button-sizes: ( "small", "medium", "large" );
|
|
10
8
|
$hds-button-border-radius: 5px;
|
|
@@ -19,6 +17,7 @@ $hds-button-focus-border-width: 3px;
|
|
|
19
17
|
justify-content: center;
|
|
20
18
|
width: auto;
|
|
21
19
|
font-family: var(--token-typography-font-stack-text);
|
|
20
|
+
text-decoration: none;
|
|
22
21
|
border: $hds-button-border-width solid transparent; // We need this to be transparent for a11y
|
|
23
22
|
border-radius: $hds-button-border-radius;
|
|
24
23
|
outline-style: solid; // used to avoid double outline+focus-ring in Safari (see https://github.com/hashicorp/design-system-components/issues/161#issuecomment-1031548656)
|
|
@@ -28,6 +27,16 @@ $hds-button-focus-border-width: 3px;
|
|
|
28
27
|
// the <a> element behaves differently than a <button>
|
|
29
28
|
@at-root a#{&} {
|
|
30
29
|
width: fit-content;
|
|
30
|
+
|
|
31
|
+
// for more background on the use of underlining as defined below read the following document: https://docs.google.com/document/d/1acLxdRqmy92vQ8ArShPxoBFmAV0StsbZrqEic6MVt20
|
|
32
|
+
&:hover,
|
|
33
|
+
&:focus,
|
|
34
|
+
&:active,
|
|
35
|
+
&.mock-hover,
|
|
36
|
+
&.mock-focus,
|
|
37
|
+
&.mock-active {
|
|
38
|
+
text-decoration: underline;
|
|
39
|
+
}
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
// This covers all of the browsers and focus scenarios (due to the custom focus design).
|
|
@@ -14,10 +14,8 @@
|
|
|
14
14
|
//
|
|
15
15
|
// DROPDOWN COMPONENT
|
|
16
16
|
//
|
|
17
|
-
// properties within each class are sorted alphabetically
|
|
18
17
|
// notice: pseudo-classes for the states *must* follow the order link > visited > hover > focus > active
|
|
19
18
|
//
|
|
20
|
-
//
|
|
21
19
|
|
|
22
20
|
@use "../mixins/focus-ring" as *;
|
|
23
21
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
//
|
|
2
2
|
// LINK > INLINE COMPONENT
|
|
3
3
|
//
|
|
4
|
-
// properties within each class are sorted alphabetically
|
|
5
4
|
// notice: pseudo-classes for the states *must* follow the order link > visited > focus > hover > active
|
|
6
5
|
// see https://github.com/hashicorp/design-system-components/issues/132
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
7
|
|
|
10
8
|
.hds-link-inline {
|
|
11
9
|
border-radius: 2px; // this is used by the outline too
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
//
|
|
2
2
|
// LINK > STANDALONE COMPONENT
|
|
3
3
|
//
|
|
4
|
-
// properties within each class are sorted alphabetically
|
|
5
4
|
// notice: pseudo-classes for the states *must* follow the order link > visited > hover > focus > active
|
|
6
5
|
//
|
|
7
|
-
//
|
|
8
6
|
|
|
9
7
|
@use "../../mixins/focus-ring" as *;
|
|
10
8
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//
|
|
2
|
+
// TABS
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
@use "../mixins/focus-ring" as *;
|
|
6
|
+
|
|
7
|
+
// Sub-components:
|
|
8
|
+
.hds-tabs__tablist-wrapper {
|
|
9
|
+
position: relative;
|
|
10
|
+
|
|
11
|
+
// bottom gray border:
|
|
12
|
+
&::before {
|
|
13
|
+
position: absolute;
|
|
14
|
+
right: 0;
|
|
15
|
+
bottom: calc((var(--token-tabs-indicator-height) - var(--token-tabs-divider-height)) / 2);
|
|
16
|
+
left: 0;
|
|
17
|
+
display: block;
|
|
18
|
+
border-top: var(--token-tabs-divider-height) solid var(--token-color-border-primary);
|
|
19
|
+
content: "";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.hds-tabs__tablist {
|
|
24
|
+
position: relative;
|
|
25
|
+
display: flex;
|
|
26
|
+
margin: 0;
|
|
27
|
+
padding: 0;
|
|
28
|
+
overflow-x: auto;
|
|
29
|
+
-webkit-overflow-scrolling: touch;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.hds-tabs__tab {
|
|
33
|
+
position: relative;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
height: var(--token-tabs-tab-height);
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: var(--token-tabs-tab-padding-vertical) var(--token-tabs-tab-padding-horizontal);
|
|
39
|
+
color: var(--token-color-foreground-primary);
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
list-style: none;
|
|
43
|
+
|
|
44
|
+
&:hover,
|
|
45
|
+
&.mock-hover {
|
|
46
|
+
color: var(--token-color-foreground-action);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.hds-tabs__tab--is-selected {
|
|
50
|
+
color: var(--token-color-foreground-action);
|
|
51
|
+
|
|
52
|
+
&:hover {
|
|
53
|
+
color: var(--token-color-foreground-action-hover);
|
|
54
|
+
|
|
55
|
+
& ~ .hds-tabs__tab-indicator {
|
|
56
|
+
background: var(--token-color-foreground-action-hover);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.hds-tabs__tab-button {
|
|
63
|
+
@include hds-focus-ring-with-pseudo-element(
|
|
64
|
+
$top: var(--token-tabs-tab-focus-inset),
|
|
65
|
+
$right: var(--token-tabs-tab-focus-inset),
|
|
66
|
+
$bottom: var(--token-tabs-tab-focus-inset),
|
|
67
|
+
$left: var(--token-tabs-tab-focus-inset),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
position: static;
|
|
71
|
+
padding: 0;
|
|
72
|
+
color: inherit;
|
|
73
|
+
background-color: transparent;
|
|
74
|
+
border: none;
|
|
75
|
+
border-radius: var(--token-tabs-tab-border-radius);
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
|
|
78
|
+
// Expand click target area
|
|
79
|
+
&::after {
|
|
80
|
+
position: absolute;
|
|
81
|
+
content: "";
|
|
82
|
+
inset: 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.hds-tabs__tab-icon {
|
|
87
|
+
margin-right: var(--token-tabs-tab-gutter);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.hds-tabs__tab-count {
|
|
91
|
+
margin-left: var(--token-tabs-tab-gutter);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.hds-tabs__tab-indicator {
|
|
95
|
+
position: absolute;
|
|
96
|
+
right: 0;
|
|
97
|
+
bottom: 0;
|
|
98
|
+
// notice: this custom prop is set dynamically via JavaScript
|
|
99
|
+
left: var(--indicator-left-pos);
|
|
100
|
+
z-index: 10;
|
|
101
|
+
display: block;
|
|
102
|
+
// notice: this custom prop is set dynamically via JavaScript
|
|
103
|
+
width: var(--indicator-width);
|
|
104
|
+
height: var(--token-tabs-indicator-height);
|
|
105
|
+
background-color: var(--token-color-foreground-action);
|
|
106
|
+
border-radius: var(--token-tabs-indicator-height);
|
|
107
|
+
|
|
108
|
+
@media screen and (prefers-reduced-motion: no-preference) {
|
|
109
|
+
transition-timing-function: var(--token-tabs-indicator-transition-function);
|
|
110
|
+
transition-duration: var(--token-tabs-indicator-transition-duration);
|
|
111
|
+
transition-property: left, width;
|
|
112
|
+
}
|
|
113
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hashicorp/design-system-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "HashiCorp Design System Components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hashicorp",
|
|
@@ -36,32 +36,34 @@
|
|
|
36
36
|
"test:ember:percy": "percy exec ember test"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@hashicorp/design-system-tokens": "^1.
|
|
40
|
-
"@hashicorp/ember-flight-icons": "^3.0.
|
|
41
|
-
"ember-auto-import": "^2.4.
|
|
39
|
+
"@hashicorp/design-system-tokens": "^1.2.0",
|
|
40
|
+
"@hashicorp/ember-flight-icons": "^3.0.1",
|
|
41
|
+
"ember-auto-import": "^2.4.2",
|
|
42
|
+
"ember-cached-decorator-polyfill": "^0.1.4",
|
|
42
43
|
"ember-cli-babel": "^7.26.11",
|
|
43
|
-
"ember-cli-htmlbars": "^6.0
|
|
44
|
+
"ember-cli-htmlbars": "^6.1.0",
|
|
44
45
|
"ember-cli-sass": "^10.0.1",
|
|
45
46
|
"ember-keyboard": "^8.1.0",
|
|
46
47
|
"ember-named-blocks-polyfill": "^0.2.5",
|
|
48
|
+
"ember-style-modifier": "^0.8.0",
|
|
47
49
|
"ember-truth-helpers": "^3.0.0",
|
|
48
50
|
"sass": "^1.43.4"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
53
|
"@ember/optional-features": "^2.0.0",
|
|
52
|
-
"@ember/test-helpers": "^2.
|
|
53
|
-
"@embroider/test-setup": "^1.
|
|
54
|
-
"@glimmer/component": "^1.
|
|
55
|
-
"@glimmer/tracking": "^1.
|
|
56
|
-
"@percy/cli": "^1.
|
|
54
|
+
"@ember/test-helpers": "^2.8.1",
|
|
55
|
+
"@embroider/test-setup": "^1.8.3",
|
|
56
|
+
"@glimmer/component": "^1.1.2",
|
|
57
|
+
"@glimmer/tracking": "^1.1.2",
|
|
58
|
+
"@percy/cli": "^1.12.0",
|
|
57
59
|
"@percy/ember": "^4.0.0",
|
|
58
60
|
"babel-eslint": "^10.1.0",
|
|
59
61
|
"broccoli-asset-rev": "^3.0.0",
|
|
60
62
|
"ember-a11y-refocus": "^2.1.0",
|
|
61
63
|
"ember-a11y-testing": "^5.0.0",
|
|
62
|
-
"ember-cli": "~4.
|
|
64
|
+
"ember-cli": "~4.7.0",
|
|
63
65
|
"ember-cli-clipboard": "^0.16.0",
|
|
64
|
-
"ember-cli-dependency-checker": "^3.3.
|
|
66
|
+
"ember-cli-dependency-checker": "^3.3.1",
|
|
65
67
|
"ember-cli-deprecation-workflow": "^2.1.0",
|
|
66
68
|
"ember-cli-inject-live-reload": "^2.1.0",
|
|
67
69
|
"ember-cli-sri": "^2.1.1",
|
|
@@ -69,36 +71,32 @@
|
|
|
69
71
|
"ember-cli-terser": "^4.0.2",
|
|
70
72
|
"ember-concurrency": "^2.2.0",
|
|
71
73
|
"ember-disable-prototype-extensions": "^1.1.3",
|
|
72
|
-
"ember-export-application-global": "^2.0.1",
|
|
73
74
|
"ember-load-initializers": "^2.1.2",
|
|
74
75
|
"ember-page-title": "^7.0.0",
|
|
75
76
|
"ember-power-select": "^6.0.0",
|
|
76
77
|
"ember-prism": "^0.12.0",
|
|
77
78
|
"ember-qunit": "^5.1.5",
|
|
78
79
|
"ember-resolver": "^8.0.3",
|
|
79
|
-
"ember-source": "~4.
|
|
80
|
+
"ember-source": "~4.7.0",
|
|
80
81
|
"ember-source-channel-url": "^3.0.0",
|
|
81
|
-
"ember-
|
|
82
|
-
"ember-template-lint": "^4.3.0",
|
|
82
|
+
"ember-template-lint": "^4.14.0",
|
|
83
83
|
"ember-template-lint-plugin-prettier": "^4.0.0",
|
|
84
84
|
"ember-try": "^2.0.0",
|
|
85
85
|
"eslint": "^7.32.0",
|
|
86
86
|
"eslint-config-prettier": "^8.5.0",
|
|
87
|
-
"eslint-plugin-ember": "^
|
|
87
|
+
"eslint-plugin-ember": "^11.0.6",
|
|
88
88
|
"eslint-plugin-node": "^11.1.0",
|
|
89
|
-
"eslint-plugin-prettier": "^4.
|
|
90
|
-
"eslint-plugin-qunit": "^7.
|
|
89
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
90
|
+
"eslint-plugin-qunit": "^7.3.1",
|
|
91
91
|
"loader.js": "^4.7.0",
|
|
92
92
|
"npm-run-all": "^4.1.5",
|
|
93
|
-
"prettier": "^2.
|
|
94
|
-
"qunit": "^2.
|
|
93
|
+
"prettier": "^2.7.1",
|
|
94
|
+
"qunit": "^2.19.1",
|
|
95
95
|
"qunit-dom": "^2.0.0",
|
|
96
96
|
"stylelint": "^14.11.0",
|
|
97
|
-
"stylelint-config-prettier-scss": "0.0.1",
|
|
98
97
|
"stylelint-config-rational-order": "^0.1.2",
|
|
99
98
|
"stylelint-config-standard-scss": "^5.0.0",
|
|
100
|
-
"
|
|
101
|
-
"webpack": "^5.70.0"
|
|
99
|
+
"webpack": "^5.74.0"
|
|
102
100
|
},
|
|
103
101
|
"engines": {
|
|
104
102
|
"node": "12.* || 14.* || >= 16"
|