@redvars/peacock 3.6.2 → 3.7.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.
Files changed (200) hide show
  1. package/dist/ButtonConstants-D06bY4uy.js +114 -0
  2. package/dist/ButtonConstants-D06bY4uy.js.map +1 -0
  3. package/dist/{BaseHyperlinkMixin-BNuwbiEf.js → NativeHyperlinkMixin-DrYXyfMQ.js} +8 -10
  4. package/dist/NativeHyperlinkMixin-DrYXyfMQ.js.map +1 -0
  5. package/dist/assets/components.css +1 -1
  6. package/dist/assets/components.css.map +1 -1
  7. package/dist/assets/styles.css +1 -1
  8. package/dist/assets/styles.css.map +1 -1
  9. package/dist/button-colors-Dwnez1tR.js +586 -0
  10. package/dist/button-colors-Dwnez1tR.js.map +1 -0
  11. package/dist/button-group.js +8 -8
  12. package/dist/button-group.js.map +1 -1
  13. package/dist/button.js +236 -133
  14. package/dist/button.js.map +1 -1
  15. package/dist/calendar-column-view.js +0 -1
  16. package/dist/calendar-column-view.js.map +1 -1
  17. package/dist/calendar-month-view.js +0 -1
  18. package/dist/calendar-month-view.js.map +1 -1
  19. package/dist/canvas.js +126 -107
  20. package/dist/canvas.js.map +1 -1
  21. package/dist/card-content.js +0 -1
  22. package/dist/card-content.js.map +1 -1
  23. package/dist/card.js +96 -90
  24. package/dist/card.js.map +1 -1
  25. package/dist/cb-compound-expression.js +4 -1
  26. package/dist/cb-compound-expression.js.map +1 -1
  27. package/dist/cb-divider.js +0 -1
  28. package/dist/cb-divider.js.map +1 -1
  29. package/dist/cb-expression.js +0 -2
  30. package/dist/cb-expression.js.map +1 -1
  31. package/dist/cb-predicate.js +0 -1
  32. package/dist/cb-predicate.js.map +1 -1
  33. package/dist/code-highlighter.js +23 -6
  34. package/dist/code-highlighter.js.map +1 -1
  35. package/dist/custom-elements-jsdocs.json +5079 -17882
  36. package/dist/custom-elements.json +19272 -19314
  37. package/dist/fab.js +181 -117
  38. package/dist/fab.js.map +1 -1
  39. package/dist/flow-designer.js +4 -4
  40. package/dist/icon-button-DJ0kZXYr.js +318 -0
  41. package/dist/icon-button-DJ0kZXYr.js.map +1 -0
  42. package/dist/index.js +7 -7
  43. package/dist/{navigation-rail-CD7IrqbN.js → navigation-rail-CM_svs5_.js} +1311 -730
  44. package/dist/navigation-rail-CM_svs5_.js.map +1 -0
  45. package/dist/observe-slot-change-D8Xg-kSS.js +60 -0
  46. package/dist/observe-slot-change-D8Xg-kSS.js.map +1 -0
  47. package/dist/peacock-loader.js +10 -7
  48. package/dist/peacock-loader.js.map +1 -1
  49. package/dist/popover-content.js +0 -1
  50. package/dist/popover-content.js.map +1 -1
  51. package/dist/search.js +15 -15
  52. package/dist/search.js.map +1 -1
  53. package/dist/src/__controllers/attachable-controller.d.ts +109 -0
  54. package/dist/src/__mixins/{BaseButtonMixin.d.ts → NativeButtonMixin.d.ts} +3 -3
  55. package/dist/src/__mixins/{BaseHyperlinkMixin.d.ts → NativeHyperlinkMixin.d.ts} +3 -4
  56. package/dist/src/__utils/is-link.d.ts +1 -0
  57. package/dist/src/__utils/observe-slot-change.d.ts +1 -1
  58. package/dist/src/accordion/accordion-item.d.ts +0 -1
  59. package/dist/src/breadcrumb/breadcrumb-item/breadcrumb-item.d.ts +0 -1
  60. package/dist/src/button/ButtonConstants.d.ts +1 -0
  61. package/dist/src/button/GroupButtonInterface.d.ts +4 -0
  62. package/dist/src/button/button/button.d.ts +32 -7
  63. package/dist/src/button/button-group/button-group.d.ts +2 -1
  64. package/dist/src/button/icon-button/icon-button.d.ts +26 -5
  65. package/dist/src/button/index.d.ts +1 -1
  66. package/dist/src/calendar/calendar-column-view.d.ts +0 -1
  67. package/dist/src/calendar/calendar-month-view.d.ts +0 -1
  68. package/dist/src/canvas/canvas.d.ts +3 -3
  69. package/dist/src/card/card-content.d.ts +0 -1
  70. package/dist/src/card/card.d.ts +9 -6
  71. package/dist/src/chip/chip/chip.d.ts +22 -3
  72. package/dist/src/condition-builder/cb-compound-expression.d.ts +0 -1
  73. package/dist/src/condition-builder/cb-divider.d.ts +0 -1
  74. package/dist/src/condition-builder/cb-expression.d.ts +0 -1
  75. package/dist/src/condition-builder/cb-predicate.d.ts +0 -1
  76. package/dist/src/fab/fab.d.ts +20 -6
  77. package/dist/src/field/field.d.ts +1 -0
  78. package/dist/src/focus-ring/focus-ring.d.ts +26 -20
  79. package/dist/src/image/image.d.ts +2 -2
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/input/input.d.ts +1 -3
  82. package/dist/src/item/index.d.ts +1 -0
  83. package/dist/src/item/item.d.ts +49 -0
  84. package/dist/src/link/link.d.ts +1 -1
  85. package/dist/src/list/list-item.d.ts +1 -2
  86. package/dist/src/menu/menu-item/menu-item.d.ts +9 -11
  87. package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -1
  88. package/dist/src/navigation-rail/navigation-rail-item.d.ts +0 -2
  89. package/dist/src/navigation-rail/navigation-rail.d.ts +2 -6
  90. package/dist/src/popover/popover-content.d.ts +0 -1
  91. package/dist/src/ripple/ripple.d.ts +9 -1
  92. package/dist/src/search/search.d.ts +2 -6
  93. package/dist/src/segmented-button/segmented-button.d.ts +0 -1
  94. package/dist/src/select/option.d.ts +0 -1
  95. package/dist/src/sidebar-menu/sidebar-menu-item.d.ts +0 -1
  96. package/dist/src/sidebar-menu/sidebar-sub-menu.d.ts +0 -1
  97. package/dist/src/tabs/tab-panel.d.ts +0 -1
  98. package/dist/src/tabs/tab.d.ts +4 -6
  99. package/dist/test/item.test.d.ts +1 -0
  100. package/dist/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +4 -2
  102. package/readme.md +2 -2
  103. package/scss/components.scss +0 -1
  104. package/scss/mixin.scss +33 -13
  105. package/scss/styles.scss +1 -3
  106. package/src/__controllers/attachable-controller.ts +198 -0
  107. package/src/__mixins/NativeButtonMixin.ts +87 -0
  108. package/src/__mixins/{BaseHyperlinkMixin.ts → NativeHyperlinkMixin.ts} +15 -15
  109. package/src/__utils/is-link.ts +3 -0
  110. package/src/__utils/observe-slot-change.ts +46 -14
  111. package/src/accordion/accordion-item.scss +1 -1
  112. package/src/accordion/accordion-item.ts +0 -1
  113. package/src/breadcrumb/breadcrumb-item/breadcrumb-item.ts +0 -1
  114. package/src/button/ButtonConstants.ts +1 -0
  115. package/src/button/GroupButtonInterface.ts +4 -0
  116. package/src/button/button/button-colors.scss +2 -2
  117. package/src/button/button/button-layers.scss +124 -0
  118. package/src/button/button/button-sizes.scss +31 -53
  119. package/src/button/button/button.scss +139 -262
  120. package/src/button/button/button.ts +260 -106
  121. package/src/button/button/only-button.scss +13 -0
  122. package/src/button/button-group/button-group.ts +59 -17
  123. package/src/button/icon-button/icon-button-sizes.scss +12 -27
  124. package/src/button/icon-button/icon-button.ts +191 -83
  125. package/src/button/index.ts +1 -1
  126. package/src/calendar/calendar-column-view.ts +0 -1
  127. package/src/calendar/calendar-month-view.ts +0 -1
  128. package/src/canvas/canvas.scss +18 -6
  129. package/src/canvas/canvas.ts +125 -103
  130. package/src/card/card-content.ts +2 -3
  131. package/src/card/card.scss +87 -95
  132. package/src/card/card.ts +62 -60
  133. package/src/chip/chip/chip.scss +66 -71
  134. package/src/chip/chip/chip.ts +155 -56
  135. package/src/code-highlighter/code-highlighter.scss +1 -1
  136. package/src/code-highlighter/code-highlighter.ts +20 -5
  137. package/src/condition-builder/cb-compound-expression.scss +4 -0
  138. package/src/condition-builder/cb-compound-expression.ts +0 -1
  139. package/src/condition-builder/cb-divider.ts +0 -1
  140. package/src/condition-builder/cb-expression.scss +0 -1
  141. package/src/condition-builder/cb-expression.ts +0 -1
  142. package/src/condition-builder/cb-predicate.ts +0 -1
  143. package/src/elevation/elevation.scss +5 -1
  144. package/src/empty-state/empty-state.scss +1 -0
  145. package/src/fab/fab-colors.scss +2 -2
  146. package/src/fab/fab-sizes.scss +24 -34
  147. package/src/fab/fab.scss +77 -71
  148. package/src/fab/fab.ts +141 -65
  149. package/src/field/field.ts +6 -0
  150. package/src/focus-ring/focus-ring.ts +81 -72
  151. package/src/image/image.scss +21 -16
  152. package/src/image/image.ts +13 -14
  153. package/src/index.ts +1 -0
  154. package/src/input/input.ts +16 -25
  155. package/src/item/index.ts +1 -0
  156. package/src/item/item.scss +195 -0
  157. package/src/item/item.ts +362 -0
  158. package/src/link/link.scss +1 -10
  159. package/src/link/link.ts +4 -2
  160. package/src/list/list-item.ts +8 -8
  161. package/src/menu/menu/menu.ts +5 -9
  162. package/src/menu/menu-item/menu-item.scss +30 -108
  163. package/src/menu/menu-item/menu-item.ts +102 -133
  164. package/src/menu/sub-menu/sub-menu.ts +6 -3
  165. package/src/navigation-rail/navigation-rail-item.scss +5 -0
  166. package/src/navigation-rail/navigation-rail-item.ts +10 -15
  167. package/src/navigation-rail/navigation-rail.ts +2 -6
  168. package/src/peacock-loader.ts +5 -1
  169. package/src/popover/popover-content.ts +0 -1
  170. package/src/ripple/ripple.ts +52 -20
  171. package/src/search/search.scss +3 -0
  172. package/src/search/search.ts +11 -16
  173. package/src/segmented-button/segmented-button.ts +0 -1
  174. package/src/select/option.ts +1 -2
  175. package/src/select/select.scss +1 -10
  176. package/src/select/select.ts +2 -0
  177. package/src/sidebar-menu/sidebar-menu-item.ts +0 -1
  178. package/src/sidebar-menu/sidebar-sub-menu.ts +0 -1
  179. package/src/skeleton/skeleton.scss +5 -1
  180. package/src/tabs/tab-panel.ts +0 -1
  181. package/src/tabs/tab.ts +60 -70
  182. package/src/text/text.css-component.scss +3 -21
  183. package/src/tooltip/tooltip.scss +5 -8
  184. package/src/tooltip/tooltip.ts +1 -2
  185. package/dist/BaseButton-BNFAYn-S.js +0 -219
  186. package/dist/BaseButton-BNFAYn-S.js.map +0 -1
  187. package/dist/BaseHyperlinkMixin-BNuwbiEf.js.map +0 -1
  188. package/dist/button-colors-AvGh22Zn.js +0 -561
  189. package/dist/button-colors-AvGh22Zn.js.map +0 -1
  190. package/dist/icon-button-ohxHhy4t.js +0 -247
  191. package/dist/icon-button-ohxHhy4t.js.map +0 -1
  192. package/dist/navigation-rail-CD7IrqbN.js.map +0 -1
  193. package/dist/observe-slot-change-BGJfgg2E.js +0 -31
  194. package/dist/observe-slot-change-BGJfgg2E.js.map +0 -1
  195. package/dist/src/button/BaseButton.d.ts +0 -28
  196. package/dist/src/focus-ring/FocusAttachableController.d.ts +0 -8
  197. package/src/__mixins/BaseButtonMixin.ts +0 -83
  198. package/src/button/BaseButton.ts +0 -113
  199. package/src/focus-ring/FocusAttachableController.ts +0 -28
  200. package/src/popover/tooltip.css-component.scss +0 -19
