@hashicorp/design-system-components 0.0.13 → 0.0.14
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/.github/ISSUE_TEMPLATE/new-component-quest-issue-engineering-checklist.md +78 -0
- package/addon/components/hds/badge/index.hbs +1 -1
- package/addon/components/hds/badge/index.js +20 -27
- package/addon/components/hds/badge-count/index.hbs +1 -1
- package/addon/components/hds/badge-count/index.js +16 -23
- package/addon/components/hds/button/index.hbs +1 -1
- package/addon/components/hds/button/index.js +26 -34
- package/addon/components/hds/card/container.hbs +1 -4
- package/addon/components/hds/card/container.js +18 -32
- package/addon/components/hds/icon-tile/index.hbs +1 -1
- package/addon/components/hds/icon-tile/index.js +21 -27
- package/addon/components/hds/link/standalone.hbs +20 -0
- package/addon/components/hds/link/standalone.js +132 -0
- package/addon/components/hds/link-to/standalone.hbs +25 -0
- package/addon/components/hds/link-to/standalone.js +158 -0
- package/addon/helpers/hds-link-to-models.js +30 -0
- package/app/components/hds/link/standalone.js +1 -0
- package/app/components/hds/link-to/standalone.js +1 -0
- package/app/helpers/hds-link-to-models.js +1 -0
- package/app/styles/@hashicorp/design-system-components.scss +3 -0
- package/app/styles/components/button.scss +37 -49
- package/app/styles/components/card/container.scss +0 -62
- package/app/styles/components/link/standalone.scss +126 -0
- package/package.json +6 -4
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: New Component Quest Issue/Engineering Checklist
|
|
3
|
+
about: 'DS Team: Engineering Checklist for New Components'
|
|
4
|
+
title: "[Quest] New Component: Component Name"
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
This is the quest issue/engineering checklist for the COMPONENT_NAME Component. All new components will have their own feature branch, and any PR that adds an item from the checklist should target the feature branch, and not `main`.
|
|
11
|
+
|
|
12
|
+
## Pre-Flight Checklist
|
|
13
|
+
Update this list and these links as appropriate.
|
|
14
|
+
|
|
15
|
+
- [Component Doc](url_here): This file should exist before any code is written.
|
|
16
|
+
- [FIGMA Design](url_here): Since we are trying to align the component API naming with the same terms used in the Figma file, it is likely useful to have a fairly stable Figma design before we create a component; it should definitely be finalized before the component ships, however.
|
|
17
|
+
- [Design System Website](https://design-system-website.vercel.app/?path=/story/example-introduction--page) (storybook of storybooks): use for reference, to consider existing features that we might need to replicate in the component.
|
|
18
|
+
|
|
19
|
+
## Engineering Checklist
|
|
20
|
+
The engineering checklist has six parts: creating the feature branch, component template, component backing class, component style, tests, and documentation.
|
|
21
|
+
|
|
22
|
+
### Component Creation
|
|
23
|
+
|
|
24
|
+
- [ ] create new branch from main for the component.
|
|
25
|
+
- [ ] create new component
|
|
26
|
+
- `ember generate component hds/COMPONENT_NAME/index --gc` (the component won't need to be invoked with index, it's just to put all the files in the correct place)
|
|
27
|
+
- if it's a variation on a component, then `hds/COMPONENT_NAME/VARIATION` instead of `index`
|
|
28
|
+
- [ ] **component template**
|
|
29
|
+
- use semantic HTML
|
|
30
|
+
- the component should have a css class that is the same as the component (e.g. `hds/button` should have a class name of `hds-button` on the component, and additional CSS classes should start with this same class name.
|
|
31
|
+
- add `...attributes` unless doing so would be detrimental (e.g., a parent component and child component that both have ...attributes)
|
|
32
|
+
- [ ] **component class**
|
|
33
|
+
- use getters (vs template conditionals or constructors, if possible)
|
|
34
|
+
- write API comments in the JS doc way (copy from an existing DS component)
|
|
35
|
+
- use the same naming as the Figma file for the components API unless it conflicts with a pre-existing HTML attribute. If that is the case, document the difference in the comment.
|
|
36
|
+
- ensure that all existing functionality (from a Structure component) is accounted for in some way. If we are not providing existing functionality at all, it should be documented (along with the reason why). If we are providing temporary functionality, explain that it's temporary and why.
|
|
37
|
+
- check the [design system website](https://design-system-website.vercel.app/?path=/story/example-introduction--page) to see what kind of component functionality is being used across all products
|
|
38
|
+
- booleans should start with a verb (is/has/etc)
|
|
39
|
+
- assertion text should match the content style of the other components.
|
|
40
|
+
- goal is a terse invocation
|
|
41
|
+
- [ ] **component style**
|
|
42
|
+
- create `component/COMPONENT_NAME.scss` in `app/styles`
|
|
43
|
+
- add `@use` to `app/styles/@hashicorp/design-system-components.scss` (see existing code for precise syntax)
|
|
44
|
+
- use design tokens wherever possible, comment where they are not
|
|
45
|
+
- sizes should be in relative units
|
|
46
|
+
- line heights should be unitless
|
|
47
|
+
- [ ] **testing**
|
|
48
|
+
- [ ] test basic functionality
|
|
49
|
+
- [ ] test defaults
|
|
50
|
+
- [ ] try not to repeat tests (i.e., don't have to test all sizes, all colors, etc.)
|
|
51
|
+
- [ ] test all accessibility attributes
|
|
52
|
+
- [ ] **documentation**
|
|
53
|
+
- create component page `ember generate route components/COMPONENT_NAME --dummy`
|
|
54
|
+
- add link to `templates/index.hbs` page
|
|
55
|
+
- [ ] API docs
|
|
56
|
+
- [ ] Usage
|
|
57
|
+
- [ ] Showcase
|
|
58
|
+
|
|
59
|
+
### Component Review
|
|
60
|
+
|
|
61
|
+
Pre-review request checks:
|
|
62
|
+
|
|
63
|
+
- [ ] make sure all tests pass (`ember s` then visit /tests; or `ember t -s`)
|
|
64
|
+
- [ ] check for basic a11y on docs page:
|
|
65
|
+
- keyboard navigation
|
|
66
|
+
- logical DOM order
|
|
67
|
+
- zoom up to 400%
|
|
68
|
+
- color contrast
|
|
69
|
+
- (the axe-core browser plugin can run some basic tests and give immediate feedback)
|
|
70
|
+
- [ ] check page on browsers
|
|
71
|
+
- Chrome
|
|
72
|
+
- Firefox
|
|
73
|
+
- Safari
|
|
74
|
+
- Edge (once available)
|
|
75
|
+
|
|
76
|
+
When ready for review:
|
|
77
|
+
- [ ] add situationally appropriate reviewers
|
|
78
|
+
- [ ] added instructions for reviewers in your PR, letting them know what kind of review you need
|
|
@@ -37,15 +37,6 @@ export default class HdsBadgeIndexComponent extends Component {
|
|
|
37
37
|
return size;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Get a class to apply to the component based on the size argument.
|
|
42
|
-
* @method Badge#sizeClass
|
|
43
|
-
* @return {string} The css class to apply to the component.
|
|
44
|
-
*/
|
|
45
|
-
get sizeClass() {
|
|
46
|
-
return `hds-badge--size-${this.size}`;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
40
|
/**
|
|
50
41
|
* Sets the type of the component
|
|
51
42
|
* Accepted values: filled, inverted, outlined
|
|
@@ -67,15 +58,6 @@ export default class HdsBadgeIndexComponent extends Component {
|
|
|
67
58
|
return type;
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
/**
|
|
71
|
-
* Get a class to apply to the component based on the type argument.
|
|
72
|
-
* @method Badge#typeClass
|
|
73
|
-
* @return {string} The css class to apply to the component.
|
|
74
|
-
*/
|
|
75
|
-
get typeClass() {
|
|
76
|
-
return `hds-badge--type-${this.type}`;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
61
|
/**
|
|
80
62
|
* Sets the color scheme for the component
|
|
81
63
|
* Accepted values: neutral, neutral-dark-mode, highlight, success, warning, critical
|
|
@@ -97,15 +79,6 @@ export default class HdsBadgeIndexComponent extends Component {
|
|
|
97
79
|
return color;
|
|
98
80
|
}
|
|
99
81
|
|
|
100
|
-
/**
|
|
101
|
-
* Get a class to apply to the component based on the color argument.
|
|
102
|
-
* @method Badge#colorClass
|
|
103
|
-
* @return {string} The css class to apply to the component.
|
|
104
|
-
*/
|
|
105
|
-
get colorClass() {
|
|
106
|
-
return `hds-badge--color-${this.color}`;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
82
|
/**
|
|
110
83
|
* @param text
|
|
111
84
|
* @type {string}
|
|
@@ -145,4 +118,24 @@ export default class HdsBadgeIndexComponent extends Component {
|
|
|
145
118
|
}
|
|
146
119
|
return false;
|
|
147
120
|
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the class names to apply to the component.
|
|
124
|
+
* @method Badge#classNames
|
|
125
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
126
|
+
*/
|
|
127
|
+
get classNames() {
|
|
128
|
+
let classes = ['hds-badge'];
|
|
129
|
+
|
|
130
|
+
// add a class based on the @size argument
|
|
131
|
+
classes.push(`hds-badge--size-${this.size}`);
|
|
132
|
+
|
|
133
|
+
// add a class based on the @type argument
|
|
134
|
+
classes.push(`hds-badge--type-${this.type}`);
|
|
135
|
+
|
|
136
|
+
// add a class based on the @color argument
|
|
137
|
+
classes.push(`hds-badge--color-${this.color}`);
|
|
138
|
+
|
|
139
|
+
return classes.join(' ');
|
|
140
|
+
}
|
|
148
141
|
}
|
|
@@ -30,15 +30,6 @@ export default class HdsBadgeCountIndexComponent extends Component {
|
|
|
30
30
|
return size;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* Get a class to apply to the component based on the size argument.
|
|
35
|
-
* @method BadgeCount#sizeClass
|
|
36
|
-
* @return {string} The css class to apply to the component.
|
|
37
|
-
*/
|
|
38
|
-
get sizeClass() {
|
|
39
|
-
return `hds-badge-count--size-${this.size}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
33
|
/**
|
|
43
34
|
* Sets the type of the component
|
|
44
35
|
* Accepted values: filled, inverted, outlined
|
|
@@ -60,15 +51,6 @@ export default class HdsBadgeCountIndexComponent extends Component {
|
|
|
60
51
|
return type;
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
/**
|
|
64
|
-
* Get a class to apply to the component based on the type argument.
|
|
65
|
-
* @method BadgeCount#typeClass
|
|
66
|
-
* @return {string} The css class to apply to the component.
|
|
67
|
-
*/
|
|
68
|
-
get typeClass() {
|
|
69
|
-
return `hds-badge-count--type-${this.type}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
54
|
/**
|
|
73
55
|
* Sets the color scheme for the component
|
|
74
56
|
* Accepted colors: neutral, neutral-dark-mode
|
|
@@ -91,11 +73,22 @@ export default class HdsBadgeCountIndexComponent extends Component {
|
|
|
91
73
|
}
|
|
92
74
|
|
|
93
75
|
/**
|
|
94
|
-
* Get
|
|
95
|
-
* @method BadgeCount#
|
|
96
|
-
* @return {string} The
|
|
76
|
+
* Get the class names to apply to the component.
|
|
77
|
+
* @method BadgeCount#classNames
|
|
78
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
97
79
|
*/
|
|
98
|
-
get
|
|
99
|
-
|
|
80
|
+
get classNames() {
|
|
81
|
+
let classes = ['hds-badge-count'];
|
|
82
|
+
|
|
83
|
+
// add a class based on the @size argument
|
|
84
|
+
classes.push(`hds-badge-count--size-${this.size}`);
|
|
85
|
+
|
|
86
|
+
// add a class based on the @type argument
|
|
87
|
+
classes.push(`hds-badge-count--type-${this.type}`);
|
|
88
|
+
|
|
89
|
+
// add a class based on the @color argument
|
|
90
|
+
classes.push(`hds-badge-count--color-${this.color}`);
|
|
91
|
+
|
|
92
|
+
return classes.join(' ');
|
|
100
93
|
}
|
|
101
94
|
}
|
|
@@ -46,16 +46,6 @@ export default class HdsButtonIndexComponent extends Component {
|
|
|
46
46
|
return size;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* @param sizeClass
|
|
51
|
-
* @type {string}
|
|
52
|
-
* @default hds-button--size-medium
|
|
53
|
-
* @description Determines the CSS class that the button should have, based on the size value; automatically set.
|
|
54
|
-
*/
|
|
55
|
-
get sizeClass() {
|
|
56
|
-
return `hds-button--size-${this.size}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
49
|
/**
|
|
60
50
|
* @param color
|
|
61
51
|
* @type {string}
|
|
@@ -75,16 +65,6 @@ export default class HdsButtonIndexComponent extends Component {
|
|
|
75
65
|
return color;
|
|
76
66
|
}
|
|
77
67
|
|
|
78
|
-
/**
|
|
79
|
-
* @param colorClass
|
|
80
|
-
* @type {string}
|
|
81
|
-
* @default hds-button--color-primary
|
|
82
|
-
* @description Determines the CSS class that the button should have, based on the color value; automatically set
|
|
83
|
-
*/
|
|
84
|
-
get colorClass() {
|
|
85
|
-
return `hds-button--color-${this.color}`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
68
|
/**
|
|
89
69
|
* @param icon
|
|
90
70
|
* @type {string}
|
|
@@ -170,20 +150,6 @@ export default class HdsButtonIndexComponent extends Component {
|
|
|
170
150
|
return this.args.isFullWidth ?? false;
|
|
171
151
|
}
|
|
172
152
|
|
|
173
|
-
/**
|
|
174
|
-
* @param widthClass
|
|
175
|
-
* @type {string|null}
|
|
176
|
-
* @default null
|
|
177
|
-
* @description Determines if the full-width class should be applied to the component. This is set automatically based on the value of `isFullWidth`.
|
|
178
|
-
*/
|
|
179
|
-
get widthClass() {
|
|
180
|
-
if (this.isFullWidth === true) {
|
|
181
|
-
return 'hds-button--width-full';
|
|
182
|
-
} else {
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
153
|
/**
|
|
188
154
|
* @param isDisabled
|
|
189
155
|
* @type {boolean}
|
|
@@ -193,4 +159,30 @@ export default class HdsButtonIndexComponent extends Component {
|
|
|
193
159
|
get isDisabled() {
|
|
194
160
|
return this.args.isDisabled ?? null;
|
|
195
161
|
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the class names to apply to the component.
|
|
165
|
+
* @method Badge#classNames
|
|
166
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
167
|
+
*/
|
|
168
|
+
// "hds-button {{this.sizeClass}} {{this.colorClass}} {{this.widthClass}}"
|
|
169
|
+
get classNames() {
|
|
170
|
+
let classes = ['hds-button'];
|
|
171
|
+
|
|
172
|
+
// add a class based on the @size argument
|
|
173
|
+
classes.push(`hds-button--size-${this.size}`);
|
|
174
|
+
|
|
175
|
+
// add a class based on the @color argument
|
|
176
|
+
classes.push(`hds-button--color-${this.color}`);
|
|
177
|
+
|
|
178
|
+
// add a class based on the @isFullWidth argument
|
|
179
|
+
if (this.isFullWidth) {
|
|
180
|
+
classes.push('hds-button--width-full');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// the button has a "low" elevation effect applied to it
|
|
184
|
+
classes.push('hds-elevation-low');
|
|
185
|
+
|
|
186
|
+
return classes.join(' ');
|
|
187
|
+
}
|
|
196
188
|
}
|
|
@@ -30,15 +30,6 @@ export default class HdsCardContainerComponent extends Component {
|
|
|
30
30
|
return level;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
* Get a class to apply to the component based on the level argument.
|
|
35
|
-
* @method Card#levelClass
|
|
36
|
-
* @return {string} The css class to apply to the component.
|
|
37
|
-
*/
|
|
38
|
-
get levelClass() {
|
|
39
|
-
return `hds-card__container--level-${this.level}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
33
|
/**
|
|
43
34
|
* Sets the background for the component
|
|
44
35
|
* Accepted values: neutral-primary, neutral-secondary
|
|
@@ -60,24 +51,6 @@ export default class HdsCardContainerComponent extends Component {
|
|
|
60
51
|
return background;
|
|
61
52
|
}
|
|
62
53
|
|
|
63
|
-
/**
|
|
64
|
-
* Get a class to apply to the component based on the background argument.
|
|
65
|
-
* @method Card#backgroundClass
|
|
66
|
-
* @return {string} The css class to apply to the component.
|
|
67
|
-
*/
|
|
68
|
-
get backgroundClass() {
|
|
69
|
-
return `hds-card__container--background-${this.background}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Get a class to apply to the component based on the hasBorder argument.
|
|
74
|
-
* @method Card#hasBorderClass
|
|
75
|
-
* @return {string} The css class to apply to the component.
|
|
76
|
-
*/
|
|
77
|
-
get borderClass() {
|
|
78
|
-
return this.args.hasBorder ? `hds-card__container--has-border` : undefined;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
54
|
/**
|
|
82
55
|
* Sets the level for the card
|
|
83
56
|
* Accepted values: visible, hidden
|
|
@@ -100,11 +73,24 @@ export default class HdsCardContainerComponent extends Component {
|
|
|
100
73
|
}
|
|
101
74
|
|
|
102
75
|
/**
|
|
103
|
-
* Get
|
|
104
|
-
* @method Card#
|
|
105
|
-
* @return {string} The
|
|
76
|
+
* Get the class names to apply to the component.
|
|
77
|
+
* @method Card#classNames
|
|
78
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
106
79
|
*/
|
|
107
|
-
get
|
|
108
|
-
|
|
80
|
+
get classNames() {
|
|
81
|
+
let classes = ['hds-card__container'];
|
|
82
|
+
|
|
83
|
+
// add an "elevation" class helper based on the @level and @hasBorder arguments
|
|
84
|
+
classes.push(
|
|
85
|
+
`hds-${this.args.hasBorder ? 'surface' : 'elevation'}-${this.level}`
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// add a class based on the @background argument
|
|
89
|
+
classes.push(`hds-card__container--background-${this.background}`);
|
|
90
|
+
|
|
91
|
+
// add a class based on the @overflow argument
|
|
92
|
+
classes.push(`hds-card__container--overflow-${this.overflow}`);
|
|
93
|
+
|
|
94
|
+
return classes.join(' ');
|
|
109
95
|
}
|
|
110
96
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div class=
|
|
1
|
+
<div class={{this.classNames}} aria-hidden="true" ...attributes>
|
|
2
2
|
{{#if @icon}}
|
|
3
3
|
<div class="hds-icon-tile__icon">
|
|
4
4
|
<FlightIcon @name={{this.icon}} @size={{this.iconSize}} @stretched="true" />
|
|
@@ -39,15 +39,6 @@ export default class HdsIconTileIndexComponent extends Component {
|
|
|
39
39
|
return size;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/**
|
|
43
|
-
* Get a class to apply to the component based on the size argument.
|
|
44
|
-
* @method IconTile#sizeClass
|
|
45
|
-
* @return {string} The css class to apply to the component.
|
|
46
|
-
*/
|
|
47
|
-
get sizeClass() {
|
|
48
|
-
return `hds-icon-tile--size-${this.size}`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
42
|
/**
|
|
52
43
|
* Sets the color scheme for the component
|
|
53
44
|
* Accepted values: see THE COLORS LIST
|
|
@@ -75,15 +66,6 @@ export default class HdsIconTileIndexComponent extends Component {
|
|
|
75
66
|
return color;
|
|
76
67
|
}
|
|
77
68
|
|
|
78
|
-
/**
|
|
79
|
-
* Get a class to apply to the component based on the color argument.
|
|
80
|
-
* @method IconTile#colorClass
|
|
81
|
-
* @return {string} The css class to apply to the component.
|
|
82
|
-
*/
|
|
83
|
-
get colorClass() {
|
|
84
|
-
return `hds-icon-tile--color-${this.color}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
69
|
/**
|
|
88
70
|
* Sets the icon name (one of the FlightIcons)
|
|
89
71
|
*
|
|
@@ -167,15 +149,6 @@ export default class HdsIconTileIndexComponent extends Component {
|
|
|
167
149
|
return entity;
|
|
168
150
|
}
|
|
169
151
|
|
|
170
|
-
/**
|
|
171
|
-
* Get a class to apply to the component based on the its entity.
|
|
172
|
-
* @method IconTile#entityClass
|
|
173
|
-
* @return {string} The css class to apply to the component.
|
|
174
|
-
*/
|
|
175
|
-
get entityClass() {
|
|
176
|
-
return `hds-icon-tile--${this.entity}`;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
152
|
/**
|
|
180
153
|
* Sets the "secondary" icon name (one of the FlightIcons)
|
|
181
154
|
*
|
|
@@ -186,4 +159,25 @@ export default class HdsIconTileIndexComponent extends Component {
|
|
|
186
159
|
get iconSecondary() {
|
|
187
160
|
return this.args.iconSecondary ?? null;
|
|
188
161
|
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the class names to apply to the component.
|
|
165
|
+
* @method IconTile#classNames
|
|
166
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
167
|
+
*/
|
|
168
|
+
// hds-icon-tile {{this.entityClass}} {{this.sizeClass}} {{this.colorClass}}"
|
|
169
|
+
get classNames() {
|
|
170
|
+
let classes = ['hds-icon-tile'];
|
|
171
|
+
|
|
172
|
+
// add a class based on its entity argument
|
|
173
|
+
classes.push(`hds-icon-tile--${this.entity}`);
|
|
174
|
+
|
|
175
|
+
// add a class based on the @size argument
|
|
176
|
+
classes.push(`hds-icon-tile--size-${this.size}`);
|
|
177
|
+
|
|
178
|
+
// add a class based on the @color argument
|
|
179
|
+
classes.push(`hds-icon-tile--color-${this.color}`);
|
|
180
|
+
|
|
181
|
+
return classes.join(' ');
|
|
182
|
+
}
|
|
189
183
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{{! template-lint-disable link-href-attributes }}
|
|
2
|
+
{{! we can disable this linting rule because the developer will add the html attribute themselves }}
|
|
3
|
+
<a class={{this.classNames}} target="_blank" rel="noopener noreferrer" ...attributes>
|
|
4
|
+
{{#if (eq this.iconPosition "leading")}}
|
|
5
|
+
<div class="hds-link-standalone__icon">
|
|
6
|
+
<FlightIcon @name={{this.icon}} @size={{this.iconSize}} @stretched={{true}} />
|
|
7
|
+
</div>
|
|
8
|
+
<div class="hds-link-standalone__text">
|
|
9
|
+
{{this.text}}
|
|
10
|
+
</div>
|
|
11
|
+
{{else}}
|
|
12
|
+
<div class="hds-link-standalone__text">
|
|
13
|
+
{{this.text}}
|
|
14
|
+
</div>
|
|
15
|
+
<div class="hds-link-standalone__icon">
|
|
16
|
+
<FlightIcon @name={{this.icon}} @size={{this.iconSize}} @stretched={{true}} />
|
|
17
|
+
</div>
|
|
18
|
+
{{/if}}
|
|
19
|
+
</a>
|
|
20
|
+
{{! template-lint-enable link-href-attributes }}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { assert } from '@ember/debug';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_ICONPOSITION = 'leading';
|
|
5
|
+
export const DEFAULT_COLOR = 'primary';
|
|
6
|
+
export const DEFAULT_SIZE = 'medium';
|
|
7
|
+
export const ICONPOSITIONS = ['leading', 'trailing'];
|
|
8
|
+
export const COLORS = ['primary', 'secondary'];
|
|
9
|
+
export const SIZES = ['small', 'medium', 'large'];
|
|
10
|
+
|
|
11
|
+
export default class HdsLinkStandaloneComponent extends Component {
|
|
12
|
+
/**
|
|
13
|
+
* @param text
|
|
14
|
+
* @type {string}
|
|
15
|
+
* @description The text of the link. If no text value is defined an error will be thrown.
|
|
16
|
+
*/
|
|
17
|
+
get text() {
|
|
18
|
+
let { text } = this.args;
|
|
19
|
+
|
|
20
|
+
assert(
|
|
21
|
+
'@text for "Hds::Link::Standalone" must have a valid value',
|
|
22
|
+
text !== undefined
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return text;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param color
|
|
30
|
+
* @type {string}
|
|
31
|
+
* @default primary
|
|
32
|
+
* @description Determines the color of link to be used; acceptable values are `primary` and `secondary`
|
|
33
|
+
*/
|
|
34
|
+
get color() {
|
|
35
|
+
let { color = DEFAULT_COLOR } = this.args;
|
|
36
|
+
|
|
37
|
+
assert(
|
|
38
|
+
`@color for "Hds::Link::Standalone" must be one of the following: ${COLORS.join(
|
|
39
|
+
', '
|
|
40
|
+
)}; received: ${color}`,
|
|
41
|
+
COLORS.includes(color)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return color;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param icon
|
|
49
|
+
* @type {string|null}
|
|
50
|
+
* @default null
|
|
51
|
+
* @description The name of the icon to be used. An icon name must be defined.
|
|
52
|
+
*/
|
|
53
|
+
get icon() {
|
|
54
|
+
let { icon } = this.args;
|
|
55
|
+
|
|
56
|
+
assert(
|
|
57
|
+
'@icon for "Hds::Link::Standalone" must have a valid value',
|
|
58
|
+
icon !== undefined
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return icon;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param iconPosition
|
|
66
|
+
* @type {string}
|
|
67
|
+
* @default leading
|
|
68
|
+
* @description Positions the icon before or after the text; allowed values are `leading` or `trailing`
|
|
69
|
+
*/
|
|
70
|
+
get iconPosition() {
|
|
71
|
+
let { iconPosition = DEFAULT_ICONPOSITION } = this.args;
|
|
72
|
+
|
|
73
|
+
assert(
|
|
74
|
+
`@iconPosition for "Hds::Link::Standalone" must be one of the following: ${ICONPOSITIONS.join(
|
|
75
|
+
', '
|
|
76
|
+
)}; received: ${iconPosition}`,
|
|
77
|
+
ICONPOSITIONS.includes(iconPosition)
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return iconPosition;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param size
|
|
85
|
+
* @type {string}
|
|
86
|
+
* @default medium
|
|
87
|
+
* @description The size of the standalone link; acceptable values are `small`, `medium`, and `large`
|
|
88
|
+
*/
|
|
89
|
+
get size() {
|
|
90
|
+
let { size = DEFAULT_SIZE } = this.args;
|
|
91
|
+
|
|
92
|
+
assert(
|
|
93
|
+
`@size for "Hds::Link::Standalone" must be one of the following: ${SIZES.join(
|
|
94
|
+
', '
|
|
95
|
+
)}; received: ${size}`,
|
|
96
|
+
SIZES.includes(size)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return size;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param iconSize
|
|
104
|
+
* @type {string}
|
|
105
|
+
* @default 16
|
|
106
|
+
* @description ensures that the correct icon size is used. Automatically calculated.
|
|
107
|
+
*/
|
|
108
|
+
get iconSize() {
|
|
109
|
+
if (this.args.size === 'large') {
|
|
110
|
+
return '24';
|
|
111
|
+
} else {
|
|
112
|
+
return '16';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get the class names to apply to the component.
|
|
118
|
+
* @method LinkStandalone#classNames
|
|
119
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
120
|
+
*/
|
|
121
|
+
get classNames() {
|
|
122
|
+
let classes = ['hds-link-standalone'];
|
|
123
|
+
|
|
124
|
+
// add a class based on the @size argument
|
|
125
|
+
classes.push(`hds-link-standalone--size-${this.size}`);
|
|
126
|
+
|
|
127
|
+
// add a class based on the @color argument
|
|
128
|
+
classes.push(`hds-link-standalone--color-${this.color}`);
|
|
129
|
+
|
|
130
|
+
return classes.join(' ');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<LinkTo
|
|
2
|
+
class={{this.classNames}}
|
|
3
|
+
@current-when={{@current-when}}
|
|
4
|
+
@models={{hds-link-to-models @model @models}}
|
|
5
|
+
@query={{this.queryParams}}
|
|
6
|
+
@replace={{@replace}}
|
|
7
|
+
@route={{this.route}}
|
|
8
|
+
...attributes
|
|
9
|
+
>
|
|
10
|
+
{{#if (eq this.iconPosition "leading")}}
|
|
11
|
+
<div class="hds-link-standalone__icon">
|
|
12
|
+
<FlightIcon @name={{this.icon}} @size={{this.iconSize}} @stretched={{true}} />
|
|
13
|
+
</div>
|
|
14
|
+
<div class="hds-link-standalone__text">
|
|
15
|
+
{{this.text}}
|
|
16
|
+
</div>
|
|
17
|
+
{{else}}
|
|
18
|
+
<div class="hds-link-standalone__text">
|
|
19
|
+
{{this.text}}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="hds-link-standalone__icon">
|
|
22
|
+
<FlightIcon @name={{this.icon}} @size={{this.iconSize}} @stretched={{true}} />
|
|
23
|
+
</div>
|
|
24
|
+
{{/if}}
|
|
25
|
+
</LinkTo>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { assert } from '@ember/debug';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_ICONPOSITION = 'leading';
|
|
5
|
+
export const DEFAULT_COLOR = 'primary';
|
|
6
|
+
export const DEFAULT_SIZE = 'medium';
|
|
7
|
+
export const ICONPOSITIONS = ['leading', 'trailing'];
|
|
8
|
+
export const COLORS = ['primary', 'secondary'];
|
|
9
|
+
export const SIZES = ['small', 'medium', 'large'];
|
|
10
|
+
|
|
11
|
+
export default class HdsLinkToStandaloneComponent extends Component {
|
|
12
|
+
/**
|
|
13
|
+
* @param text
|
|
14
|
+
* @type {string}
|
|
15
|
+
* @description The text of the link. If no text value is defined an error will be thrown.
|
|
16
|
+
*/
|
|
17
|
+
get text() {
|
|
18
|
+
let { text } = this.args;
|
|
19
|
+
|
|
20
|
+
assert(
|
|
21
|
+
'@text for "Hds::LinkTo::Standalone" must have a valid value',
|
|
22
|
+
text !== undefined
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return text;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param route
|
|
30
|
+
* @type {string|null}
|
|
31
|
+
* @description Checks to make sure route is defined.
|
|
32
|
+
*/
|
|
33
|
+
get route() {
|
|
34
|
+
let { route } = this.args;
|
|
35
|
+
assert(
|
|
36
|
+
'@route must be defined for "Hds::LinkTo::Standalone"',
|
|
37
|
+
route !== undefined
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return route;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param color
|
|
45
|
+
* @type {string}
|
|
46
|
+
* @default primary
|
|
47
|
+
* @description Determines the color of link to be used; acceptable values are `primary` and `secondary`
|
|
48
|
+
*/
|
|
49
|
+
get color() {
|
|
50
|
+
let { color = DEFAULT_COLOR } = this.args;
|
|
51
|
+
|
|
52
|
+
assert(
|
|
53
|
+
`@color for "Hds::LinkTo::Standalone" must be one of the following: ${COLORS.join(
|
|
54
|
+
', '
|
|
55
|
+
)}; received: ${color}`,
|
|
56
|
+
COLORS.includes(color)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return color;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param icon
|
|
64
|
+
* @type {string|null}
|
|
65
|
+
* @default null
|
|
66
|
+
* @description The name of the icon to be used. An icon name must be defined.
|
|
67
|
+
*/
|
|
68
|
+
get icon() {
|
|
69
|
+
let { icon } = this.args;
|
|
70
|
+
|
|
71
|
+
assert(
|
|
72
|
+
'@icon for "Hds::LinkTo::Standalone" must have a valid value',
|
|
73
|
+
icon !== undefined
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return icon;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param iconPosition
|
|
81
|
+
* @type {string}
|
|
82
|
+
* @default leading
|
|
83
|
+
* @description Positions the icon before or after the text; allowed values are `leading` or `trailing`
|
|
84
|
+
*/
|
|
85
|
+
get iconPosition() {
|
|
86
|
+
let { iconPosition = DEFAULT_ICONPOSITION } = this.args;
|
|
87
|
+
|
|
88
|
+
assert(
|
|
89
|
+
`@iconPosition for "Hds::LinkTo::Standalone" must be one of the following: ${ICONPOSITIONS.join(
|
|
90
|
+
', '
|
|
91
|
+
)}; received: ${iconPosition}`,
|
|
92
|
+
ICONPOSITIONS.includes(iconPosition)
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return iconPosition;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param size
|
|
100
|
+
* @type {string}
|
|
101
|
+
* @default medium
|
|
102
|
+
* @description The size of the standalone link; acceptable values are `small`, `medium`, and `large`
|
|
103
|
+
*/
|
|
104
|
+
get size() {
|
|
105
|
+
let { size = DEFAULT_SIZE } = this.args;
|
|
106
|
+
|
|
107
|
+
assert(
|
|
108
|
+
`@size for "Hds::LinkTo::Standalone" must be one of the following: ${SIZES.join(
|
|
109
|
+
', '
|
|
110
|
+
)}; received: ${size}`,
|
|
111
|
+
SIZES.includes(size)
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return size;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param iconSize
|
|
119
|
+
* @type {string}
|
|
120
|
+
* @default 16
|
|
121
|
+
* @description ensures that the correct icon size is used. Automatically calculated.
|
|
122
|
+
*/
|
|
123
|
+
get iconSize() {
|
|
124
|
+
if (this.args.size === 'large') {
|
|
125
|
+
return '24';
|
|
126
|
+
} else {
|
|
127
|
+
return '16';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// this is a workaround for https://github.com/emberjs/ember.js/issues/19693
|
|
132
|
+
// don't remove until we drop support for ember 3.27 and 3.28
|
|
133
|
+
get queryParams() {
|
|
134
|
+
if (this.args.query) {
|
|
135
|
+
return this.args.query;
|
|
136
|
+
} else {
|
|
137
|
+
return {};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get the class names to apply to the component.
|
|
143
|
+
* @method LinkToStandalone#classNames
|
|
144
|
+
* @return {string} The "class" attribute to apply to the component.
|
|
145
|
+
*/
|
|
146
|
+
get classNames() {
|
|
147
|
+
// Notice: we've left this class name the same as the hds::link::standalone (we didn't add the "-to") so we didn't have to replicate the CSS
|
|
148
|
+
let classes = ['hds-link-standalone'];
|
|
149
|
+
|
|
150
|
+
// add a class based on the @size argument
|
|
151
|
+
classes.push(`hds-link-standalone--size-${this.size}`);
|
|
152
|
+
|
|
153
|
+
// add a class based on the @color argument
|
|
154
|
+
classes.push(`hds-link-standalone--color-${this.color}`);
|
|
155
|
+
|
|
156
|
+
return classes.join(' ');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { helper } from '@ember/component/helper';
|
|
2
|
+
import { assert } from '@ember/debug';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* This helper can be used to support both @model and @models arguments when wrapping
|
|
6
|
+
* the `<LinkTo>` component without it triggering assertions or having to use the component helper.
|
|
7
|
+
*
|
|
8
|
+
* The result of this helper should be passed into the `@models` argument of the `<LinkTo>` component:
|
|
9
|
+
*
|
|
10
|
+
* ```hbs
|
|
11
|
+
* <LinkTo @models={{hds-link-to-models @model @models}} />
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export function hdsLinkToModels([model, models]) {
|
|
16
|
+
assert(
|
|
17
|
+
'You cannot provide both the `@model` and `@models` arguments to the component.',
|
|
18
|
+
!model || !models
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
if (model) {
|
|
22
|
+
return [model];
|
|
23
|
+
} else if (models) {
|
|
24
|
+
return models;
|
|
25
|
+
} else {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default helper(hdsLinkToModels);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/components/hds/link/standalone';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/components/hds/link-to/standalone';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@hashicorp/design-system-components/helpers/hds-link-to-models';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
// these are files coming from the 'design-system-tokens' package
|
|
1
2
|
@use "tokens";
|
|
3
|
+
@use "helpers/elevation";
|
|
2
4
|
|
|
3
5
|
@use "../mixins/generic-focus-state";
|
|
4
6
|
|
|
@@ -7,6 +9,7 @@
|
|
|
7
9
|
@use "../components/button";
|
|
8
10
|
@use "../components/card";
|
|
9
11
|
@use "../components/icon-tile";
|
|
12
|
+
@use "../components/link/standalone";
|
|
10
13
|
|
|
11
14
|
.sr-only {
|
|
12
15
|
border: 0 !important;
|
|
@@ -4,25 +4,9 @@ $hds-button-border-radius: 5px;
|
|
|
4
4
|
$hds-button-border-width: 1px;
|
|
5
5
|
$hds-button-focus-border-width: 3px;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
@mixin tempElevation() {
|
|
9
|
-
box-shadow:
|
|
10
|
-
var(--token-elevation-low-shadow-01-x)
|
|
11
|
-
var(--token-elevation-low-shadow-01-y)
|
|
12
|
-
var(--token-elevation-low-shadow-01-blur)
|
|
13
|
-
var(--token-elevation-low-shadow-01-spread)
|
|
14
|
-
var(--token-elevation-low-shadow-01-color),
|
|
15
|
-
var(--token-elevation-low-shadow-02-x)
|
|
16
|
-
var(--token-elevation-low-shadow-02-y)
|
|
17
|
-
var(--token-elevation-low-shadow-02-blur)
|
|
18
|
-
var(--token-elevation-low-shadow-02-spread)
|
|
19
|
-
var(--token-elevation-low-shadow-02-color)
|
|
20
|
-
;
|
|
21
|
-
}
|
|
7
|
+
$hds-button-sizes: ( 'small', 'medium', 'large' );
|
|
22
8
|
|
|
23
9
|
.hds-button {
|
|
24
|
-
@include tempElevation();
|
|
25
|
-
|
|
26
10
|
align-items: center;
|
|
27
11
|
border: $hds-button-border-width solid transparent; // We need this to be transparent for a11y
|
|
28
12
|
border-radius: $hds-button-border-radius;
|
|
@@ -101,41 +85,45 @@ $hds-button-focus-border-width: 3px;
|
|
|
101
85
|
|
|
102
86
|
// SIZE
|
|
103
87
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
88
|
+
// these values later may come from the design tokens
|
|
89
|
+
$size-props: (
|
|
90
|
+
"small": (
|
|
91
|
+
"font-size": 0.8125rem, // 13px;
|
|
92
|
+
"line-height": 1,
|
|
93
|
+
"min-height": 1.75rem, // 28px
|
|
94
|
+
"padding": 0 1rem, // 0 16px
|
|
95
|
+
"icon-size": 0.75rem, // 12px
|
|
96
|
+
),
|
|
97
|
+
"medium": (
|
|
98
|
+
"font-size": 0.875rem, // 14px
|
|
99
|
+
"line-height": 1rem,// 16px
|
|
100
|
+
"min-height": 2.25rem, // 36px
|
|
101
|
+
"padding": 0.625rem 1rem, // 10px 16px
|
|
102
|
+
"icon-size": 1rem, // 16px
|
|
103
|
+
),
|
|
104
|
+
"large": (
|
|
105
|
+
"font-size": 1rem, //16px
|
|
106
|
+
"line-height": 1.5rem, // 24px
|
|
107
|
+
"min-height": 3rem, // 48px
|
|
108
|
+
"padding": 0.75rem 1.25rem, // 12px 20px
|
|
109
|
+
"icon-size": 1.5rem, // 24px
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
@each $size in $hds-button-sizes {
|
|
114
|
+
.hds-button--size-#{$size} {
|
|
115
|
+
font-size: map-get($size-props, $size, "font-size");
|
|
116
|
+
min-height: map-get($size-props, $size, "min-height");
|
|
117
|
+
line-height: map-get($size-props, $size, "line-height");
|
|
118
|
+
padding: map-get($size-props, $size, "padding");
|
|
119
|
+
|
|
120
|
+
.hds-button__icon {
|
|
121
|
+
height: map-get($size-props, $size, "icon-size");
|
|
122
|
+
width: map-get($size-props, $size, "icon-size");
|
|
123
|
+
}
|
|
125
124
|
}
|
|
126
125
|
}
|
|
127
126
|
|
|
128
|
-
.hds-button--size-large {
|
|
129
|
-
font-size: 1rem; //16px
|
|
130
|
-
line-height: 1.5rem; // 24px
|
|
131
|
-
min-height: 3rem; //48px
|
|
132
|
-
padding: 0.75rem 1.25rem; // 12px 20px
|
|
133
|
-
|
|
134
|
-
.hds-button__icon {
|
|
135
|
-
height: 1.5rem;
|
|
136
|
-
width: 1.5rem;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
127
|
|
|
140
128
|
// COLORS & STATES
|
|
141
129
|
// Note: the order of the pseuo-selectors need to stay the way they are; it doesn't match the Figma file but it's the correct order for browsers to render the styles correctly.
|
|
@@ -5,56 +5,6 @@
|
|
|
5
5
|
//
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
-
// this mixin is used to apply the "elevation" styles to the card container
|
|
9
|
-
// depending on the "elevation level" and if it has a border applied to it.
|
|
10
|
-
// we are mimicking the way this effect is defined in Figma, through a set of
|
|
11
|
-
// multiple drop shadows (also the border is a 1px shadow); we tried using an
|
|
12
|
-
// outline but Safari still doesn't support rounded edges for outlines.
|
|
13
|
-
// for details see: https://www.figma.com/file/oQsMzMMnynfPWpMEt91OpH/?node-id=1988%3A2
|
|
14
|
-
|
|
15
|
-
@mixin getElevationStyle($level, $has-border: false) {
|
|
16
|
-
$drop-shadow: false;
|
|
17
|
-
$border-shadow: false;
|
|
18
|
-
|
|
19
|
-
// here we define the "drop-shadow" values (there are two shadows applied)
|
|
20
|
-
// notice: the "base" level doesn't have a "drop shadow" effect applied (no elevation)
|
|
21
|
-
@if ($level != 'base') {
|
|
22
|
-
$drop-shadow:
|
|
23
|
-
var(--token-elevation-#{$level}-shadow-01-x)
|
|
24
|
-
var(--token-elevation-#{$level}-shadow-01-y)
|
|
25
|
-
var(--token-elevation-#{$level}-shadow-01-blur)
|
|
26
|
-
var(--token-elevation-#{$level}-shadow-01-spread)
|
|
27
|
-
var(--token-elevation-#{$level}-shadow-01-color),
|
|
28
|
-
var(--token-elevation-#{$level}-shadow-02-x)
|
|
29
|
-
var(--token-elevation-#{$level}-shadow-02-y)
|
|
30
|
-
var(--token-elevation-#{$level}-shadow-02-blur)
|
|
31
|
-
var(--token-elevation-#{$level}-shadow-02-spread)
|
|
32
|
-
var(--token-elevation-#{$level}-shadow-02-color)
|
|
33
|
-
;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// here we define the "border-shadow" values
|
|
37
|
-
// notice: we create a border via a shadow, so we have zero values for x/y/blur
|
|
38
|
-
@if ($has-border) {
|
|
39
|
-
$border-shadow:
|
|
40
|
-
0
|
|
41
|
-
0
|
|
42
|
-
0
|
|
43
|
-
var(--token-elevation-#{$level}-border-width)
|
|
44
|
-
var(--token-elevation-#{$level}-border-color);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// here we join the two effects in a single box-shadow (depending on the different cases)
|
|
48
|
-
@if ($drop-shadow and not $border-shadow) {
|
|
49
|
-
box-shadow: $drop-shadow;
|
|
50
|
-
} @else if($border-shadow and not $drop-shadow) {
|
|
51
|
-
box-shadow: $border-shadow;
|
|
52
|
-
} @else {
|
|
53
|
-
// notice: we put the "border-shadow" first because the final rendering in the browser looks better
|
|
54
|
-
// see: https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow - "The z-ordering of multiple box shadows is the same as multiple text shadows (the first specified shadow is on top)."
|
|
55
|
-
box-shadow: $border-shadow, $drop-shadow;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
8
|
|
|
59
9
|
$hds-card-container-levels: ( 'base', 'mid', 'high' );
|
|
60
10
|
|
|
@@ -66,18 +16,6 @@ $hds-card-container-border-radius: 6px;
|
|
|
66
16
|
position: relative;
|
|
67
17
|
}
|
|
68
18
|
|
|
69
|
-
// LEVEL (elevation style as "drop" + "border" shadow effects)
|
|
70
|
-
|
|
71
|
-
@each $level in $hds-card-container-levels {
|
|
72
|
-
.hds-card__container--level-#{$level} {
|
|
73
|
-
@include getElevationStyle($level);
|
|
74
|
-
|
|
75
|
-
&.hds-card__container--has-border {
|
|
76
|
-
@include getElevationStyle($level, true);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
19
|
|
|
82
20
|
// BACKGROUND
|
|
83
21
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
$hds-link-standalone-border-radius: 5px;
|
|
2
|
+
$hds-link-standalone-sizes: ( 'small', 'medium', 'large' );
|
|
3
|
+
$hds-link-standalone-border-width: 1px;
|
|
4
|
+
$hds-link-standalone-focus-border-width: 3px + $hds-link-standalone-border-width;
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
.hds-link-standalone {
|
|
8
|
+
align-items: center;
|
|
9
|
+
background-color: transparent;
|
|
10
|
+
border: $hds-link-standalone-border-width solid transparent; // needs to exist AND be transparent for a11y
|
|
11
|
+
border-radius: $hds-link-standalone-border-radius;
|
|
12
|
+
color: var(--token-color-action-foreground-on-faint);
|
|
13
|
+
display: flex;
|
|
14
|
+
font-family: var(--token-typography-body-base-font-family);
|
|
15
|
+
justify-content: center;
|
|
16
|
+
outline-color: transparent;
|
|
17
|
+
padding: 0.25rem; // should be 4px; iconPosition will override it on one side
|
|
18
|
+
position: relative;
|
|
19
|
+
text-decoration: none;
|
|
20
|
+
width: fit-content;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// these values later may come from the design tokens
|
|
24
|
+
$size-props: (
|
|
25
|
+
"small": (
|
|
26
|
+
"font-size": 0.8125rem, // 13px;
|
|
27
|
+
"icon-size": 0.75rem, // 12px
|
|
28
|
+
"line-height": 0.75,
|
|
29
|
+
),
|
|
30
|
+
"medium": (
|
|
31
|
+
"font-size": 0.875rem, // 14px
|
|
32
|
+
"icon-size": 1rem, // 16px
|
|
33
|
+
"line-height": 1, // 16px
|
|
34
|
+
),
|
|
35
|
+
"large": (
|
|
36
|
+
"font-size": 1rem, // 16px
|
|
37
|
+
"icon-size": 1.5rem, // 24px
|
|
38
|
+
"line-height": 1.5, // 24px
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
@each $size in $hds-link-standalone-sizes {
|
|
43
|
+
.hds-link-standalone--size-#{$size} {
|
|
44
|
+
|
|
45
|
+
.hds-link-standalone__icon {
|
|
46
|
+
height: map-get($size-props, $size, "icon-size");
|
|
47
|
+
width: map-get($size-props, $size, "icon-size");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.hds-link-standalone__text {
|
|
51
|
+
font-size: map-get($size-props, $size, "font-size");
|
|
52
|
+
line-height: map-get($size-props, $size, "line-height");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.hds-link-standalone__text {
|
|
59
|
+
flex: 1 0 0;
|
|
60
|
+
.hds-link-standalone__icon + & {
|
|
61
|
+
margin-left: 0.375rem;
|
|
62
|
+
}
|
|
63
|
+
& +.hds-link-standalone__icon {
|
|
64
|
+
margin-left: 0.375rem;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// COLORS & STATES
|
|
69
|
+
// Note: the order of the pseuo-selectors need to stay the way they are
|
|
70
|
+
|
|
71
|
+
.hds-link-standalone--color-primary {
|
|
72
|
+
color: var(--token-color-action-foreground-on-faint);
|
|
73
|
+
|
|
74
|
+
&:visited {
|
|
75
|
+
color: var(--token-color-action-foreground-on-faint);
|
|
76
|
+
}
|
|
77
|
+
&:hover,
|
|
78
|
+
&.is-hover {
|
|
79
|
+
text-decoration-color: #4E81E8;
|
|
80
|
+
text-decoration: underline;
|
|
81
|
+
transition: text-decoration-color 0.25s ease-in;
|
|
82
|
+
}
|
|
83
|
+
&:focus,
|
|
84
|
+
&:focus-visible,
|
|
85
|
+
&.is-focus {
|
|
86
|
+
outline: 2px solid transparent;
|
|
87
|
+
box-shadow:
|
|
88
|
+
0 0 0 $hds-link-standalone-border-width var(--token-color-action-border-on-primary),
|
|
89
|
+
0 0 0 $hds-link-standalone-focus-border-width #5990FF;
|
|
90
|
+
}
|
|
91
|
+
&:active,
|
|
92
|
+
&.is-active {
|
|
93
|
+
color: var(--token-color-action-foreground-high-contrast);
|
|
94
|
+
text-decoration: underline;
|
|
95
|
+
text-decoration-color: #596987;
|
|
96
|
+
&::before {
|
|
97
|
+
border-color: transparent;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.hds-link-standalone--color-secondary {
|
|
103
|
+
background-color: transparent;
|
|
104
|
+
color: var(--token-color-neutral-foreground-primary);
|
|
105
|
+
|
|
106
|
+
&:focus,
|
|
107
|
+
&:focus-visible,
|
|
108
|
+
&.is-focus {
|
|
109
|
+
outline: 2px solid transparent;
|
|
110
|
+
box-shadow:
|
|
111
|
+
0 0 0 $hds-link-standalone-border-width var(--token-color-action-border-on-primary),
|
|
112
|
+
0 0 0 $hds-link-standalone-focus-border-width #5990FF;
|
|
113
|
+
}
|
|
114
|
+
&:hover,
|
|
115
|
+
&.is-hover {
|
|
116
|
+
text-decoration: underline;
|
|
117
|
+
text-decoration-color: var(--token-color-neutral-foreground-primary);
|
|
118
|
+
}
|
|
119
|
+
&:active,
|
|
120
|
+
&.is-active {
|
|
121
|
+
color: var(--token-color-neutral-foreground-secondary);
|
|
122
|
+
text-decoration: underline;
|
|
123
|
+
text-decoration-color: var(--token-color-neutral-foreground-primary);
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hashicorp/design-system-components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "HashiCorp Design System Components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hashicorp",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"prepare": "husky install"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@hashicorp/design-system-tokens": "^0.0
|
|
64
|
+
"@hashicorp/design-system-tokens": "^0.1.0",
|
|
65
65
|
"@hashicorp/ember-flight-icons": "^2.0.0",
|
|
66
66
|
"ember-cli-babel": "^7.26.6",
|
|
67
67
|
"ember-cli-htmlbars": "^5.7.1",
|
|
@@ -78,12 +78,14 @@
|
|
|
78
78
|
"@percy/ember": "^3.0.0",
|
|
79
79
|
"babel-eslint": "^10.1.0",
|
|
80
80
|
"broccoli-asset-rev": "^3.0.0",
|
|
81
|
+
"ember-a11y-refocus": "^2.1.0",
|
|
81
82
|
"ember-auto-import": "^2.2.3",
|
|
82
83
|
"ember-cli": "~3.28.4",
|
|
83
84
|
"ember-cli-dependency-checker": "^3.2.0",
|
|
84
85
|
"ember-cli-inject-live-reload": "^2.1.0",
|
|
85
86
|
"ember-cli-markdown-it-templates": "^0.0.3",
|
|
86
87
|
"ember-cli-sri": "^2.1.1",
|
|
88
|
+
"ember-cli-string-helpers": "^6.1.0",
|
|
87
89
|
"ember-cli-terser": "^4.0.2",
|
|
88
90
|
"ember-disable-prototype-extensions": "^1.1.3",
|
|
89
91
|
"ember-export-application-global": "^2.0.1",
|
|
@@ -104,8 +106,8 @@
|
|
|
104
106
|
"eslint-plugin-node": "^11.1.0",
|
|
105
107
|
"eslint-plugin-prettier": "^3.4.1",
|
|
106
108
|
"eslint-plugin-qunit": "^6.2.0",
|
|
107
|
-
"husky": "
|
|
108
|
-
"lint-staged": "
|
|
109
|
+
"husky": "^7.0.4",
|
|
110
|
+
"lint-staged": "^12.1.2",
|
|
109
111
|
"loader.js": "^4.7.0",
|
|
110
112
|
"npm-run-all": "^4.1.5",
|
|
111
113
|
"prettier": "^2.3.2",
|