@hashicorp/design-system-components 1.3.2 → 1.4.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +3 -2
  3. package/addon/components/hds/alert/index.hbs +1 -3
  4. package/addon/components/hds/dismiss-button/index.hbs +3 -0
  5. package/addon/components/hds/form/radio-card/group.hbs +1 -0
  6. package/addon/components/hds/form/radio-card/index.js +33 -0
  7. package/addon/components/hds/modal/body.hbs +3 -0
  8. package/addon/components/hds/modal/footer.hbs +3 -0
  9. package/addon/components/hds/modal/header.hbs +14 -0
  10. package/addon/components/hds/modal/index.hbs +15 -0
  11. package/addon/components/hds/modal/index.js +144 -0
  12. package/addon/components/hds/table/index.hbs +54 -0
  13. package/addon/components/hds/table/index.js +121 -0
  14. package/addon/components/hds/table/td.hbs +3 -0
  15. package/addon/components/hds/table/th-sort.hbs +8 -0
  16. package/addon/components/hds/table/th-sort.js +44 -0
  17. package/addon/components/hds/table/th.hbs +3 -0
  18. package/addon/components/hds/table/tr.hbs +3 -0
  19. package/addon/components/hds/tabs/tab.hbs +1 -1
  20. package/app/components/hds/dismiss-button/index.js +1 -0
  21. package/app/components/hds/modal/body.js +1 -0
  22. package/app/components/hds/modal/footer.js +1 -0
  23. package/app/components/hds/modal/header.js +1 -0
  24. package/app/components/hds/modal/index.js +1 -0
  25. package/app/components/hds/table/index.js +1 -0
  26. package/app/components/hds/table/td.js +1 -0
  27. package/app/components/hds/table/th-sort.js +1 -0
  28. package/app/components/hds/table/th.js +1 -0
  29. package/app/components/hds/table/tr.js +1 -0
  30. package/app/styles/@hashicorp/design-system-components.scss +3 -0
  31. package/app/styles/components/alert.scss +0 -27
  32. package/app/styles/components/dismiss-button.scss +34 -0
  33. package/app/styles/components/form/checkbox.scss +22 -5
  34. package/app/styles/components/form/radio-card.scss +10 -1
  35. package/app/styles/components/modal.scss +134 -0
  36. package/app/styles/components/table.scss +166 -0
  37. package/index.js +11 -0
  38. package/package.json +7 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @hashicorp/design-system-components
2
2
 
