@hashicorp/design-system-components 2.14.1 → 2.15.0
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 +21 -0
- package/addon/components/hds/button/index.js +5 -0
- package/addon/components/hds/pagination/compact/index.js +66 -27
- package/addon/components/hds/pagination/numbered/index.js +13 -13
- package/addon/components/hds/tabs/index.js +16 -6
- package/app/styles/components/dropdown.scss +3 -3
- package/app/styles/mixins/_button.scss +14 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @hashicorp/design-system-components
|
|
2
2
|
|
|
3
|
+
## 2.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1690](https://github.com/hashicorp/design-system/pull/1690) [`33df4e25e`](https://github.com/hashicorp/design-system/commit/33df4e25e7bff4dabbba3744128449e2b99d4911) Thanks [@didoo](https://github.com/didoo)! - `Button` - updated horizontal padding of icon-only variant
|
|
8
|
+
`Dropdown::ToggleIcon` - updated sizing of the "small" variant to match the height of the "small" variant `Button`
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- [#1736](https://github.com/hashicorp/design-system/pull/1736) [`541d22442`](https://github.com/hashicorp/design-system/commit/541d22442396d33850a68a61e2781094df1b121a) Thanks [@didoo](https://github.com/didoo)! - `Pagination` - Removed handling of query parameters from `onPageSizeChange` function.
|
|
13
|
+
|
|
14
|
+
_Notice: while technically this is a breaking change, we consider this a fast-follow fix for the previous release._
|
|
15
|
+
|
|
16
|
+
## 2.14.2
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#1724](https://github.com/hashicorp/design-system/pull/1724) [`65ebe6dde`](https://github.com/hashicorp/design-system/commit/65ebe6ddeb477ebc74ad6db353aaf19e1dfb06b1) Thanks [@didoo](https://github.com/didoo)! - `Pagination` - updated the logic for “Compact” variant to expose `@currentPageSize` and handle controlled/uncontrolled changes
|
|
21
|
+
|
|
22
|
+
- [#1716](https://github.com/hashicorp/design-system/pull/1716) [`cde67bc7f`](https://github.com/hashicorp/design-system/commit/cde67bc7fc32c1025ddd22de6d0f9baeabf43961) Thanks [@didoo](https://github.com/didoo)! - `Tabs` - replace `assert` with `warn` in `setIndicator` function
|
|
23
|
+
|
|
3
24
|
## 2.14.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -158,6 +158,11 @@ export default class HdsButtonIndexComponent extends Component {
|
|
|
158
158
|
classes.push('hds-button--width-full');
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
// add a class if it's icon-only
|
|
162
|
+
if (this.isIconOnly) {
|
|
163
|
+
classes.push('hds-button--is-icon-only');
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
return classes.join(' ');
|
|
162
167
|
}
|
|
163
168
|
}
|
|
@@ -4,17 +4,27 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import Component from '@glimmer/component';
|
|
7
|
+
import { tracked } from '@glimmer/tracking';
|
|
7
8
|
import { action } from '@ember/object';
|
|
8
9
|
import { assert } from '@ember/debug';
|
|
9
|
-
import { inject as service } from '@ember/service';
|
|
10
10
|
|
|
11
11
|
// for context about the decision to use these values, see:
|
|
12
12
|
// https://hashicorp.slack.com/archives/C03A0N1QK8S/p1673546329082759
|
|
13
13
|
export const DEFAULT_PAGE_SIZES = [10, 30, 50];
|
|
14
14
|
|
|
15
15
|
export default class HdsPaginationCompactIndexComponent extends Component {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// This private variable is used to differentiate between
|
|
17
|
+
// "uncontrolled" component (where the state is handled internally) and
|
|
18
|
+
// "controlled" component (where the state is handled externally, by the consumer's code).
|
|
19
|
+
// In the first case, the variable stores the internal state of the component at any moment,
|
|
20
|
+
// and its value is updated internally according to the user's interaction with the component.
|
|
21
|
+
// In the second case, the variable stores *only* the initial state of the component (coming from the arguments)
|
|
22
|
+
// at rendering time, but from that moment on it's not updated anymore, no matter what interaction the user
|
|
23
|
+
// has with the component (the state is controlled externally, eg. via query parameters)
|
|
24
|
+
@tracked _currentPageSize = this.args.currentPageSize ?? this.pageSizes[0];
|
|
25
|
+
@tracked isControlled;
|
|
26
|
+
|
|
27
|
+
showLabels = this.args.showLabels ?? true; // if the labels for the "prev/next" controls are visible
|
|
18
28
|
showSizeSelector = this.args.showSizeSelector ?? false; // if the "size selector" block is visible
|
|
19
29
|
|
|
20
30
|
constructor() {
|
|
@@ -31,28 +41,16 @@ export default class HdsPaginationCompactIndexComponent extends Component {
|
|
|
31
41
|
// initialized and updated using the arguments passed to it.
|
|
32
42
|
|
|
33
43
|
if (queryFunction === undefined) {
|
|
34
|
-
this.
|
|
44
|
+
this.isControlled = false;
|
|
35
45
|
} else {
|
|
36
46
|
assert(
|
|
37
47
|
'@queryFunction for "Hds::Pagination::Numbered" must be a function',
|
|
38
48
|
typeof queryFunction === 'function'
|
|
39
49
|
);
|
|
40
|
-
this.
|
|
50
|
+
this.isControlled = true;
|
|
41
51
|
}
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
/**
|
|
45
|
-
* @param showLabels
|
|
46
|
-
* @type {boolean}
|
|
47
|
-
* @default true
|
|
48
|
-
* @description Show the labels for the "prev/next" controls
|
|
49
|
-
*/
|
|
50
|
-
get showLabels() {
|
|
51
|
-
let { showLabels = true } = this.args;
|
|
52
|
-
|
|
53
|
-
return showLabels;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
54
|
/**
|
|
57
55
|
* @param ariaLabel
|
|
58
56
|
* @type {string}
|
|
@@ -62,6 +60,35 @@ export default class HdsPaginationCompactIndexComponent extends Component {
|
|
|
62
60
|
return this.args.ariaLabel ?? 'Pagination';
|
|
63
61
|
}
|
|
64
62
|
|
|
63
|
+
// This very specific `get/set` pattern is used to handle the two different use cases of the component
|
|
64
|
+
// being "controlled" (when it has routing, meaning it needs to support pagination controls as links/`LinkTo`)
|
|
65
|
+
// vs being "uncontrolled" (see comments above for details).
|
|
66
|
+
//
|
|
67
|
+
// If it has routing (and so it's "controlled"), than the value ("state") of the `currentPageSize` variable
|
|
68
|
+
// is *always* determined by the controller via arguments (most of the times, connected to query parameters in the URL).
|
|
69
|
+
// For this reason the "get" method always returns the value from the `args`,
|
|
70
|
+
// while the "set" method never updates the private internal state (_variable).
|
|
71
|
+
//
|
|
72
|
+
// If instead it doesn't have routing (and so it's "uncontrolled") than the value ("state") of the `currentPageSize` variables
|
|
73
|
+
// is *always* determined by the component's internal logic (and updated according to the user interaction with it).
|
|
74
|
+
// For this reason the "get" and "set" methods always read from or write to the private internal state (_variable).
|
|
75
|
+
|
|
76
|
+
get currentPageSize() {
|
|
77
|
+
if (this.isControlled) {
|
|
78
|
+
return this.args.currentPageSize;
|
|
79
|
+
} else {
|
|
80
|
+
return this._currentPageSize;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
set currentPageSize(value) {
|
|
85
|
+
if (this.isControlled) {
|
|
86
|
+
// noop
|
|
87
|
+
} else {
|
|
88
|
+
this._currentPageSize = value;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
65
92
|
/**
|
|
66
93
|
* @param pageSizes
|
|
67
94
|
* @type {array of numbers}
|
|
@@ -79,13 +106,9 @@ export default class HdsPaginationCompactIndexComponent extends Component {
|
|
|
79
106
|
return pageSizes;
|
|
80
107
|
}
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
buildQueryParamsObject(page) {
|
|
87
|
-
if (this.hasRouting) {
|
|
88
|
-
return this.args.queryFunction(page, this.currentPage);
|
|
109
|
+
buildQueryParamsObject(page, pageSize) {
|
|
110
|
+
if (this.isControlled) {
|
|
111
|
+
return this.args.queryFunction(page, pageSize);
|
|
89
112
|
} else {
|
|
90
113
|
return {};
|
|
91
114
|
}
|
|
@@ -100,9 +123,15 @@ export default class HdsPaginationCompactIndexComponent extends Component {
|
|
|
100
123
|
};
|
|
101
124
|
|
|
102
125
|
// the "query" is dynamic and needs to be calculated
|
|
103
|
-
if (this.
|
|
104
|
-
routing.queryPrev = this.buildQueryParamsObject(
|
|
105
|
-
|
|
126
|
+
if (this.isControlled) {
|
|
127
|
+
routing.queryPrev = this.buildQueryParamsObject(
|
|
128
|
+
'prev',
|
|
129
|
+
this.currentPageSize
|
|
130
|
+
);
|
|
131
|
+
routing.queryNext = this.buildQueryParamsObject(
|
|
132
|
+
'next',
|
|
133
|
+
this.currentPageSize
|
|
134
|
+
);
|
|
106
135
|
} else {
|
|
107
136
|
routing.queryPrev = undefined;
|
|
108
137
|
routing.queryNext = undefined;
|
|
@@ -121,4 +150,14 @@ export default class HdsPaginationCompactIndexComponent extends Component {
|
|
|
121
150
|
onPageChange(newPage);
|
|
122
151
|
}
|
|
123
152
|
}
|
|
153
|
+
|
|
154
|
+
@action
|
|
155
|
+
onPageSizeChange(newPageSize) {
|
|
156
|
+
let { onPageSizeChange } = this.args;
|
|
157
|
+
|
|
158
|
+
// invoke the callback function
|
|
159
|
+
if (typeof onPageSizeChange === 'function') {
|
|
160
|
+
onPageSizeChange(newPageSize);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
124
163
|
}
|
|
@@ -85,6 +85,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
85
85
|
// has with the component (the state is controlled externally, eg. via query parameters)
|
|
86
86
|
@tracked _currentPage = this.args.currentPage ?? 1;
|
|
87
87
|
@tracked _currentPageSize = this.args.currentPageSize ?? this.pageSizes[0];
|
|
88
|
+
@tracked isControlled;
|
|
88
89
|
|
|
89
90
|
showInfo = this.args.showInfo ?? true; // if the "info" block is visible
|
|
90
91
|
showLabels = this.args.showLabels ?? false; // if the labels for the "prev/next" controls are visible
|
|
@@ -107,7 +108,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
107
108
|
// initialized and updated using the arguments passed to it.
|
|
108
109
|
|
|
109
110
|
if (queryFunction === undefined) {
|
|
110
|
-
this.
|
|
111
|
+
this.isControlled = false;
|
|
111
112
|
} else {
|
|
112
113
|
assert(
|
|
113
114
|
'@queryFunction for "Hds::Pagination::Numbered" must be a function',
|
|
@@ -118,7 +119,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
118
119
|
typeof this.args.currentPageSize === 'number' &&
|
|
119
120
|
typeof this.args.currentPage === 'number'
|
|
120
121
|
);
|
|
121
|
-
this.
|
|
122
|
+
this.isControlled = true;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
assert(
|
|
@@ -137,7 +138,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
// This very specific `get/set` pattern is used to handle the two different use cases of the component
|
|
140
|
-
// being "controlled" (when it has routing, meaning it needs to support
|
|
141
|
+
// being "controlled" (when it has routing, meaning it needs to support pagination controls as links/`LinkTo`)
|
|
141
142
|
// vs being "uncontrolled" (see comments above for details).
|
|
142
143
|
//
|
|
143
144
|
// If it has routing (and so it's "controlled"), than the value ("state") of the `currentPage/currentPageSize` variables
|
|
@@ -150,7 +151,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
150
151
|
// For this reason the "get" and "set" methods always read from or write to the private internal state (_variable).
|
|
151
152
|
|
|
152
153
|
get currentPage() {
|
|
153
|
-
if (this.
|
|
154
|
+
if (this.isControlled) {
|
|
154
155
|
return this.args.currentPage;
|
|
155
156
|
} else {
|
|
156
157
|
return this._currentPage;
|
|
@@ -158,7 +159,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
set currentPage(value) {
|
|
161
|
-
if (this.
|
|
162
|
+
if (this.isControlled) {
|
|
162
163
|
// noop
|
|
163
164
|
} else {
|
|
164
165
|
this._currentPage = value;
|
|
@@ -166,7 +167,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
get currentPageSize() {
|
|
169
|
-
if (this.
|
|
170
|
+
if (this.isControlled) {
|
|
170
171
|
return this.args.currentPageSize;
|
|
171
172
|
} else {
|
|
172
173
|
return this._currentPageSize;
|
|
@@ -174,7 +175,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
set currentPageSize(value) {
|
|
177
|
-
if (this.
|
|
178
|
+
if (this.isControlled) {
|
|
178
179
|
// noop
|
|
179
180
|
} else {
|
|
180
181
|
this._currentPageSize = value;
|
|
@@ -242,7 +243,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
buildQueryParamsObject(page, pageSize) {
|
|
245
|
-
if (this.
|
|
246
|
+
if (this.isControlled) {
|
|
246
247
|
return this.args.queryFunction(page, pageSize);
|
|
247
248
|
} else {
|
|
248
249
|
return {};
|
|
@@ -258,7 +259,7 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
258
259
|
};
|
|
259
260
|
|
|
260
261
|
// the "query" is dynamic and needs to be calculated
|
|
261
|
-
if (this.
|
|
262
|
+
if (this.isControlled) {
|
|
262
263
|
routing.queryPrev = this.buildQueryParamsObject(
|
|
263
264
|
this.currentPage - 1,
|
|
264
265
|
this.currentPageSize
|
|
@@ -323,10 +324,9 @@ export default class HdsPaginationNumberedIndexComponent extends Component {
|
|
|
323
324
|
let { onPageSizeChange } = this.args;
|
|
324
325
|
|
|
325
326
|
// we need to manually update the query parameters in the route (it's not a link!)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
queryParams = this.buildQueryParamsObject(1, newPageSize);
|
|
327
|
+
if (this.isControlled) {
|
|
328
|
+
// notice: we agreed to reset the pagination to the first element (any alternative would result in an unpredictable UX)
|
|
329
|
+
const queryParams = this.buildQueryParamsObject(1, newPageSize);
|
|
330
330
|
this.router.transitionTo({ queryParams });
|
|
331
331
|
} else {
|
|
332
332
|
this.currentPage = 1;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import Component from '@glimmer/component';
|
|
7
7
|
import { tracked } from '@glimmer/tracking';
|
|
8
8
|
import { action } from '@ember/object';
|
|
9
|
-
import { assert } from '@ember/debug';
|
|
9
|
+
import { assert, warn } from '@ember/debug';
|
|
10
10
|
import { next, schedule } from '@ember/runloop';
|
|
11
11
|
|
|
12
12
|
export default class HdsTabsIndexComponent extends Component {
|
|
@@ -188,13 +188,23 @@ export default class HdsTabsIndexComponent extends Component {
|
|
|
188
188
|
);
|
|
189
189
|
}
|
|
190
190
|
} else {
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
let message;
|
|
192
|
+
message +=
|
|
193
|
+
'"Hds::Tabs" has tried to set the indicator for an element that doesn\'t exist';
|
|
194
|
+
if (this.tabNodes.length === 0) {
|
|
195
|
+
message +=
|
|
196
|
+
' (the array `this.tabNodes` is empty, there are no tabs, probably already destroyed)';
|
|
197
|
+
} else {
|
|
198
|
+
message += ` (the value ${
|
|
193
199
|
this.selectedTabIndex
|
|
194
|
-
} of \`this.selectedTabIndex\` is out of bound for the array \`this.tabNodes\`, whose index range is [0
|
|
200
|
+
} of \`this.selectedTabIndex\` is out of bound for the array \`this.tabNodes\`, whose index range is [0 - ${
|
|
195
201
|
this.tabNodes.length - 1
|
|
196
|
-
}])
|
|
197
|
-
|
|
202
|
+
}])`;
|
|
203
|
+
}
|
|
204
|
+
// https://api.emberjs.com/ember/5.3/classes/@ember%2Fdebug/methods/warn?anchor=warn
|
|
205
|
+
warn(message, true, {
|
|
206
|
+
id: 'hds-debug.tabs.setTabIndicator-tabElem-not-available',
|
|
207
|
+
});
|
|
198
208
|
}
|
|
199
209
|
});
|
|
200
210
|
}
|
|
@@ -75,14 +75,14 @@ $hds-dropdown-toggle-border-radius: $hds-button-border-radius;
|
|
|
75
75
|
|
|
76
76
|
.hds-dropdown-toggle-icon--size-small {
|
|
77
77
|
.hds-dropdown-toggle-icon__wrapper {
|
|
78
|
-
width:
|
|
79
|
-
height:
|
|
78
|
+
width: 24px; // same as the `button[small]` minus 2*2px becaus there are a 1px padding and 1px border to take into account
|
|
79
|
+
height: 24px;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.hds-dropdown-toggle-icon--size-medium {
|
|
84
84
|
.hds-dropdown-toggle-icon__wrapper {
|
|
85
|
-
width: 32px;
|
|
85
|
+
width: 32px; // same as the `button[medium]` minus 2*2px becaus there are a 1px padding and 1px border to take into account
|
|
86
86
|
height: 32px;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -14,21 +14,24 @@ $size-props: (
|
|
|
14
14
|
"font-size": 0.8125rem, // 13px;
|
|
15
15
|
"line-height": 0.875rem, // 14px - we need to make it even (so we set it slighly larger than the font-size; notice: in Figma is 12px but this would cut some ascendants/descendants)
|
|
16
16
|
"min-height": 1.75rem, // 28px
|
|
17
|
-
"padding": 0.375rem
|
|
17
|
+
"padding-vertical": 0.375rem, // 6px - here we're taking into account the 1px border
|
|
18
|
+
"padding-horizontal": 0.6875rem, // 11px - here we're taking into account the 1px border
|
|
18
19
|
"icon-size": 0.75rem, // 12px
|
|
19
20
|
),
|
|
20
21
|
"medium": (
|
|
21
22
|
"font-size": 0.875rem, // 14px
|
|
22
23
|
"line-height": 1rem,// 16px
|
|
23
24
|
"min-height": 2.25rem, // 36px
|
|
24
|
-
"padding": 0.5625rem
|
|
25
|
+
"padding-vertical": 0.5625rem, // 9px - here we're taking into account the 1px border
|
|
26
|
+
"padding-horizontal": 0.9375rem, // 15px - here we're taking into account the 1px border
|
|
25
27
|
"icon-size": 1rem, // 16px
|
|
26
28
|
),
|
|
27
29
|
"large": (
|
|
28
30
|
"font-size": 1rem, // 16px
|
|
29
31
|
"line-height": 1.5rem, // 24px
|
|
30
32
|
"min-height": 3rem, // 48px
|
|
31
|
-
"padding": 0.6875rem
|
|
33
|
+
"padding-vertical": 0.6875rem, // 11px - here we're taking into account the 1px border
|
|
34
|
+
"padding-horizontal": 1.1875rem, // 19px - here we're taking into account the 1px border
|
|
32
35
|
"icon-size": 1.5rem, // 24px
|
|
33
36
|
)
|
|
34
37
|
);
|
|
@@ -271,7 +274,7 @@ $size-props: (
|
|
|
271
274
|
@each $size in $hds-button-sizes {
|
|
272
275
|
.#{$blockName}--size-#{$size} {
|
|
273
276
|
min-height: map-get($size-props, $size, "min-height");
|
|
274
|
-
padding: map-get($size-props, $size, "padding");
|
|
277
|
+
padding: map-get($size-props, $size, "padding-vertical") map-get($size-props, $size, "padding-horizontal");
|
|
275
278
|
|
|
276
279
|
.#{$blockName}__icon {
|
|
277
280
|
width: map-get($size-props, $size, "icon-size");
|
|
@@ -282,6 +285,13 @@ $size-props: (
|
|
|
282
285
|
font-size: map-get($size-props, $size, "font-size");
|
|
283
286
|
line-height: map-get($size-props, $size, "line-height");
|
|
284
287
|
}
|
|
288
|
+
|
|
289
|
+
&.#{$blockName}--is-icon-only {
|
|
290
|
+
// overrides to have the icon-only button squared
|
|
291
|
+
min-width: map-get($size-props, $size, "min-height");
|
|
292
|
+
padding-right: map-get($size-props, $size, "padding-vertical");
|
|
293
|
+
padding-left: map-get($size-props, $size, "padding-vertical");
|
|
294
|
+
}
|
|
285
295
|
}
|
|
286
296
|
}
|
|
287
297
|
}
|