@vaadin/multi-select-combo-box 23.1.0-alpha2 → 23.1.0-alpha3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/multi-select-combo-box",
3
- "version": "23.1.0-alpha2",
3
+ "version": "23.1.0-alpha3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -33,18 +33,18 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "@polymer/polymer": "^3.0.0",
36
- "@vaadin/combo-box": "23.1.0-alpha2",
37
- "@vaadin/component-base": "23.1.0-alpha2",
38
- "@vaadin/field-base": "23.1.0-alpha2",
39
- "@vaadin/input-container": "23.1.0-alpha2",
40
- "@vaadin/vaadin-lumo-styles": "23.1.0-alpha2",
41
- "@vaadin/vaadin-material-styles": "23.1.0-alpha2",
42
- "@vaadin/vaadin-themable-mixin": "23.1.0-alpha2"
36
+ "@vaadin/combo-box": "23.1.0-alpha3",
37
+ "@vaadin/component-base": "23.1.0-alpha3",
38
+ "@vaadin/field-base": "23.1.0-alpha3",
39
+ "@vaadin/input-container": "23.1.0-alpha3",
40
+ "@vaadin/vaadin-lumo-styles": "23.1.0-alpha3",
41
+ "@vaadin/vaadin-material-styles": "23.1.0-alpha3",
42
+ "@vaadin/vaadin-themable-mixin": "23.1.0-alpha3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@esm-bundle/chai": "^4.3.4",
46
46
  "@vaadin/testing-helpers": "^0.3.2",
47
- "sinon": "^9.2.0"
47
+ "sinon": "^13.0.2"
48
48
  },
49
- "gitHead": "6842dcb8b163d4512fae8d3d12a6559077a4aee6"
49
+ "gitHead": "8c9e64e8dfa158dd52a9bf6da351ff038c88ca85"
50
50
  }