3
+ ## 1.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#740](https://github.com/hashicorp/design-system/pull/740) [`cd1a09307`](https://github.com/hashicorp/design-system/commit/cd1a09307aef9617e7a31a5d9e722417f4c9045e) Thanks [@alex-ju](https://github.com/alex-ju)! - Add `indeterminate` style to `Checkbox` component
8
+
9
+ - Updated dependencies [[`92c83961f`](https://github.com/hashicorp/design-system/commit/92c83961f0e8b01e52e3c596c85871ec5cf8c94d)]:
10
+ - @hashicorp/design-system-tokens@1.3.0
11
+
12
+ ## 1.4.0
13
+
14
+ ### Minor Changes
15
+
16
+ - [#631](https://github.com/hashicorp/design-system/pull/631) [`5d4b1811`](https://github.com/hashicorp/design-system/commit/5d4b1811a4bcdfe0c2205767aceead9286f5f159) Thanks [@alex-ju](https://github.com/alex-ju)! - Add `Modal` component and `DismissButton` utility component (used by `Alert`, `Toast` and `Modal`)
17
+
18
+ * [#722](https://github.com/hashicorp/design-system/pull/722) [`58a52103`](https://github.com/hashicorp/design-system/commit/58a521034b0e6a2a421b4c8b79f26a431e13a83b) Thanks [@MelSumner](https://github.com/MelSumner)! - Add `Table` component
19
+
20
+ ### Patch Changes
21
+
22
+ - [#681](https://github.com/hashicorp/design-system/pull/681) [`6f08ddd2`](https://github.com/hashicorp/design-system/commit/6f08ddd2b491ed13b60e153aa4cc13db8c3884da) Thanks [@KristinLBradley](https://github.com/KristinLBradley)! - Explicitly set `aria-selected` to `true` or `false`
23
+
24
+ * [#698](https://github.com/hashicorp/design-system/pull/698) [`db8a1caf`](https://github.com/hashicorp/design-system/commit/db8a1caff4553ed3240c0260a831526fd2fe6844) Thanks [@alex-ju](https://github.com/alex-ju)! - Add `@layout` parameter to `RadioCard`
25
+
26
+ * Updated dependencies [[`aeff4e02`](https://github.com/hashicorp/design-system/commit/aeff4e02e3c5c738104be326569c110dc2f79618)]:
27
+ - @hashicorp/ember-flight-icons@3.0.2
28
+
3
29
  ## 1.3.2
4
30
 
5
31
  ### Patch Changes
package/README.md CHANGED
@@ -9,8 +9,9 @@ A package containing the components for the HashiCorp Design System.
9
9
  Compatibility
10
10
  ------------------------------------------------------------------------------
11
11
 
12
- * Ember.js v3.24 or above
13
- * Ember CLI v3.24 or above
12
+ * Ember.js v3.28 or above
13
+ * Note: The library _should_ work with earlier versions of Ember, but we only test with Ember 3.28 and newer
14
+ * Ember CLI v3.28 or above
14
15
  * Node.js v12 or above
15
16
 
16
17
 
@@ -29,8 +29,6 @@
29
29
  </div>
30
30
 
31
31
  {{#if this.onDismiss}}
32
- <button class="hds-alert__dismiss" type="button" aria-label="Dismiss" {{on "click" this.onDismiss}}>
33
- <FlightIcon @name="x" @size="16" @isInlineBlock={{false}} />
34
- </button>
32
+ <Hds::DismissButton class="hds-alert__dismiss" {{on "click" this.onDismiss}} />
35
33
  {{/if}}
36
34
  </div>
@@ -0,0 +1,3 @@
1
+ <button class="hds-dismiss-button" type="button" aria-label="Dismiss" ...attributes>
2
+ <FlightIcon @name="x" @size="16" @isInlineBlock={{false}} />
3
+ </button>
@@ -18,6 +18,7 @@
18
18
  name=@name
19
19
  alignment=@alignment
20
20
  controlPosition=@controlPosition
21
+ layout=@layout
21
22
  extraAriaDescribedBy=F.ariaDescribedBy
22
23
  )
23
24
  )
@@ -7,8 +7,10 @@ import { schedule } from '@ember/runloop';
7
7
 
8
8
  export const DEFAULT_CONTROL_POSITION = 'bottom';
9
9
  export const DEFAULT_ALIGNMENT = 'left';
10
+ export const DEFAULT_LAYOUT = 'fluid';
10
11
  export const CONTROL_POSITIONS = ['bottom', 'left'];
11
12
  export const ALIGNMENTS = ['left', 'center'];
13
+ export const LAYOUTS = ['fluid', 'fixed'];
12
14
 
13
15
  export default class HdsFormRadioCardIndexComponent extends Component {
14
16
  @tracked ariaDescribedBy = this.args.extraAriaDescribedBy;
@@ -64,6 +66,34 @@ export default class HdsFormRadioCardIndexComponent extends Component {
64
66
  return alignment;
65
67
  }
66
68
 
69
+ /**
70
+ * Sets the layout of the card within the group
71
+ * Accepted values: fluid, fixed
72
+ *
73
+ * @param layout
74
+ * @type {string}
75
+ * @default 'fluid'
76
+ */
77
+ get layout() {
78
+ let { layout = DEFAULT_LAYOUT } = this.args;
79
+
80
+ assert(
81
+ `@layout for "Hds::Form::RadioCard" must be one of the following: ${LAYOUTS.join(
82
+ ', '
83
+ )}; received: ${layout}`,
84
+ LAYOUTS.includes(layout)
85
+ );
86
+
87
+ // if the `@layout` is set to 'fixed' we need a `@maxWidth` value to constrain the card to
88
+ if (layout === 'fixed') {
89
+ assert(
90
+ `@maxWidth for "Hds::Form::RadioCard" with @layout "fixed" is required`,
91
+ this.args.maxWidth
92
+ );
93
+ }
94
+ return layout;
95
+ }
96
+
67
97
  /**
68
98
  * Get the class names to apply to the component.
69
99
  * @method classNames
@@ -85,6 +115,9 @@ export default class HdsFormRadioCardIndexComponent extends Component {
85
115
  // add a class based on the @alignment argument
86
116
  classes.push(`hds-form-radio-card--align-${this.alignment}`);
87
117
 
118
+ // add a class based on the @layout argument
119
+ classes.push(`hds-form-radio-card--layout-${this.layout}`);
120
+
88
121
  return classes.join(' ');
89
122
  }
90
123
  }
@@ -0,0 +1,3 @@
1
+ <div class="hds-modal__body" ...attributes>
2
+ {{yield}}
3
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="hds-modal__footer" ...attributes>
2
+ {{yield (hash close=@onDismiss)}}
3
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="hds-modal__header" ...attributes>
2
+ {{#if @icon}}
3
+ <FlightIcon class="hds-modal__icon" @name={{@icon}} @size="24" @isInlineBlock={{false}} />
4
+ {{/if}}
5
+ <div class="hds-modal__title hds-typography-display-300 hds-font-weight-semibold" id={{@id}}>
6
+ {{#if @tagline}}
7
+ <div class="hds-modal__tagline hds-typography-body-100 hds-font-weight-regular">
8
+ {{@tagline}}
9
+ </div>
10
+ {{/if}}
11
+ {{yield}}
12
+ </div>
13
+ <Hds::DismissButton class="hds-modal__dismiss" {{on "click" @onDismiss}} />
14
+ </div>
@@ -0,0 +1,15 @@
1
+ {{! template-lint-disable no-invalid-interactive }}
2
+ <dialog
3
+ class={{this.classNames}}
4
+ ...attributes
5
+ aria-labelledby={{this.id}}
6
+ {{did-insert this.didInsert}}
7
+ {{focus-trap isActive=this.isOpen focusTrapOptions=(hash onDeactivate=this.onDismiss clickOutsideDeactivates=true)}}
8
+ >
9
+ {{yield (hash Header=(component "hds/modal/header" id=this.id onDismiss=this.onDismiss))}}
10
+ {{yield (hash Body=(component "hds/modal/body"))}}
11
+ {{yield (hash Footer=(component "hds/modal/footer" onDismiss=this.onDismiss))}}
12
+ </dialog>
13
+ {{#if this.isOpen}}
14
+ <div class="hds-modal__overlay"></div>
15
+ {{/if}}
@@ -0,0 +1,144 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+ import { assert } from '@ember/debug';
4
+ import { getElementId } from '../form/utils/getElementId';
5
+ import { tracked } from '@glimmer/tracking';
6
+
7
+ export const DEFAULT_SIZE = 'medium';
8
+ export const DEFAULT_COLOR = 'neutral';
9
+ export const SIZES = ['small', 'medium', 'large'];
10
+ export const COLORS = ['neutral', 'warning', 'critical'];
11
+
12
+ export default class HdsModalIndexComponent extends Component {
13
+ @tracked isOpen = false;
14
+ @tracked isDismissDisabled = this.args.isDismissDisabled ?? false;
15
+
16
+ /**
17
+ * Sets the size of the modal dialog
18
+ * Accepted values: small, medium, large
19
+ *
20
+ * @param size
21
+ * @type {string}
22
+ * @default 'medium'
23
+ */
24
+ get size() {
25
+ let { size = DEFAULT_SIZE } = this.args;
26
+
27
+ assert(
28
+ `@size for "Hds::Modal" must be one of the following: ${SIZES.join(
29
+ ', '
30
+ )}; received: ${size}`,
31
+ SIZES.includes(size)
32
+ );
33
+
34
+ return size;
35
+ }
36
+
37
+ /**
38
+ * Sets the color of the modal dialog
39
+ * Accepted values: neutral, warning, critical
40
+ *
41
+ * @param color
42
+ * @type {string}
43
+ * @default 'neutral'
44
+ */
45
+ get color() {
46
+ let { color = DEFAULT_COLOR } = this.args;
47
+
48
+ assert(
49
+ `@color for "Hds::Modal" must be one of the following: ${COLORS.join(
50
+ ', '
51
+ )}; received: ${color}`,
52
+ COLORS.includes(color)
53
+ );
54
+
55
+ return color;
56
+ }
57
+
58
+ /**
59
+ * Calculates the unique ID to assign to the title
60
+ */
61
+ get id() {
62
+ return getElementId(this);
63
+ }
64
+
65
+ /**
66
+ * Get the class names to apply to the component.
67
+ * @method classNames
68
+ * @return {string} The "class" attribute to apply to the component.
69
+ */
70
+ get classNames() {
71
+ let classes = ['hds-modal'];
72
+
73
+ // add a class based on the @size argument
74
+ classes.push(`hds-modal--size-${this.size}`);
75
+
76
+ // add a class based on the @color argument
77
+ classes.push(`hds-modal--color-${this.color}`);
78
+
79
+ return classes.join(' ');
80
+ }
81
+
82
+ @action
83
+ didInsert(element) {
84
+ // Store a reference of the `<dialog>` element
85
+ this.element = element;
86
+
87
+ // Register `<dialog>` element for polyfilling if no native support is available
88
+ if (!element.showModal) {
89
+ Promise.all([import('dialog-polyfill'), import('dialog-polyfill-css')])
90
+ .then(([dialogPolyfill]) => {
91
+ const dialog = dialogPolyfill.default;
92
+ if (dialog.registerDialog) {
93
+ dialog.registerDialog(element);
94
+ // This unscoped class is defined in the dialog polyfill: https://github.com/GoogleChrome/dialog-polyfill/blob/master/dist/dialog-polyfill.css#L33
95
+ element.classList.add('fixed');
96
+ }
97
+ })
98
+ .catch({});
99
+ }
100
+
101
+ // Register "onClose" callback function to be called when a native 'close' event is dispatched
102
+ this.element.addEventListener('close', () => {
103
+ if (this.args.onClose && typeof this.args.onClose === 'function') {
104
+ this.args.onClose();
105
+ }
106
+
107
+ // If the dismissal of the modal is disabled, we keep the modal open/visible otherwise we mark it as closed
108
+ if (this.isDismissDisabled) {
109
+ // If, in a chain of events, the element is not attached to the DOM, the `showModal` would fail
110
+ // so we add this safeguard condition that checks for the `<dialog>` to have a parent
111
+ if (this.element.parentElement) {
112
+ // As there is no way to `preventDefault` on `close` events, we call the `showModal` function
113
+ // preserving the state of the modal dialog
114
+ this.element.showModal();
115
+ }
116
+ } else {
117
+ this.isOpen = false;
118
+ }
119
+ });
120
+
121
+ // If the modal dialog is not already open
122
+ if (!this.element.open) {
123
+ this.open();
124
+ }
125
+ }
126
+
127
+ @action
128
+ open() {
129
+ // Make modal dialog visible using the native `showModal` method
130
+ this.element.showModal();
131
+ this.isOpen = true;
132
+
133
+ // Call "onOpen" callback function
134
+ if (this.args.onOpen && typeof this.args.onOpen === 'function') {
135
+ this.args.onOpen();
136
+ }
137
+ }
138
+
139
+ @action
140
+ onDismiss() {
141
+ // Make modal dialog invisible using the native `close` method
142
+ this.element.close();
143
+ }
144
+ }
@@ -0,0 +1,54 @@
1
+ <table class={{this.classNames}} ...attributes>
2
+ {{#if @columns}}
3
+ <caption class="sr-only" aria-live="polite">{{@caption}} {{this.sortedMessageText}}</caption>
4
+ {{else if @caption}}
5
+ <caption class="sr-only">{{@caption}}</caption>
6
+ {{/if}}
7
+ <thead class="hds-table__thead">
8
+ {{#if @columns}}
9
+ <Hds::Table::Tr>
10
+ {{#each @columns as |column|}}
11
+ {{#if @sortingKeys}}
12
+ {{#if (includes column.key @sortingKeys)}}
13
+ <Hds::Table::ThSort
14
+ @isSorted={{eq column.key this.sortBy}}
15
+ @sortOrder={{this.sortOrder}}
16
+ @onClick={{(fn this.setSortBy column.key)}}
17
+ >
18
+ {{column.label}}
19
+ </Hds::Table::ThSort>
20
+ {{else}}
21
+ <Hds::Table::Th>{{column.label}}</Hds::Table::Th>
22
+ {{/if}}
23
+ {{else}}
24
+ <Hds::Table::ThSort
25
+ @isSorted={{eq column.key this.sortBy}}
26
+ @sortOrder={{this.sortOrder}}
27
+ @onClick={{(fn this.setSortBy column.key)}}
28
+ >
29
+ {{column.label}}
30
+ </Hds::Table::ThSort>
31
+ {{/if}}
32
+ {{/each}}
33
+ </Hds::Table::Tr>
34
+ {{else}}
35
+ {{yield
36
+ (hash Tr=(component "hds/table/tr") Th=(component "hds/table/th") ThSort=(component "hds/table/th-sort"))
37
+ to="head"
38
+ }}
39
+ {{/if}}
40
+ </thead>
41
+ <tbody class="hds-table__tbody">
42
+ {{#if @columns}}
43
+ {{#each (sort-by this.getSortCriteria @model) as |data|}}
44
+ {{yield (hash Tr=(component "hds/table/tr") Td=(component "hds/table/td") data=data) to="body"}}
45
+ {{/each}}
46
+ {{else if @model}}
47
+ {{#each @model as |data|}}
48
+ {{yield (hash Tr=(component "hds/table/tr") Td=(component "hds/table/td") data=data) to="body"}}
49
+ {{/each}}
50
+ {{else}}
51
+ {{yield (hash Tr=(component "hds/table/tr") Td=(component "hds/table/td")) to="body"}}
52
+ {{/if}}
53
+ </tbody>
54
+ </table>
@@ -0,0 +1,121 @@
1
+ import Component from '@glimmer/component';
2
+ import { action } from '@ember/object';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { assert } from '@ember/debug';
5
+
6
+ const DENSITIES = ['short', 'medium', 'tall'];
7
+ const DEFAULT_DENSITY = 'medium';
8
+ const VALIGNMENTS = ['top', 'middle'];
9
+ const DEFAULT_VALIGN = 'top';
10
+
11
+ export default class HdsTableIndexComponent extends Component {
12
+ @tracked sortBy = this.args.sortBy;
13
+ @tracked sortOrder = this.args.sortOrder || 'asc';
14
+ @tracked sortedMessageText = '';
15
+
16
+ get getSortCriteria() {
17
+ return `${this.sortBy}:${this.sortOrder}`;
18
+ }
19
+
20
+ /**
21
+ * @param isStriped
22
+ * @type {boolean}
23
+ * @default false
24
+ * @description Determines whether the table rows should have alternating background colors; defaults to false.
25
+ */
26
+ get isStriped() {
27
+ return this.args.isStriped ?? false;
28
+ }
29
+
30
+ /**
31
+ * @param isFixedLayout
32
+ * @type {boolean}
33
+ * @default false
34
+ * @description Determines whether the table-display should be set to fixed; meaning, the table columns are of equal width no matter the content; defaults to false.
35
+ */
36
+ get isFixedLayout() {
37
+ return this.args.isFixedLayout ?? false;
38
+ }
39
+
40
+ /**
41
+ * @param density
42
+ * @type {string}
43
+ * @default 'medium'
44
+ * @description Determines the density of the table cells; options are "short", "medium" and "tall". If no density is defined, "medium" is used.
45
+ */
46
+ get density() {
47
+ let { density = DEFAULT_DENSITY } = this.args;
48
+
49
+ assert(
50
+ `@density for "Hds::Table" must be one of the following: ${DENSITIES.join(
51
+ ', '
52
+ )}; received: ${density}`,
53
+ DENSITIES.includes(density)
54
+ );
55
+
56
+ return density;
57
+ }
58
+
59
+ /**
60
+ * @param valign
61
+ * @type {string}
62
+ * @default 'top'
63
+ * @description Determines the vertical alignment of the table cells; options are: "top", "middle". If no valign is defined, "top" is used.
64
+ */
65
+ get valign() {
66
+ let { valign = DEFAULT_VALIGN } = this.args;
67
+
68
+ assert(
69
+ `@valign for "Hds::Table" must be one of the following: ${VALIGNMENTS.join(
70
+ ', '
71
+ )}; received: ${valign}`,
72
+ VALIGNMENTS.includes(valign)
73
+ );
74
+
75
+ return valign;
76
+ }
77
+
78
+ /**
79
+ * Get the class names to apply to the component.
80
+ * @method classNames
81
+ * @return {string} The "class" attribute to apply to the component.
82
+ */
83
+ get classNames() {
84
+ let classes = ['hds-table'];
85
+
86
+ // add a class based on the @isStriped argument
87
+ if (this.isStriped) {
88
+ classes.push('hds-table--striped');
89
+ }
90
+
91
+ // add a class based on the @isFixedLayout argument
92
+ if (this.isFixedLayout) {
93
+ classes.push('hds-table--layout-fixed');
94
+ }
95
+
96
+ // add a class based on the @density argument
97
+ if (this.density) {
98
+ classes.push(`hds-table--density-${this.density}`);
99
+ }
100
+
101
+ // add a class based on the @valign argument
102
+ if (this.valign) {
103
+ classes.push(`hds-table--valign-${this.valign}`);
104
+ }
105
+
106
+ return classes.join(' ');
107
+ }
108
+
109
+ @action
110
+ setSortBy(column) {
111
+ if (this.sortBy === column) {
112
+ //invert the sort order
113
+ this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
114
+ } else {
115
+ this.sortBy = column;
116
+ this.sortOrder = 'asc';
117
+ }
118
+ // we should allow the user to define a custom value here (e.g., for i18n) - tracked with HDS-965
119
+ this.sortedMessageText = `Sorted by ${this.sortBy} ${this.sortOrder}ending`;
120
+ }
121
+ }
@@ -0,0 +1,3 @@
1
+ <td class="hds-table__td hds-typography-body-200 hds-font-weight-regular" ...attributes>
2
+ {{yield}}
3
+ </td>
@@ -0,0 +1,8 @@
1
+ <th scope="col" class="hds-table__th-sort" aria-sort={{this.ariaSort}} ...attributes>
2
+ <button type="button" {{on "click" this.onClick}}>
3
+ <div class="hds-table__th-sort--button-content">
4
+ <span class="hds-typography-body-200 hds-font-weight-semibold">{{yield}}</span>
5
+ <FlightIcon @name={{this.icon}} />
6
+ </div>
7
+ </button>
8
+ </th>
@@ -0,0 +1,44 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ const NOOP = () => {};
4
+
5
+ export default class HdsTableThSortComponent extends Component {
6
+ /**
7
+ * @param ariaSort
8
+ * @type {string}
9
+ * @private
10
+ * @description Sets the aria-sort attribute based on the sort order defined
11
+ */
12
+ get ariaSort() {
13
+ if (this.args.isSorted) {
14
+ return this.args.sortOrder === 'asc' ? 'ascending' : 'descending';
15
+ } else {
16
+ return undefined;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * @param icon
22
+ * @type {string}
23
+ * @private
24
+ * @default swap-vertical
25
+ * @description Determines which icon to use based on the sort order defined
26
+ */
27
+ get icon() {
28
+ if (this.args.isSorted && this.args.sortOrder) {
29
+ return this.args.sortOrder === 'asc' ? 'arrow-up' : 'arrow-down';
30
+ } else {
31
+ return 'swap-vertical';
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @param onClick
37
+ * @type {function}
38
+ * @default () => {}
39
+ */
40
+ get onClick() {
41
+ let { onClick } = this.args;
42
+ return onClick || NOOP;
43
+ }
44
+ }
@@ -0,0 +1,3 @@
1
+ <th class="hds-table__th hds-typography-body-200 hds-font-weight-semibold" ...attributes scope="col">
2
+ {{yield}}
3
+ </th>
@@ -0,0 +1,3 @@
1
+ <tr class="hds-table__tr" ...attributes>
2
+ {{yield}}
3
+ </tr>
@@ -9,7 +9,7 @@
9
9
  role="tab"
10
10
  type="button"
11
11
  id={{this.tabId}}
12
- aria-selected={{this.isSelected}}
12
+ aria-selected={{if this.isSelected "true" "false"}}
13
13
  tabindex={{unless this.isSelected "-1"}}
14
14
  data-is-selected={{this.isInitialTab}}
15
15
  {{did-insert this.didInsertNode}}
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/dismiss-button/index';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/modal/body';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/modal/footer';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/modal/header';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/modal/index';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/table/index';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/table/td';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/table/th-sort';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/table/th';
@@ -0,0 +1 @@
1
+ export { default } from '@hashicorp/design-system-components/components/hds/table/tr';
@@ -16,13 +16,16 @@
16
16
  @use "../components/button-set";
17
17
  @use "../components/card";
18
18
  @use "../components/disclosure";
19
+ @use "../components/dismiss-button";
19
20
  @use "../components/dropdown";
20
21
  @use "../components/empty-state";
21
22
  @use "../components/form"; // multiple components
22
23
  @use "../components/icon-tile";
23
24
  @use "../components/link"; // multiple components
25
+ @use "../components/modal";
24
26
  @use "../components/stepper";
25
27
  @use "../components/tabs";
28
+ @use "../components/table";
26
29
  @use "../components/tag";
27
30
  @use "../components/toast";
28
31
  // END COMPONENT CSS FILES IMPORTS
@@ -2,8 +2,6 @@
2
2
  // ALERT COMPONENT
3
3
  //
4
4
 
5
- @use "../mixins/focus-ring" as *;
6
-
7
5
  .hds-alert {
8
6
  display: flex;
9
7
  align-items: flex-start;
@@ -117,39 +115,14 @@
117
115
  // DISMISS
118
116
 
119
117
  .hds-alert__dismiss {
120
- flex: none;
121
118
  margin-top: 2px; // for alignment with the main icon and text
122
119
  margin-left: 16px;
123
- padding: 0;
124
- color: var(--token-color-foreground-faint);
125
- background-color: transparent;
126
- border: none;
127
- cursor: pointer;
128
120
 
129
121
  .hds-alert--type-compact & {
130
122
  margin-top: 1px;
131
123
  }
132
-
133
- &:hover {
134
- &::before { // we re-use the pseudo-element created by the "focus-ring" mixin
135
- background-color: rgba(#dedfe3, 0.4);
136
- }
137
- }
138
-
139
- // notice: this is used not only for the focus, but also to increase the clickable area
140
- @include hds-focus-ring-with-pseudo-element($top: -4px, $right: -4px, $bottom: -4px, $left: -4px);
141
-
142
- &:active {
143
- color: var(--token-color-foreground-secondary);
144
-
145
- &::before {
146
- background-color: rgba(#dedfe3, 0.4);
147
- border: 1px solid var(--token-color-border-strong);
148
- }
149
- }
150
124
  }
151
125
 
152
-
153
126
  // TYPES
154
127
 
155
128
  .hds-alert--type-page {
@@ -0,0 +1,34 @@
1
+ //
2
+ // DISMISS-BUTTON
3
+ //
4
+
5
+ @use "../mixins/focus-ring" as *;
6
+
7
+ .hds-dismiss-button {
8
+ flex: none;
9
+ padding: 0;
10
+ color: var(--token-color-foreground-faint);
11
+ background-color: transparent;
12
+ border: none;
13
+ cursor: pointer;
14
+
15
+ &:hover,
16
+ &.mock-hover {
17
+ &::before { // we re-use the pseudo-element created by the "focus-ring" mixin
18
+ background-color: rgba(#dedfe3, 0.4);
19
+ }
20
+ }
21
+
22
+ // notice: this is used not only for the focus, but also to increase the clickable area
23
+ @include hds-focus-ring-with-pseudo-element($top: -4px, $right: -4px, $bottom: -4px, $left: -4px);
24
+
25
+ &:active,
26
+ &.mock-active {
27
+ color: var(--token-color-foreground-secondary);
28
+
29
+ &::before {
30
+ background-color: rgba(#dedfe3, 0.4);
31
+ border: 1px solid var(--token-color-border-strong);
32
+ }
33
+ }
34
+ }
@@ -22,7 +22,7 @@
22
22
 
23
23
  // base (default)
24
24
 
25
- &:not(:checked) {
25
+ &:not(:checked, :indeterminate) {
26
26
  background-color: var(--token-form-control-base-surface-color-default);
27
27
  border-color: var(--token-form-control-base-border-color-default);
28
28
  box-shadow: var(--hds-elevation-inset-box-shadow);
@@ -34,16 +34,24 @@
34
34
  border-color: var(--token-form-control-checked-border-color-default);
35
35
  }
36
36
 
37
+ &:indeterminate {
38
+ background-color: var(--token-form-control-checked-surface-color-default);
39
+ background-image: var(--token-form-checkbox-background-image-data-url-indeterminate);
40
+ border-color: var(--token-form-control-checked-border-color-default);
41
+ }
42
+
37
43
  // hover
38
44
 
39
- &:hover:not(:checked),
40
- &.mock-hover:not(:checked) {
45
+ &:hover:not(:checked, :indeterminate),
46
+ &.mock-hover:not(:checked, :indeterminate) {
41
47
  background-color: var(--token-form-control-base-surface-color-hover);
42
48
  border-color: var(--token-form-control-base-border-color-hover);
43
49
  }
44
50
 
45
51
  &:hover:checked,
46
- &.mock-hover:checked {
52
+ &.mock-hover:checked,
53
+ &:hover:indeterminate,
54
+ &.mock-hover:indeterminate {
47
55
  background-color: var(--token-form-control-checked-border-color-default);
48
56
  border-color: var(--token-form-control-checked-border-color-hover);
49
57
  }
@@ -58,7 +66,7 @@
58
66
 
59
67
  // DISABLED
60
68
 
61
- &:disabled:not(:checked) {
69
+ &:disabled:not(:checked, :indeterminate) {
62
70
  background-color: var(--token-form-control-disabled-surface-color);
63
71
  border-color: var(--token-form-control-disabled-border-color);
64
72
  box-shadow: none;
@@ -72,4 +80,13 @@
72
80
  box-shadow: none;
73
81
  cursor: not-allowed;
74
82
  }
83
+
84
+ &:disabled:indeterminate {
85
+ background-color: var(--token-form-control-disabled-surface-color);
86
+ background-image: var(--token-form-checkbox-background-image-data-url-indeterminate-disabled);
87
+ background-repeat: no-repeat;
88
+ border-color: var(--token-form-control-disabled-border-color);
89
+ box-shadow: none;
90
+ cursor: not-allowed;
91
+ }
75
92
  }
@@ -15,9 +15,18 @@
15
15
  }
16
16
 
17
17
  .hds-form-radio-card {
18
- flex: 1;
19
18
  margin: calc(var(--token-form-radiocard-group-gap) / 2);
20
19
  }
20
+
21
+ // LAYOUT
22
+
23
+ .hds-form-radio-card--layout-fluid {
24
+ flex: 1 0 0;
25
+ }
26
+
27
+ .hds-form-radio-card--layout-fixed {
28
+ flex: 1 0 100%;
29
+ }
21
30
  }
22
31
 
23
32
  // RadioCard
@@ -0,0 +1,134 @@
1
+ //
2
+ // MODAL
3
+ //
4
+
5
+ .hds-modal {
6
+ z-index: 50;
7
+ flex-direction: column;
8
+ padding: 0;
9
+ background: var(--token-color-surface-primary);
10
+ border: none;
11
+ border-radius: 10px;
12
+ box-shadow: var(--token-surface-overlay-box-shadow);
13
+
14
+ &[open] {
15
+ position: fixed;
16
+ display: flex;
17
+ }
18
+
19
+ // we hide the native `::backdrop` pseudo-element in favor of using
20
+ // an `hds-modal__overlay` element to detect click events with more ease
21
+ &::backdrop {
22
+ display: none;
23
+ }
24
+ }
25
+
26
+ .hds-modal__overlay {
27
+ position: fixed;
28
+ top: 0;
29
+ right: 0;
30
+ bottom: 0;
31
+ left: 0;
32
+ z-index: 50;
33
+ background: var(--token-color-palette-neutral-700);
34
+ opacity: 0.5;
35
+ }
36
+
37
+ .hds-modal__header {
38
+ display: flex;
39
+ flex: none;
40
+ align-items: flex-start;
41
+ padding: 16px 24px;
42
+ border-top-left-radius: inherit;
43
+ border-top-right-radius: inherit;
44
+ }
45
+
46
+ .hds-modal__icon {
47
+ flex: none;
48
+ align-self: center;
49
+ margin-right: 16px;
50
+ }
51
+
52
+ .hds-modal__title {
53
+ flex-grow: 1;
54
+ }
55
+
56
+ .hds-modal__tagline {
57
+ margin-bottom: 4px;
58
+ }
59
+
60
+ .hds-modal__dismiss {
61
+ align-self: center;
62
+ margin-left: 16px;
63
+ }
64
+
65
+ .hds-modal__body {
66
+ flex: 1 1 auto;
67
+ padding: 24px;
68
+ overflow-y: auto;
69
+ overscroll-behavior: contain;
70
+ }
71
+
72
+ .hds-modal__footer {
73
+ flex: none;
74
+ padding: 16px 24px;
75
+ background: var(--token-color-surface-faint);
76
+ border-top: 1px solid var(--token-color-border-primary);
77
+ border-bottom-right-radius: inherit;
78
+ border-bottom-left-radius: inherit;
79
+
80
+ // Tertiary buttons must always be placed/aligned at the end of the row
81
+ .hds-button-set {
82
+ .hds-button--color-tertiary {
83
+ margin-left: auto;
84
+ }
85
+ }
86
+ }
87
+
88
+ .hds-modal--size-small {
89
+ width: min(400px, 95vw);
90
+ }
91
+
92
+ .hds-modal--size-medium {
93
+ width: min(600px, 95vw);
94
+ }
95
+
96
+ .hds-modal--size-large {
97
+ width: min(800px, 95vw);
98
+ }
99
+
100
+ .hds-modal--color-neutral {
101
+ .hds-modal__header {
102
+ color: var(--token-color-foreground-strong);
103
+ background: var(--token-color-surface-faint);
104
+ border-bottom: 1px solid var(--token-color-border-primary);
105
+ }
106
+
107
+ .hds-modal__tagline {
108
+ color: var(--token-color-foreground-faint);
109
+ }
110
+ }
111
+
112
+ .hds-modal--color-warning {
113
+ .hds-modal__header {
114
+ color: var(--token-color-foreground-warning-on-surface);
115
+ background: var(--token-color-surface-warning);
116
+ border-bottom: 1px solid var(--token-color-border-warning);
117
+ }
118
+
119
+ .hds-modal__tagline {
120
+ color: var(--token-color-foreground-warning-on-surface);
121
+ }
122
+ }
123
+
124
+ .hds-modal--color-critical {
125
+ .hds-modal__header {
126
+ color: var(--token-color-foreground-critical-on-surface);
127
+ background: var(--token-color-surface-critical);
128
+ border-bottom: 1px solid var(--token-color-border-critical);
129
+ }
130
+
131
+ .hds-modal__tagline {
132
+ color: var(--token-color-foreground-critical-on-surface);
133
+ }
134
+ }
@@ -0,0 +1,166 @@
1
+ //
2
+ // TABLE
3
+ //
4
+ //
5
+
6
+ @use "../mixins/focus-ring" as *;
7
+
8
+ $hds-table-border-radius: 6px;
9
+ $hds-table-border-width: 1px;
10
+ $hds-table-inner-border-radius: $hds-table-border-radius - $hds-table-border-width;
11
+ $hds-table-border-color: var(--token-color-border-primary);
12
+ $hds-table-header-height: 48px;
13
+ $hds-table-cell-padding-medium: 12px 16px;
14
+ $hds-table-cell-padding-short: 4px 16px;
15
+ $hds-table-cell-padding-tall: 20px 16px;
16
+
17
+ .hds-table {
18
+ width: 100%;
19
+ border: $hds-table-border-width solid $hds-table-border-color;
20
+ border-radius: $hds-table-border-radius;
21
+ border-spacing: 0;
22
+ }
23
+
24
+ // TABLE DISPLAY
25
+ .hds-table--layout-fixed {
26
+ table-layout: fixed;
27
+ }
28
+
29
+ // TABLE HEADER
30
+ .hds-table__thead {
31
+ .hds-table__tr {
32
+ color: var(--token-color-foreground-strong);
33
+ background-color: var(--token-color-surface-strong);
34
+
35
+ .hds-table__th,
36
+ .hds-table__th-sort {
37
+ height: $hds-table-header-height;
38
+ text-align: left;
39
+ border-top: none;
40
+ border-right: none;
41
+ border-bottom: $hds-table-border-width solid $hds-table-border-color;
42
+ border-left: none;
43
+ }
44
+
45
+ .hds-table__th {
46
+ padding: $hds-table-cell-padding-medium;
47
+ }
48
+
49
+ .hds-table__th-sort {
50
+ padding: 0;
51
+
52
+ button {
53
+ width: 100%;
54
+ height: 100%;
55
+ min-height: $hds-table-header-height;
56
+ margin: 0;
57
+ padding: $hds-table-cell-padding-medium;
58
+ text-align: inherit;
59
+ background-color: transparent;
60
+ border: 1px solid transparent;
61
+ border-radius: inherit;
62
+
63
+ .hds-table__th-sort--button-content {
64
+ display: flex; // we can't put flex on the button itself so we drop the content into its own container
65
+ align-items: center;
66
+
67
+ .flight-icon {
68
+ flex: none;
69
+ margin-left: 8px;
70
+ color: var(--token-color-foreground-action);
71
+ }
72
+ }
73
+
74
+ &:hover,
75
+ &.mock-hover {
76
+ color: var(--token-color-foreground-strong);
77
+ background-color: var(--token-color-palette-neutral-200);
78
+ cursor: pointer;
79
+ }
80
+
81
+ @include hds-focus-ring-with-pseudo-element($radius: inherit);
82
+
83
+ &:active,
84
+ &.mock-active {
85
+ color: var(--token-color-foreground-strong);
86
+ background-color: var(--token-color-palette-neutral-300);
87
+ }
88
+ }
89
+ }
90
+
91
+ // BORDER RADIUS: TARGET FIRST AND LAST TH ELEMENTS IN THE ROW
92
+ &:first-of-type {
93
+ th:first-child {
94
+ border-top-left-radius: $hds-table-inner-border-radius;
95
+ }
96
+
97
+ // LAST TH IN THE ROW, BORDER RADIUS
98
+ th:last-child {
99
+ border-top-right-radius: $hds-table-inner-border-radius;
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ // TABLE BODY
106
+
107
+ // TABLE STRIPING ROWS
108
+ .hds-table--striped {
109
+ .hds-table__tbody {
110
+ .hds-table__tr:nth-child(even) {
111
+ background-color: var(--token-color-surface-faint);
112
+ }
113
+ }
114
+ }
115
+
116
+ // TABLE DENSITY (TBODY ROW HEIGHT)
117
+ .hds-table--density-short .hds-table__tbody td {
118
+ padding: $hds-table-cell-padding-short;
119
+ }
120
+
121
+ .hds-table--density-medium .hds-table__tbody td {
122
+ padding: $hds-table-cell-padding-medium;
123
+ }
124
+
125
+ .hds-table--density-tall .hds-table__tbody td {
126
+ padding: $hds-table-cell-padding-tall;
127
+ }
128
+
129
+ // TABLE CELL VERTICAL ALIGNMENT
130
+ .hds-table--valign-top .hds-table__tbody td {
131
+ vertical-align: top;
132
+ }
133
+
134
+ .hds-table--valign-middle .hds-table__tbody td {
135
+ vertical-align: middle;
136
+ }
137
+
138
+
139
+ .hds-table__tbody {
140
+ .hds-table__tr {
141
+ color: var(--token-color-foreground-primary);
142
+ background-color: var(--token-color-surface-primary);
143
+
144
+ td {
145
+ border-top: none;
146
+ border-right: none;
147
+ border-bottom: $hds-table-border-width solid $hds-table-border-color;
148
+ border-left: none;
149
+ }
150
+
151
+ // BORDER RADIUS: TARGET FIRST AND LAST TD ELEMENTS IN THE LAST ROW
152
+ &:last-of-type {
153
+ td {
154
+ border-bottom: none;
155
+ }
156
+
157
+ td:first-child {
158
+ border-bottom-left-radius: $hds-table-inner-border-radius;
159
+ }
160
+
161
+ td:last-child {
162
+ border-bottom-right-radius: $hds-table-inner-border-radius;
163
+ }
164
+ }
165
+ }
166
+ }
package/index.js CHANGED
@@ -10,4 +10,15 @@ module.exports = {
10
10
  included: function (/* app */) {
11
11
  this._super.included.apply(this, arguments);
12
12
  },
13
+
14
+ options: {
15
+ babel: {
16
+ plugins: [require.resolve('ember-auto-import/babel-plugin')],
17
+ },
18
+ autoImport: {
19
+ alias: {
20
+ 'dialog-polyfill-css': 'dialog-polyfill/dist/dialog-polyfill.css',
21
+ },
22
+ },
23
+ },
13
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hashicorp/design-system-components",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
4
4
  "description": "HashiCorp Design System Components",
5
5
  "keywords": [
6
6
  "hashicorp",
@@ -36,13 +36,16 @@
36
36
  "test:ember:percy": "percy exec ember test"
37
37
  },
38
38
  "dependencies": {
39
- "@hashicorp/design-system-tokens": "^1.2.0",
40
- "@hashicorp/ember-flight-icons": "^3.0.1",
39
+ "@hashicorp/design-system-tokens": "^1.3.0",
40
+ "@hashicorp/ember-flight-icons": "^3.0.2",
41
+ "dialog-polyfill": "^0.5.6",
41
42
  "ember-auto-import": "^2.4.2",
42
43
  "ember-cached-decorator-polyfill": "^0.1.4",
43
44
  "ember-cli-babel": "^7.26.11",
44
45
  "ember-cli-htmlbars": "^6.1.0",
45
46
  "ember-cli-sass": "^10.0.1",
47
+ "ember-composable-helpers": "^4.4.1",
48
+ "ember-focus-trap": "^1.0.1",
46
49
  "ember-keyboard": "^8.1.0",
47
50
  "ember-named-blocks-polyfill": "^0.2.5",
48
51
  "ember-style-modifier": "^0.8.0",
@@ -55,7 +58,7 @@
55
58
  "@embroider/test-setup": "^1.8.3",
56
59
  "@glimmer/component": "^1.1.2",
57
60
  "@glimmer/tracking": "^1.1.2",
58
- "@percy/cli": "^1.12.0",
61
+ "@percy/cli": "^1.16.0",
59
62
  "@percy/ember": "^4.0.0",
60
63
  "babel-eslint": "^10.1.0",
61
64
  "broccoli-asset-rev": "^3.0.0",