@@ -79,7 +79,14 @@ export class Input extends BaseInput {
79
79
  @query('.input-element')
80
80
  private inputElement?: HTMLInputElement;
81
81
 
82
- private tabindex?: string;
82
+ override async focus() {
83
+ await Promise.all([
84
+ customElements.whenDefined('wc-input'),
85
+ customElements.whenDefined('wc-field'),
86
+ ]);
87
+ await this.updateComplete;
88
+ this.inputElement?.focus();
89
+ }
83
90
 
84
91
  connectedCallback() {
85
92
  super.connectedCallback();
@@ -87,11 +94,6 @@ export class Input extends BaseInput {
87
94
  }
88
95
 
89
96
  private handleInitialAttributes() {
90
- if (this.hasAttribute('tabindex')) {
91
- this.tabindex = this.getAttribute('tabindex') || undefined;
92
- this.removeAttribute('tabindex');
93
- }
94
-
95
97
  Array.from(this.attributes).forEach(attr => {
96
98
  if (attr.name.startsWith('aria-')) {
97
99
  this.configAria[attr.name] = attr.value;
@@ -105,21 +107,9 @@ export class Input extends BaseInput {
105
107
  this.value = (event.target as HTMLInputElement).value;
106
108
  }
107
109
 
108
- override focus() {
109
- this.inputElement?.focus();
110
- }
111
-
112
- override blur() {
113
- this.inputElement?.blur();
114
- }
115
-
116
- private __handleFocusChange() {
117
- // When calling focus() or reportValidity() during change, it's possible
118
- // for blur to be called after the new focus event. Rather than set
119
- // `this.focused` to true/false on focus/blur, we always set it to whether
120
- // or not the input itself is focused.
121
- this.focused = this.inputElement?.matches(':focus') ?? false;
122
- }
110
+ private __handleFocusChange = (event: FocusEvent) => {
111
+ this.focused = event.type === 'focus';
112
+ };
123
113
 
124
114
  private __redispatchEvent(event: Event) {
125
115
  redispatchEvent(this, event);
@@ -156,7 +146,6 @@ export class Input extends BaseInput {
156
146
  placeholder=${this.placeholder}
157
147
  autocomplete=${this.autocomplete}
158
148
  .value=${this.value}
159
- ?tabindex=${this.tabindex}
160
149
  ?readonly=${this.readonly}
161
150
  ?required=${this.required}
162
151
  ?disabled=${this.disabled}
@@ -169,7 +158,7 @@ export class Input extends BaseInput {
169
158
 
170
159
  ${this.type === 'password'
171
160
  ? html`
172
- <pc-tooltip
161
+ <wc-tooltip
173
162
  slot="field-end"
174
163
  content=${this.passwordVisible
175
164
  ? 'Hide password'
@@ -183,10 +172,12 @@ export class Input extends BaseInput {
183
172
  }}
184
173
  >
185
174
  <wc-icon
186
- name=${this.passwordVisible ? 'visibility_off' : 'visibility'}
175
+ name=${this.passwordVisible
176
+ ? 'visibility_off'
177
+ : 'visibility'}
187
178
  ></wc-icon>
188
179
  </wc-icon-button>
189
- </pc-tooltip>
180
+ </wc-tooltip>
190
181
  `
191
182
  : nothing}
192
183
 
@@ -0,0 +1 @@
1
+ export { Item } from './item.js';
@@ -0,0 +1,195 @@
1
+ @use "../../scss/mixin";
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ position: relative;
7
+ display: block;
8
+ padding-inline: var(--spacing-050);
9
+ --item-height: 3.5rem;
10
+
11
+ --item-container-color: transparent;
12
+ --item-label-text-color: var(--color-on-surface);
13
+ --item-leading-trailing-color: var(--color-on-surface-variant);
14
+ --item-supporting-text-color: var(--color-on-surface-variant);
15
+
16
+ --item-container-selected-color: var(--color-tertiary-container);
17
+ --item-label-text-selected-color: var(--color-on-tertiary-container);
18
+
19
+ --private-item-container-color: var(--item-container-color);
20
+ --private-item-label-text-color: var(--item-label-text-color);
21
+ --private-item-leading-trailing-color: var(--item-leading-trailing-color);
22
+ --private-item-supporting-text-color: var(--item-supporting-text-color);
23
+
24
+ --private-item-container-state-color: var(--private-item-label-text-color);
25
+
26
+ --private-item-container-shape-start-start: var(--item-container-shape-start-start, var(--shape-corner-extra-small));
27
+ --private-item-container-shape-start-end: var(--item-container-shape-start-end, var(--shape-corner-extra-small));
28
+ --private-item-container-shape-end-start: var(--item-container-shape-end-start, var(--shape-corner-extra-small));
29
+ --private-item-container-shape-end-end: var(--item-container-shape-end-end, var(--shape-corner-extra-small));
30
+ --private-item-container-shape-variant: var(--item-container-shape-variant, none);
31
+ }
32
+
33
+ /**
34
+ * Reset native button/link styles
35
+ */
36
+ .native-button {
37
+ @include mixin.reset-button-styles;
38
+ }
39
+ .native-link {
40
+ @include mixin.reset-link-styles;
41
+ }
42
+
43
+ .item {
44
+ min-height: var(--item-height);
45
+ width: 100%;
46
+ background: transparent;
47
+ text-align: initial;
48
+ cursor: pointer;
49
+ z-index: 0;
50
+
51
+ font-family: var(--item-label-font-family, var(--typography-body-large-font-family)) !important;
52
+ font-size: var(--item-label-font-size, var(--typography-body-large-font-size)) !important;
53
+ font-weight: var(--item-label-font-weight, var(--typography-body-large-font-weight)) !important;
54
+ line-height: var(--item-label-line-height, var(--typography-body-large-line-height)) !important;
55
+ letter-spacing: var(--item-label-letter-spacing, var(--typography-body-large-letter-spacing)) !important;
56
+
57
+ .item-content {
58
+ position: relative;
59
+ z-index: 1;
60
+ display: flex;
61
+ align-items: center;
62
+ gap: var(--spacing-200);
63
+ min-height: var(--item-height);
64
+
65
+ padding-inline: var(--spacing-200);
66
+ color: var(--private-item-label-text-color);
67
+ opacity: var(--private-item-label-text-opacity, 1);
68
+ --icon-size: var(--item-icon-size, 1.5rem);
69
+ --icon-color: var(--private-item-leading-trailing-color);
70
+ }
71
+
72
+ .start,
73
+ .end {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ color: var(--private-item-leading-trailing-color);
78
+ }
79
+
80
+ .end {
81
+ margin-inline-start: auto;
82
+ }
83
+
84
+ .content {
85
+ display: flex;
86
+ flex: 1;
87
+ flex-direction: column;
88
+ justify-content: center;
89
+ gap: 0.125rem;
90
+ min-inline-size: 0;
91
+ }
92
+
93
+ .headline-row {
94
+ display: flex;
95
+ min-inline-size: 0;
96
+ }
97
+
98
+ .headline,
99
+ .overline,
100
+ .supporting-text,
101
+ .trailing-supporting-text {
102
+ min-inline-size: 0;
103
+ }
104
+
105
+ .headline {
106
+ flex: 1;
107
+ color: var(--private-item-label-text-color);
108
+ }
109
+
110
+ .overline,
111
+ .supporting-text,
112
+ .trailing-supporting-text {
113
+ color: var(--private-item-supporting-text-color);
114
+ }
115
+
116
+ .overline {
117
+ @include mixin.get-typography(label-small);
118
+ }
119
+
120
+ .supporting-text,
121
+ .trailing-supporting-text {
122
+ @include mixin.get-typography(body-medium);
123
+ }
124
+
125
+ .trailing-supporting-text {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ white-space: nowrap;
129
+ color: var(--private-item-supporting-text-color);
130
+ }
131
+ }
132
+
133
+ /*
134
+ Background layers
135
+ */
136
+ .background {
137
+ position: absolute;
138
+ inset: 0;
139
+ background-color: var(--private-item-container-color);
140
+ opacity: var(--private-item-container-opacity, 1);
141
+ pointer-events: none;
142
+ border-start-start-radius: var(--private-item-container-shape-start-start, var(--private-item-container-shape));
143
+ border-start-end-radius: var(--private-item-container-shape-start-end, var(--private-item-container-shape));
144
+ border-end-start-radius: var(--private-item-container-shape-end-start, var(--private-item-container-shape));
145
+ border-end-end-radius: var(--private-item-container-shape-end-end, var(--private-item-container-shape));
146
+ corner-shape: var(--private-item-container-shape-variant);
147
+ }
148
+
149
+ .focus-ring {
150
+ z-index: 2;
151
+ --focus-ring-container-shape-start-start: var(--private-item-container-shape-start-start, var(--private-item-container-shape));
152
+ --focus-ring-container-shape-start-end: var(--private-item-container-shape-start-end, var(--private-item-container-shape));
153
+ --focus-ring-container-shape-end-start: var(--private-item-container-shape-end-start, var(--private-item-container-shape));
154
+ --focus-ring-container-shape-end-end: var(--private-item-container-shape-end-end, var(--private-item-container-shape));
155
+ --focus-ring-container-shape-variant: var(--private-item-container-shape-variant);
156
+ }
157
+
158
+ .ripple {
159
+ border-start-start-radius: var(--private-item-container-shape-start-start, var(--private-item-container-shape));
160
+ border-start-end-radius: var(--private-item-container-shape-start-end, var(--private-item-container-shape));
161
+ border-end-start-radius: var(--private-item-container-shape-end-start, var(--private-item-container-shape));
162
+ border-end-end-radius: var(--private-item-container-shape-end-end, var(--private-item-container-shape));
163
+ corner-shape: var(--private-item-container-shape-variant);
164
+ --ripple-state-opacity: var(--private-item-container-state-opacity, 0);
165
+ --ripple-pressed-color: var(--private-item-container-state-color);
166
+ }
167
+
168
+ /* State management */
169
+ :host:hover:not([disabled], [selected]) {
170
+ --private-item-container-state-opacity: 0.08;
171
+ }
172
+
173
+ :host:has(.item.pressed):not([disabled]) {
174
+ --private-item-container-state-opacity: 0.12;
175
+ }
176
+
177
+ :host([selected]) {
178
+ --private-item-container-color: var(--item-container-selected-color);
179
+ --private-item-label-text-color: var(--item-label-text-selected-color);
180
+ --private-item-leading-trailing-color: var(--item-label-text-selected-color);
181
+ --private-item-supporting-text-color: var(--item-label-text-selected-color);
182
+ }
183
+
184
+ :host([disabled]) {
185
+ cursor: not-allowed;
186
+ --private-item-label-text-color: var(--color-on-surface);
187
+ --private-item-label-text-opacity: 0.38;
188
+ --private-item-leading-trailing-color: var(--color-on-surface);
189
+ --private-item-supporting-text-color: var(--color-on-surface);
190
+ --private-item-container-opacity: 0.12;
191
+
192
+ .ripple {
193
+ display: none;
194
+ }
195
+ }
@@ -0,0 +1,362 @@
1
+ import { html, LitElement, nothing } from 'lit';
2
+ import { property, query, state } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+ import styles from './item.scss';
6
+ import NativeButtonMixin from '@/__mixins/NativeButtonMixin.js';
7
+ import NativeHyperlinkMixin from '@/__mixins/NativeHyperlinkMixin.js';
8
+ import {
9
+ dispatchActivationClick,
10
+ isActivationClick,
11
+ } from '@/__utils/dispatch-event-utils.js';
12
+ import { isLink } from '@/__utils/is-link.js';
13
+
14
+ /**
15
+ * @label Item
16
+ * @tag wc-item
17
+ * @rawTag item
18
+ *
19
+ * @summary A Material 3 item with start, text and end slots.
20
+ *
21
+ * @example
22
+ * ```html
23
+ * <wc-item selected>
24
+ * <wc-icon slot="start" name="home"></wc-icon>
25
+ * <div slot="overline">Overline</div>
26
+ * <div slot="headline">Headline</div>
27
+ * <div slot="supporting-text">Supporting text</div>
28
+ * <div slot="trailing-supporting-text">Trailing</div>
29
+ * <wc-icon slot="end" name="chevron_right"></wc-icon>
30
+ * </wc-item>
31
+ * ```
32
+ * @tags display
33
+ */
34
+ export class Item extends NativeButtonMixin(NativeHyperlinkMixin(LitElement)) {
35
+ static styles = [styles];
36
+
37
+ static override get observedAttributes() {
38
+ return [...super.observedAttributes, 'tabindex'];
39
+ }
40
+
41
+ private readonly __contentObserver = new MutationObserver(() => {
42
+ this.requestUpdate();
43
+ });
44
+
45
+ private __capturedTabIndex?: string;
46
+
47
+ private __isCapturingTabIndex = false;
48
+
49
+ @property({ type: Boolean, reflect: true }) selected = false;
50
+
51
+ @query('#item') readonly itemElement!: HTMLElement | null;
52
+
53
+ @state() isPressed = false;
54
+
55
+ private __handleSlotChange = () => {
56
+ this.requestUpdate();
57
+ };
58
+
59
+ private __hasNamedSlot(...names: string[]) {
60
+ return names.some(name =>
61
+ Array.from(this.children).some(
62
+ child => child.getAttribute('slot') === name,
63
+ ),
64
+ );
65
+ }
66
+
67
+ private __hasDefaultSlot() {
68
+ return Array.from(this.childNodes).some(node => {
69
+ if (node.nodeType === Node.TEXT_NODE) {
70
+ return Boolean(node.textContent?.trim());
71
+ }
72
+
73
+ return (
74
+ node.nodeType === Node.ELEMENT_NODE &&
75
+ !(node as Element).hasAttribute('slot')
76
+ );
77
+ });
78
+ }
79
+
80
+ connectedCallback() {
81
+ // eslint-disable-next-line wc/guard-super-call
82
+ super.connectedCallback();
83
+ this.__captureHostTabIndex();
84
+
85
+ this.__contentObserver.observe(this, {
86
+ subtree: true,
87
+ childList: true,
88
+ characterData: true,
89
+ attributes: true,
90
+ attributeFilter: ['slot'],
91
+ });
92
+ }
93
+
94
+ disconnectedCallback() {
95
+ this.__contentObserver.disconnect();
96
+ super.disconnectedCallback();
97
+ }
98
+
99
+ override attributeChangedCallback(
100
+ name: string,
101
+ oldValue: string | null,
102
+ newValue: string | null,
103
+ ) {
104
+ if (name === 'tabindex') {
105
+ if (!this.__isCapturingTabIndex && newValue != null) {
106
+ this.__capturedTabIndex = newValue;
107
+ this.__isCapturingTabIndex = true;
108
+ this.removeAttribute('tabindex');
109
+ this.__isCapturingTabIndex = false;
110
+ this.requestUpdate();
111
+ }
112
+
113
+ return;
114
+ }
115
+
116
+ super.attributeChangedCallback(name, oldValue, newValue);
117
+ }
118
+
119
+ override focus() {
120
+ this.itemElement?.focus();
121
+ }
122
+
123
+ override blur() {
124
+ this.itemElement?.blur();
125
+ }
126
+
127
+ __dispatchClick = (event: MouseEvent | KeyboardEvent) => {
128
+ if (this.softDisabled || (this.disabled && this.href)) {
129
+ event.stopImmediatePropagation();
130
+ event.preventDefault();
131
+ return;
132
+ }
133
+
134
+ if (!isActivationClick(event) || !this.itemElement) {
135
+ return;
136
+ }
137
+
138
+ this.focus();
139
+ dispatchActivationClick(this.itemElement);
140
+ };
141
+
142
+ __handleKeyDown = (event: KeyboardEvent) => {
143
+ this.__handlePress(event);
144
+
145
+ if (this.disabled || this.softDisabled || !this.itemElement) {
146
+ return;
147
+ }
148
+
149
+ if (event.key === ' ') {
150
+ event.preventDefault();
151
+ this.itemElement.click();
152
+ return;
153
+ }
154
+
155
+ if (event.key === 'Enter' && !isLink(this)) {
156
+ event.preventDefault();
157
+ this.itemElement.click();
158
+ }
159
+ };
160
+
161
+ __handlePress = (event: KeyboardEvent | MouseEvent) => {
162
+ if (this.disabled || this.softDisabled) return;
163
+
164
+ if (
165
+ event instanceof KeyboardEvent &&
166
+ event.type === 'keydown' &&
167
+ (event.key === 'Enter' || event.key === ' ')
168
+ ) {
169
+ this.isPressed = true;
170
+ } else if (event.type === 'mousedown') {
171
+ this.isPressed = true;
172
+ } else {
173
+ this.isPressed = false;
174
+ }
175
+ };
176
+
177
+ private __getForwardedAttribute(name: string) {
178
+ return this.getAttribute(name) ?? undefined;
179
+ }
180
+
181
+ private __captureHostTabIndex() {
182
+ const tabIndex = this.getAttribute('tabindex');
183
+
184
+ if (tabIndex == null) {
185
+ return;
186
+ }
187
+
188
+ this.__capturedTabIndex = tabIndex;
189
+ this.__isCapturingTabIndex = true;
190
+ this.removeAttribute('tabindex');
191
+ this.__isCapturingTabIndex = false;
192
+ }
193
+
194
+ render() {
195
+ const role = this.__getForwardedAttribute('role');
196
+ const tabIndex = this.__capturedTabIndex;
197
+ const ariaHasPopup = this.__getForwardedAttribute('aria-haspopup');
198
+ const ariaControls = this.__getForwardedAttribute('aria-controls');
199
+ const ariaExpanded = this.__getForwardedAttribute('aria-expanded');
200
+
201
+ const cssClasses: any = {
202
+ item: true,
203
+ selected: this.selected,
204
+ disabled: this.disabled || this.softDisabled,
205
+ pressed: this.isPressed,
206
+ };
207
+
208
+ return html`
209
+ <wc-focus-ring class="focus-ring" for="item"></wc-focus-ring>
210
+ <div class="background"></div>
211
+ <wc-ripple class="ripple" for="item"></wc-ripple>
212
+
213
+ ${this.renderItemElement(cssClasses, role, tabIndex, ariaHasPopup, ariaControls, ariaExpanded)}
214
+ `;
215
+ }
216
+
217
+ renderItemElement(
218
+ cssClasses: any,
219
+ role: string | undefined,
220
+ tabIndex: string | undefined,
221
+ ariaHasPopup: string | undefined,
222
+ ariaControls: string | undefined,
223
+ ariaExpanded: string | undefined,
224
+ ) {
225
+ if (!isLink(this)) {
226
+ cssClasses['native-button'] = true;
227
+
228
+ return html`
229
+ <button
230
+ id="item"
231
+ class=${classMap(cssClasses)}
232
+ type=${this.htmlType}
233
+ role=${ifDefined(role)}
234
+ tabindex=${ifDefined(tabIndex)}
235
+ ?disabled=${this.disabled}
236
+ ?aria-disabled=${this.softDisabled}
237
+ aria-haspopup=${ifDefined(ariaHasPopup)}
238
+ aria-controls=${ifDefined(ariaControls)}
239
+ aria-expanded=${ifDefined(ariaExpanded)}
240
+ @click=${this.__dispatchClick}
241
+ @mousedown=${this.__handlePress}
242
+ @keydown=${this.__handleKeyDown}
243
+ @keyup=${this.__handlePress}
244
+ >
245
+ ${this.renderContent()}
246
+ </button>
247
+ `;
248
+ }
249
+ cssClasses['native-link'] = true;
250
+ return html`
251
+ <a
252
+ id="item"
253
+ class=${classMap(cssClasses)}
254
+ href=${this.href}
255
+ target=${this.target}
256
+ rel=${ifDefined(this.rel)}
257
+ download=${ifDefined(this.download)}
258
+ role=${ifDefined(role)}
259
+ tabindex=${ifDefined(tabIndex ?? (this.disabled ? '-1' : '0'))}
260
+ aria-disabled=${String(this.disabled || this.softDisabled)}
261
+ aria-haspopup=${ifDefined(ariaHasPopup)}
262
+ aria-controls=${ifDefined(ariaControls)}
263
+ aria-expanded=${ifDefined(ariaExpanded)}
264
+ @click=${this.__dispatchClick}
265
+ @mousedown=${this.__handlePress}
266
+ @keydown=${this.__handleKeyDown}
267
+ @keyup=${this.__handlePress}
268
+ >
269
+ ${this.renderContent()}
270
+ </a>
271
+ `;
272
+ }
273
+
274
+ renderContent() {
275
+ const hasStart = this.__hasNamedSlot('start');
276
+ const hasEnd = this.__hasNamedSlot('end');
277
+ const hasOverline = this.__hasNamedSlot('overline');
278
+ const hasHeadline = this.__hasNamedSlot('headline');
279
+ const hasDefault = this.__hasDefaultSlot();
280
+ const hasSupportingText = this.__hasNamedSlot('supporting-text');
281
+ const hasTrailingSupportingText = this.__hasNamedSlot(
282
+ 'trailing-supporting-text',
283
+ );
284
+
285
+ return html`
286
+ <div class="item-content">
287
+ ${hasStart
288
+ ? html`
289
+ <div class="start">
290
+ <slot
291
+ name="start"
292
+ @slotchange=${this.__handleSlotChange}
293
+ ></slot>
294
+ </div>
295
+ `
296
+ : nothing}
297
+ <div class="content">
298
+ ${hasOverline
299
+ ? html`
300
+ <div class="overline">
301
+ <slot
302
+ name="overline"
303
+ @slotchange=${this.__handleSlotChange}
304
+ ></slot>
305
+ </div>
306
+ `
307
+ : nothing}
308
+ ${hasHeadline || hasDefault
309
+ ? html`
310
+ <div class="headline-row">
311
+ ${hasHeadline || hasDefault
312
+ ? html`
313
+ <div class="headline">
314
+ ${hasHeadline
315
+ ? html`<slot
316
+ name="headline"
317
+ @slotchange=${this.__handleSlotChange}
318
+ ></slot>`
319
+ : nothing}
320
+ ${hasDefault
321
+ ? html`<slot
322
+ @slotchange=${this.__handleSlotChange}
323
+ ></slot>`
324
+ : nothing}
325
+ </div>
326
+ `
327
+ : nothing}
328
+ </div>
329
+ `
330
+ : nothing}
331
+ ${hasSupportingText
332
+ ? html`
333
+ <div class="supporting-text">
334
+ <slot
335
+ name="supporting-text"
336
+ @slotchange=${this.__handleSlotChange}
337
+ ></slot>
338
+ </div>
339
+ `
340
+ : nothing}
341
+ </div>
342
+ ${hasTrailingSupportingText
343
+ ? html`
344
+ <div class="trailing-supporting-text">
345
+ <slot
346
+ name="trailing-supporting-text"
347
+ @slotchange=${this.__handleSlotChange}
348
+ ></slot>
349
+ </div>
350
+ `
351
+ : nothing}
352
+ ${hasEnd
353
+ ? html`
354
+ <div class="end">
355
+ <slot name="end" @slotchange=${this.__handleSlotChange}></slot>
356
+ </div>
357
+ `
358
+ : nothing}
359
+ </div>
360
+ `;
361
+ }
362
+ }
@@ -3,9 +3,7 @@
3
3
  @include mixin.base-styles;
4
4
 
5
5
  :host {
6
- display: inline-block;
7
- border-radius: inherit;
8
- corner-shape: inherit;
6
+ display: inline;
9
7
  color: var(--color-primary);
10
8
  }
11
9
 
@@ -25,10 +23,3 @@
25
23
  color: inherit;
26
24
  text-decoration: none !important;
27
25
  }
28
-
29
- :host(.with-icon) .link {
30
- display: inline-flex;
31
- align-items: center;
32
- gap: 0.5em;
33
- }
34
-
package/src/link/link.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { html, LitElement } from 'lit';
2
2
  import { classMap } from 'lit/directives/class-map.js';
3
- import BaseHyperlinkMixin from '../__mixins/BaseHyperlinkMixin.js';
3
+ import NativeHyperlinkMixin from '@/__mixins/NativeHyperlinkMixin.js';
4
4
  import styles from './link.scss';
5
5
 
6
6
  /**
@@ -16,7 +16,7 @@ import styles from './link.scss';
16
16
  * <wc-link href="#">Link</wc-link>
17
17
  * ```
18
18
  */
19
- export class Link extends BaseHyperlinkMixin(LitElement) {
19
+ export class Link extends NativeHyperlinkMixin(LitElement) {
20
20
  static styles = [styles];
21
21
 
22
22
  render() {
@@ -25,7 +25,9 @@ export class Link extends BaseHyperlinkMixin(LitElement) {
25
25
  link: true,
26
26
  })}
27
27
  href=${this.href}
28
+ ?download=${this.download}
28
29
  target=${this.target}
30
+ ?rel=${this.rel}
29
31
  ?tabindex=${this.parentElement?.tabIndex}
30
32
  >
31
33
  <slot></slot>