@@ -42,6 +42,25 @@ class MultiSelectComboBoxChip extends ThemableMixin(PolymerElement) {
42
42
 
43
43
  static get template() {
44
44
  return html`
45
+ <style>
46
+ :host {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ align-self: center;
50
+ white-space: nowrap;
51
+ box-sizing: border-box;
52
+ min-width: 0;
53
+ }
54
+
55
+ [part='label'] {
56
+ overflow: hidden;
57
+ text-overflow: ellipsis;
58
+ }
59
+
60
+ :host([part~='overflow']) [part='remove-button'] {
61
+ display: none !important;
62
+ }
63
+ </style>
45
64
  <div part="label">[[label]]</div>
46
65
  <div part="remove-button" role="button" on-click="_onRemoveClick"></div>
47
66
  `;
@@ -9,9 +9,10 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
9
9
  registerStyles(
10
10
  'vaadin-multi-select-combo-box-container',
11
11
  css`
12
- [part='wrapper'] {
12
+ .wrapper {
13
13
  display: flex;
14
14
  width: 100%;
15
+ min-width: 0;
15
16
  }
16
17
  `,
17
18
  {
@@ -39,7 +40,7 @@ class MultiSelectComboBoxContainer extends InputContainer {
39
40
  const slots = content.querySelectorAll('slot');
40
41
 
41
42
  const wrapper = document.createElement('div');
42
- wrapper.setAttribute('part', 'wrapper');
43
+ wrapper.setAttribute('class', 'wrapper');
43
44
  content.insertBefore(wrapper, slots[2]);
44
45
 
45
46
  wrapper.appendChild(slots[0]);
@@ -81,24 +81,17 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
81
81
  this._toggleElement = this.querySelector('.toggle-button');
82
82
  }
83
83
 
84
- /** @protected */
85
- _isClearButton(event) {
86
- return (
87
- super._isClearButton(event) ||
88
- (event.type === 'input' && !event.isTrusted) || // fake input event dispatched by clear button
89
- event.composedPath()[0].getAttribute('part') === 'clear-button'
90
- );
91
- }
92
-
93
84
  /**
94
- * @param {!Event} event
85
+ * Override method from `InputMixin`.
86
+ *
95
87
  * @protected
88
+ * @override
96
89
  */
97
- _onChange(event) {
98
- super._onChange(event);
90
+ clear() {
91
+ super.clear();
99
92
 
100
- if (this._isClearButton(event)) {
101
- this._clear();
93
+ if (this.inputElement) {
94
+ this.inputElement.value = '';
102
95
  }
103
96
  }
104
97
 
@@ -9,6 +9,7 @@ import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js
9
9
  import { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
10
10
  import { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
11
11
  import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
12
+ import { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
12
13
  import { DelegateFocusMixinClass } from '@vaadin/field-base/src/delegate-focus-mixin.js';
13
14
  import { DelegateStateMixinClass } from '@vaadin/field-base/src/delegate-state-mixin.js';
14
15
  import { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
@@ -85,6 +86,9 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
85
86
  * `error-message` | The error message element
86
87
  * `helper-text` | The helper text element wrapper
87
88
  * `required-indicator` | The `required` state indicator element
89
+ * `overflow` | The chip shown when component width is not enough to fit all chips
90
+ * `overflow-one` | Set on the overflow chip when only one chip does not fit
91
+ * `overflow-two` | Set on the overflow chip when two chips do not fit
88
92
  * `toggle-button` | The toggle button
89
93
  *
90
94
  * The following state attributes are available for styling:
@@ -102,6 +106,15 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
102
106
  * `opened` | Set when the dropdown is open
103
107
  * `readonly` | Set to a readonly element
104
108
  *
109
+ * The following custom CSS properties are available for styling:
110
+ *
111
+ * Custom property | Description | Default
112
+ * -----------------------------------------------------|----------------------------|--------
113
+ * `--vaadin-field-default-width` | Default width of the field | `12em`
114
+ * `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
115
+ * `--vaadin-multi-select-combo-box-chip-min-width` | Min width of the chip | `60px`
116
+ * `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
117
+ *
105
118
  * ### Internal components
106
119
  *
107
120
  * In addition to `<vaadin-multi-select-combo-box>` itself, the following internal
@@ -241,6 +254,7 @@ interface MultiSelectComboBox
241
254
  DisabledMixinClass,
242
255
  DelegateStateMixinClass,
243
256
  DelegateFocusMixinClass,
257
+ ResizeMixinClass,
244
258
  ThemableMixinClass,
245
259
  ElementMixinClass,
246
260
  ControllerMixinClass {}
@@ -8,6 +8,7 @@ import './vaadin-multi-select-combo-box-container.js';
8
8
  import './vaadin-multi-select-combo-box-internal.js';
9
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
10
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
11
+ import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
11
12
  import { processTemplates } from '@vaadin/component-base/src/templates.js';
12
13
  import { InputControlMixin } from '@vaadin/field-base/src/input-control-mixin.js';
13
14
  import { InputController } from '@vaadin/field-base/src/input-controller.js';
@@ -16,6 +17,11 @@ import { inputFieldShared } from '@vaadin/field-base/src/styles/input-field-shar
16
17
  import { css, registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
17
18
 
18
19
  const multiSelectComboBox = css`
20
+ :host {
21
+ --chip-min-width: var(--vaadin-multi-select-combo-box-chip-min-width, 4em);
22
+ --input-min-width: var(--vaadin-multi-select-combo-box-input-min-width, 4em);
23
+ }
24
+
19
25
  [hidden] {
20
26
  display: none !important;
21
27
  }
@@ -24,17 +30,14 @@ const multiSelectComboBox = css`
24
30
  color: transparent !important;
25
31
  }
26
32
 
27
- :host([has-value]) [class$='container'] {
28
- width: auto;
29
- }
30
-
31
33
  ::slotted(input) {
32
34
  box-sizing: border-box;
33
- flex: 1 0 4em;
35
+ flex: 1 0 var(--input-min-width);
34
36
  }
35
37
 
36
- [part~='chip'] {
38
+ [part='chip'] {
37
39
  flex: 0 1 auto;
40
+ min-width: var(--chip-min-width);
38
41
  }
39
42
 
40
43
  :host([readonly]) [part~='chip'] {
@@ -73,6 +76,9 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
73
76
  * `error-message` | The error message element
74
77
  * `helper-text` | The helper text element wrapper
75
78
  * `required-indicator` | The `required` state indicator element
79
+ * `overflow` | The chip shown when component width is not enough to fit all chips
80
+ * `overflow-one` | Set on the overflow chip when only one chip does not fit
81
+ * `overflow-two` | Set on the overflow chip when two chips do not fit
76
82
  * `toggle-button` | The toggle button
77
83
  *
78
84
  * The following state attributes are available for styling:
@@ -90,6 +96,15 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
90
96
  * `opened` | Set when the dropdown is open
91
97
  * `readonly` | Set to a readonly element
92
98
  *
99
+ * The following custom CSS properties are available for styling:
100
+ *
101
+ * Custom property | Description | Default
102
+ * -----------------------------------------------------|----------------------------|--------
103
+ * `--vaadin-field-default-width` | Default width of the field | `12em`
104
+ * `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
105
+ * `--vaadin-multi-select-combo-box-chip-min-width` | Min width of the chip | `60px`
106
+ * `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
107
+ *
93
108
  * ### Internal components
94
109
  *
95
110
  * In addition to `<vaadin-multi-select-combo-box>` itself, the following internal
@@ -114,8 +129,9 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
114
129
  * @mixes ElementMixin
115
130
  * @mixes ThemableMixin
116
131
  * @mixes InputControlMixin
132
+ * @mixes ResizeMixin
117
133
  */
118
- class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(PolymerElement))) {
134
+ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(ElementMixin(PolymerElement)))) {
119
135
  static get is() {
120
136
  return 'vaadin-multi-select-combo-box';
121
137
  }
@@ -155,6 +171,15 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
155
171
  invalid="[[invalid]]"
156
172
  theme$="[[theme]]"
157
173
  >
174
+ <vaadin-multi-select-combo-box-chip
175
+ slot="prefix"
176
+ part$="[[_getOverflowPart(_overflowItems.length)]]"
177
+ disabled="[[disabled]]"
178
+ label="[[_getOverflowLabel(_overflowItems.length)]]"
179
+ title$="[[_getOverflowTitle(_overflowItems)]]"
180
+ hidden$="[[_isOverflowHidden(_overflowItems.length)]]"
181
+ on-mousedown="_preventBlur"
182
+ ></vaadin-multi-select-combo-box-chip>
158
183
  <slot name="input"></slot>
159
184
  <div id="clearButton" part="clear-button" slot="suffix"></div>
160
185
  <div id="toggleButton" class="toggle-button" part="toggle-button" slot="suffix"></div>
@@ -180,6 +205,17 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
180
205
  */
181
206
  autoOpenDisabled: Boolean,
182
207
 
208
+ /**
209
+ * Set to true to display the clear icon which clears the input.
210
+ * @attr {boolean} clear-button-visible
211
+ */
212
+ clearButtonVisible: {
213
+ type: Boolean,
214
+ reflectToAttribute: true,
215
+ observer: '_clearButtonVisibleChanged',
216
+ value: false
217
+ },
218
+
183
219
  /**
184
220
  * A full set of items to filter the visible options from.
185
221
  * The items can be of either `String` or `Object` type.
@@ -302,6 +338,12 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
302
338
  _hasValue: {
303
339
  type: Boolean,
304
340
  value: false
341
+ },
342
+
343
+ /** @private */
344
+ _overflowItems: {
345
+ type: Array,
346
+ value: () => []
305
347
  }
306
348
  };
307
349
  }
@@ -403,6 +445,26 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
403
445
  super._toggleHasValue(this._hasValue);
404
446
  }
405
447
 
448
+ /**
449
+ * Implement callback from `ResizeMixin` to update chips.
450
+ * @protected
451
+ * @override
452
+ */
453
+ _onResize() {
454
+ this.__updateChips();
455
+ }
456
+
457
+ /**
458
+ * Setting clear button visible reduces total space available
459
+ * for rendering chips, and making it hidden increases it.
460
+ * @private
461
+ */
462
+ _clearButtonVisibleChanged(visible, oldVisible) {
463
+ if (visible || oldVisible) {
464
+ this.__updateChips();
465
+ }
466
+ }
467
+
406
468
  /** @private */
407
469
  _pageSizeChanged(pageSize, oldPageSize) {
408
470
  if (Math.floor(pageSize) !== pageSize || pageSize <= 0) {
@@ -436,6 +498,34 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
436
498
  return item && Object.prototype.hasOwnProperty.call(item, itemLabelPath) ? item[itemLabelPath] : item;
437
499
  }
438
500
 
501
+ /** @private */
502
+ _getOverflowLabel(length) {
503
+ return length;
504
+ }
505
+
506
+ /** @private */
507
+ _getOverflowPart(length) {
508
+ let part = `chip overflow`;
509
+
510
+ if (length === 1) {
511
+ part += ' overflow-one';
512
+ } else if (length === 2) {
513
+ part += ' overflow-two';
514
+ }
515
+
516
+ return part;
517
+ }
518
+
519
+ /** @private */
520
+ _getOverflowTitle(items) {
521
+ return items.map((item) => this._getItemLabel(item, this.itemLabelPath)).join(', ');
522
+ }
523
+
524
+ /** @private */
525
+ _isOverflowHidden(length) {
526
+ return length === 0;
527
+ }
528
+
439
529
  /** @private */
440
530
  _findIndex(item, selectedItems, itemIdPath) {
441
531
  if (itemIdPath && item) {
@@ -452,6 +542,7 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
452
542
 
453
543
  /** @private */
454
544
  __clearFilter() {
545
+ this.filter = '';
455
546
  this.$.comboBox.clear();
456
547
  }
457
548
 
@@ -501,31 +592,83 @@ class MultiSelectComboBox extends InputControlMixin(ThemableMixin(ElementMixin(P
501
592
  chip.setAttribute('slot', 'prefix');
502
593
 
503
594
  chip.item = item;
504
- chip.label = this._getItemLabel(item, this.itemLabelPath);
505
595
  chip.toggleAttribute('disabled', this.disabled);
506
596
 
597
+ const label = this._getItemLabel(item, this.itemLabelPath);
598
+ chip.label = label;
599
+ chip.setAttribute('title', label);
600
+
507
601
  chip.addEventListener('item-removed', (e) => this._onItemRemoved(e));
508
602
  chip.addEventListener('mousedown', (e) => this._preventBlur(e));
509
603
 
510
604
  return chip;
511
605
  }
512
606
 
607
+ /** @private */
608
+ __getMinWidth(chip) {
609
+ chip.style.visibility = 'hidden';
610
+ chip.style.display = 'block';
611
+ chip.style.minWidth = 'var(--chip-min-width)';
612
+
613
+ const result = parseInt(getComputedStyle(chip).minWidth);
614
+
615
+ chip.style.minWidth = '';
616
+ chip.style.display = '';
617
+ chip.style.visibility = '';
618
+
619
+ return result;
620
+ }
621
+
513
622
  /** @private */
514
623
  __updateChips() {
515
624
  if (!this._inputField) {
516
625
  return;
517
626
  }
518
627
 
519
- this._chips.forEach((chip) => {
628
+ // Clear all chips except the overflow
629
+ const chips = Array.from(this._chips).reverse();
630
+ const overflow = chips.pop();
631
+
632
+ chips.forEach((chip) => {
520
633
  chip.remove();
521
634
  });
522
635
 
523
636
  const items = [...this.selectedItems];
524
637
 
638
+ let refNode = overflow.nextElementSibling;
639
+
640
+ // Use overflow chip to measure min-width
641
+ const chipMinWidth = this.__getMinWidth(overflow);
642
+ const inputMinWidth = parseInt(getComputedStyle(this.inputElement).flexBasis);
643
+ const containerStyle = getComputedStyle(this._inputField);
644
+
645
+ // Detect available width for chips
646
+ let totalWidth =
647
+ parseInt(containerStyle.width) -
648
+ parseInt(containerStyle.paddingLeft) -
649
+ parseInt(containerStyle.paddingRight) -
650
+ this.$.toggleButton.clientWidth -
651
+ inputMinWidth;
652
+
653
+ if (this.clearButtonVisible) {
654
+ totalWidth -= this.$.clearButton.clientWidth;
655
+ }
656
+
525
657
  for (let i = items.length - 1; i >= 0; i--) {
526
- const chip = this.__createChip(items[i]);
527
- this._inputField.insertBefore(chip, this._inputField.firstElementChild);
658
+ // Ensure there is enough space for another chip
659
+ if (totalWidth < chipMinWidth) {
660
+ break;
661
+ }
662
+
663
+ const item = items.pop();
664
+ const chip = this.__createChip(item);
665
+ this._inputField.insertBefore(chip, refNode);
666
+
667
+ refNode = chip;
668
+ totalWidth -= chipMinWidth;
528
669
  }
670
+
671
+ this._overflowItems = items;
529
672
  }
530
673
 
531
674
  /**
@@ -13,27 +13,63 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
13
13
 
14
14
  const chip = css`
15
15
  :host {
16
- display: inline-flex;
17
- align-items: center;
18
- align-self: center;
19
- font-family: var(--lumo-font-family);
20
16
  font-size: var(--lumo-font-size-xxs);
21
17
  line-height: 1;
22
- padding: 0.3125em 0 0.3125em calc(0.5em + var(--lumo-border-radius-s) / 4);
18
+ padding: 0.3125em calc(0.5em + var(--lumo-border-radius-s) / 4);
19
+ color: var(--lumo-body-text-color);
23
20
  border-radius: var(--lumo-border-radius-s);
24
- border-radius: var(--lumo-border-radius);
25
21
  background-color: var(--lumo-contrast-20pct);
26
22
  cursor: var(--lumo-clickable-cursor);
27
- white-space: nowrap;
28
- box-sizing: border-box;
29
- min-width: 0;
23
+ }
24
+
25
+ :host(:not([part~='overflow'])) {
26
+ padding-inline-end: 0;
27
+ }
28
+
29
+ :host([part~='overflow']) {
30
+ position: relative;
31
+ min-width: var(--lumo-size-xxs);
32
+ margin-inline-start: var(--lumo-space-s);
33
+ }
34
+
35
+ :host([part~='overflow'])::before,
36
+ :host([part~='overflow'])::after {
37
+ position: absolute;
38
+ content: '';
39
+ width: 3px;
40
+ height: calc(1.875em - 1px);
41
+ border-left: 2px solid;
42
+ border-radius: 4px 0 0 4px;
43
+ border-color: var(--lumo-contrast-30pct);
44
+ }
45
+
46
+ :host([part~='overflow'])::before {
47
+ left: -4px;
48
+ }
49
+
50
+ :host([part~='overflow'])::after {
51
+ left: -8px;
52
+ }
53
+
54
+ :host([part~='overflow-two']) {
55
+ margin-inline-start: calc(var(--lumo-space-s) / 2);
56
+ }
57
+
58
+ :host([part~='overflow-two'])::after {
59
+ display: none;
60
+ }
61
+
62
+ :host([part~='overflow-one']) {
63
+ margin-inline-start: 0;
64
+ }
65
+
66
+ :host([part~='overflow-one'])::before,
67
+ :host([part~='overflow-one'])::after {
68
+ display: none;
30
69
  }
31
70
 
32
71
  [part='label'] {
33
- color: var(--lumo-body-text-color);
34
72
  font-weight: 500;
35
- overflow: hidden;
36
- text-overflow: ellipsis;
37
73
  line-height: 1.25;
38
74
  }
39
75
 
@@ -43,8 +79,8 @@ const chip = css`
43
79
  justify-content: center;
44
80
  margin-top: -0.3125em;
45
81
  margin-bottom: -0.3125em;
46
- width: var(--lumo-icon-size-s);
47
- height: var(--lumo-icon-size-s);
82
+ width: 1.25em;
83
+ height: 1.25em;
48
84
  font-size: 1.5em;
49
85
  }
50
86
 
@@ -11,20 +11,57 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
11
11
 
12
12
  const chip = css`
13
13
  :host {
14
- display: flex;
15
- align-items: center;
16
- align-self: center;
17
- box-sizing: border-box;
18
14
  height: 1.25rem;
19
15
  margin-inline-end: 0.25rem;
20
16
  padding-inline-start: 0.5rem;
21
17
  border-radius: 4px;
22
18
  background-color: hsla(214, 53%, 23%, 0.1);
23
19
  cursor: default;
24
- white-space: nowrap;
25
20
  font-family: var(--material-font-family);
26
21
  }
27
22
 
23
+ :host([part~='overflow']) {
24
+ position: relative;
25
+ margin-inline-start: 0.5rem;
26
+ padding-inline-end: 0.5rem;
27
+ }
28
+
29
+ :host([part~='overflow'])::before,
30
+ :host([part~='overflow'])::after {
31
+ position: absolute;
32
+ content: '';
33
+ width: 3px;
34
+ height: 20px;
35
+ border-left: 2px solid;
36
+ border-radius: 4px 0 0 4px;
37
+ border-color: hsla(214, 53%, 23%, 0.1);
38
+ }
39
+
40
+ :host([part~='overflow'])::before {
41
+ left: -4px;
42
+ }
43
+
44
+ :host([part~='overflow'])::after {
45
+ left: -8px;
46
+ }
47
+
48
+ :host([part~='overflow-two']) {
49
+ margin-inline-start: 0.25rem;
50
+ }
51
+
52
+ :host([part~='overflow-two'])::after {
53
+ display: none;
54
+ }
55
+
56
+ :host([part~='overflow-one']) {
57
+ margin-inline-start: 0;
58
+ }
59
+
60
+ :host([part~='overflow-one'])::before,
61
+ :host([part~='overflow-one'])::after {
62
+ display: none;
63
+ }
64
+
28
65
  [part='label'] {
29
66
  font-size: var(--material-caption-font-size);
30
67
  line-height: 1;