@vaadin/card 24.7.0-alpha4 → 24.7.0-alpha6

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/card",
3
- "version": "24.7.0-alpha4",
3
+ "version": "24.7.0-alpha6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,14 +34,14 @@
34
34
  "web-component"
35
35
  ],
36
36
  "dependencies": {
37
- "@vaadin/component-base": "24.7.0-alpha4",
38
- "@vaadin/vaadin-lumo-styles": "24.7.0-alpha4",
39
- "@vaadin/vaadin-material-styles": "24.7.0-alpha4",
40
- "@vaadin/vaadin-themable-mixin": "24.7.0-alpha4",
37
+ "@vaadin/component-base": "24.7.0-alpha6",
38
+ "@vaadin/vaadin-lumo-styles": "24.7.0-alpha6",
39
+ "@vaadin/vaadin-material-styles": "24.7.0-alpha6",
40
+ "@vaadin/vaadin-themable-mixin": "24.7.0-alpha6",
41
41
  "lit": "^3.0.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@vaadin/chai-plugins": "24.7.0-alpha4",
44
+ "@vaadin/chai-plugins": "24.7.0-alpha6",
45
45
  "@vaadin/testing-helpers": "^1.1.0",
46
46
  "sinon": "^18.0.0"
47
47
  },
@@ -49,5 +49,5 @@
49
49
  "web-types.json",
50
50
  "web-types.lit.json"
51
51
  ],
52
- "gitHead": "d7165cebf9dcf6a7e9e22f6353662d33404b4856"
52
+ "gitHead": "6255a512997a648da91fed37de4d5000809eaebf"
53
53
  }
@@ -10,14 +10,40 @@ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
10
10
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
11
 
12
12
  /**
13
- * `<vaadin-card>` is a visual content container.
13
+ * `<vaadin-card>` is a versatile container for grouping related content and actions.
14
+ * It presents information in a structured and visually appealing manner, with
15
+ * customization options to fit various design requirements.
14
16
  *
15
17
  * ```html
16
- * <vaadin-card>
17
- * <div>Card content</div>
18
+ * <vaadin-card theme="outlined cover-media">
19
+ * <img slot="media" width="200" src="..." alt="">
20
+ * <div slot="title">Lapland</div>
21
+ * <div slot="subtitle">The Exotic North</div>
22
+ * <div>Lapland is the northern-most region of Finland and an active outdoor destination.</div>
23
+ * <vaadin-button slot="footer">Book Vacation</vaadin-button>
18
24
  * </vaadin-card>
19
25
  * ```
20
26
  *
27
+ * ### Styling
28
+ *
29
+ * The following shadow DOM parts are available for styling:
30
+ *
31
+ * Part name | Description
32
+ * ----------|-------------
33
+ * `media` | The container for the media element (e.g., image, video, icon). Shown above of before the card content.
34
+ * `header` | The container for title and subtitle - or for custom header content - and header prefix and suffix elements.
35
+ * `content` | The container for the card content (usually text content).
36
+ * `footer` | The container for footer elements. This part is always at the bottom of the card.
37
+ *
38
+ * The following custom properties are available for styling:
39
+ *
40
+ * Custom property | Description | Default
41
+ * ----------------|-------------|-------------
42
+ * `--vaadin-card-padding` | The space between the card edge and its content. Needs to a unified value for all edges, i.e., a single length value. | `1em`
43
+ * `--vaadin-card-gap` | The space between content elements within the card. | `1em`
44
+ *
45
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
46
+ *
21
47
  * @customElement
22
48
  * @extends HTMLElement
23
49
  * @mixes ElementMixin
@@ -31,12 +57,225 @@ class Card extends ElementMixin(ThemableMixin(PolylitMixin(LitElement))) {
31
57
  static get styles() {
32
58
  return css`
33
59
  :host {
34
- display: block;
60
+ display: flex;
61
+ flex-direction: column;
62
+ box-sizing: border-box;
63
+ padding: var(--_padding);
64
+ gap: var(--_gap);
65
+ --_padding: var(--vaadin-card-padding, 1em);
66
+ --_gap: var(--vaadin-card-gap, 1em);
67
+ --_media: 0;
68
+ --_title: 0;
69
+ --_subtitle: 0;
70
+ --_header: max(var(--_header-prefix), var(--_title), var(--_subtitle), var(--_header-suffix));
71
+ --_header-prefix: 0;
72
+ --_header-suffix: 0;
73
+ --_content: 0;
74
+ --_footer: 0;
35
75
  }
36
76
 
37
77
  :host([hidden]) {
38
78
  display: none !important;
39
79
  }
80
+
81
+ :host(:not([theme~='horizontal'])) {
82
+ justify-content: space-between;
83
+ }
84
+
85
+ :host([_m]) {
86
+ --_media: 1;
87
+ }
88
+
89
+ :host([_t]) {
90
+ --_title: 1;
91
+ }
92
+
93
+ :host([_st]) {
94
+ --_subtitle: 1;
95
+ }
96
+
97
+ :host([_h]) {
98
+ --_header: 1;
99
+ --_title: 0;
100
+ --_subtitle: 0;
101
+ }
102
+
103
+ :host([_hp]) {
104
+ --_header-prefix: 1;
105
+ }
106
+
107
+ :host([_hs]) {
108
+ --_header-suffix: 1;
109
+ }
110
+
111
+ :host([_c]) {
112
+ --_content: 1;
113
+ }
114
+
115
+ :host([_f]) {
116
+ --_footer: 1;
117
+ }
118
+
119
+ [part='media'],
120
+ [part='header'],
121
+ [part='content'],
122
+ [part='footer'] {
123
+ display: none;
124
+ }
125
+
126
+ :host([_m]) [part='media'],
127
+ :host([_c]) [part='content'] {
128
+ display: block;
129
+ }
130
+
131
+ :host([_f]) [part='footer'] {
132
+ display: flex;
133
+ gap: var(--_gap);
134
+ }
135
+
136
+ :host(:is([_h], [_t], [_st], [_hp], [_hs])) [part='header'] {
137
+ display: grid;
138
+ align-items: center;
139
+ gap: var(--_gap);
140
+ row-gap: 0;
141
+ }
142
+
143
+ [part='header'] {
144
+ margin-bottom: auto;
145
+ }
146
+
147
+ :host([_hs]) [part='header'] {
148
+ grid-template-columns: 1fr auto;
149
+ }
150
+
151
+ :host([_hp]) [part='header'] {
152
+ grid-template-columns: repeat(var(--_header-prefix), auto) 1fr;
153
+ }
154
+
155
+ slot {
156
+ border-radius: inherit;
157
+ }
158
+
159
+ ::slotted([slot='header-prefix']) {
160
+ grid-column: 1;
161
+ grid-row: 1 / span calc(var(--_title) + var(--_subtitle));
162
+ }
163
+
164
+ ::slotted([slot='header']),
165
+ ::slotted([slot='title']) {
166
+ grid-column: calc(1 + var(--_header-prefix));
167
+ grid-row: 1;
168
+ }
169
+
170
+ ::slotted([slot='subtitle']) {
171
+ grid-column: calc(1 + var(--_header-prefix));
172
+ grid-row: calc(1 + var(--_title));
173
+ }
174
+
175
+ ::slotted([slot='header-suffix']) {
176
+ grid-column: calc(2 + var(--_header-prefix));
177
+ grid-row: 1 / span calc(var(--_title) + var(--_subtitle));
178
+ }
179
+
180
+ /* Horizontal */
181
+ :host([theme~='horizontal']) {
182
+ display: grid;
183
+ grid-template-columns: repeat(var(--_media), minmax(auto, max-content)) 1fr;
184
+ align-items: start;
185
+ }
186
+
187
+ :host([theme~='horizontal'][_f]) {
188
+ grid-template-rows: 1fr auto;
189
+ }
190
+
191
+ :host([theme~='horizontal'][_c]) {
192
+ grid-template-rows: repeat(var(--_header), auto) 1fr;
193
+ }
194
+
195
+ [part='media'] {
196
+ grid-column: 1;
197
+ grid-row: 1 / span calc(var(--_header) + var(--_content) + var(--_footer));
198
+ align-self: stretch;
199
+ border-radius: inherit;
200
+ }
201
+
202
+ [part='header'] {
203
+ grid-column: calc(1 + var(--_media));
204
+ grid-row: 1;
205
+ }
206
+
207
+ [part='content'] {
208
+ grid-column: calc(1 + var(--_media));
209
+ grid-row: calc(1 + var(--_header));
210
+ flex: auto;
211
+ min-height: 0;
212
+ }
213
+
214
+ [part='footer'] {
215
+ grid-column: calc(1 + var(--_media));
216
+ grid-row: calc(1 + var(--_header) + var(--_content));
217
+ border-radius: inherit;
218
+ }
219
+
220
+ :host([theme~='horizontal']) [part='footer'] {
221
+ align-self: end;
222
+ }
223
+
224
+ :host(:not([theme~='horizontal'])) ::slotted([slot='media']:is(img, video, svg)) {
225
+ max-width: 100%;
226
+ }
227
+
228
+ ::slotted([slot='media']) {
229
+ vertical-align: middle;
230
+ }
231
+
232
+ :host(:is([theme~='cover-media'], [theme~='stretch-media']))
233
+ ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
234
+ width: 100%;
235
+ height: auto;
236
+ aspect-ratio: var(--vaadin-card-media-aspect-ratio, 16/9);
237
+ object-fit: cover;
238
+ }
239
+
240
+ :host([theme~='horizontal']:is([theme~='cover-media'], [theme~='stretch-media'])) {
241
+ grid-template-columns: repeat(var(--_media), minmax(auto, 0.5fr)) 1fr;
242
+ }
243
+
244
+ :host([theme~='horizontal']:is([theme~='cover-media'], [theme~='stretch-media']))
245
+ ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
246
+ height: 100%;
247
+ aspect-ratio: auto;
248
+ }
249
+
250
+ :host([theme~='cover-media']) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
251
+ margin-top: calc(var(--_padding) * -1);
252
+ margin-inline: calc(var(--_padding) * -1);
253
+ width: calc(100% + var(--_padding) * 2);
254
+ max-width: none;
255
+ border-radius: inherit;
256
+ border-end-end-radius: 0;
257
+ border-end-start-radius: 0;
258
+ }
259
+
260
+ :host([theme~='horizontal'][theme~='cover-media']) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
261
+ margin-inline-end: 0;
262
+ width: calc(100% + var(--_padding));
263
+ height: calc(100% + var(--_padding) * 2);
264
+ border-radius: inherit;
265
+ border-start-end-radius: 0;
266
+ border-end-end-radius: 0;
267
+ }
268
+
269
+ /* Scroller in content */
270
+ [part='content'] ::slotted(vaadin-scroller) {
271
+ margin-inline: calc(var(--_padding) * -1);
272
+ padding-inline: var(--_padding);
273
+ }
274
+
275
+ [part='content'] ::slotted(vaadin-scroller)::before,
276
+ [part='content'] ::slotted(vaadin-scroller)::after {
277
+ margin-inline: calc(var(--_padding) * -1);
278
+ }
40
279
  `;
41
280
  }
42
281
 
@@ -46,7 +285,53 @@ class Card extends ElementMixin(ThemableMixin(PolylitMixin(LitElement))) {
46
285
 
47
286
  /** @protected */
48
287
  render() {
49
- return html`<slot></slot>`;
288
+ return html`
289
+ <div part="media">
290
+ <slot name="media"></slot>
291
+ </div>
292
+ <div part="header">
293
+ <slot name="header-prefix"></slot>
294
+ <slot name="header">
295
+ <slot name="title"></slot>
296
+ <slot name="subtitle"></slot>
297
+ </slot>
298
+ <slot name="header-suffix"></slot>
299
+ </div>
300
+ <div part="content">
301
+ <slot></slot>
302
+ </div>
303
+ <div part="footer">
304
+ <slot name="footer"></slot>
305
+ </div>
306
+ `;
307
+ }
308
+
309
+ /** @private */
310
+ _onSlotChange() {
311
+ this.toggleAttribute('_m', this.querySelector(':scope > [slot="media"]'));
312
+ this.toggleAttribute('_h', this.querySelector(':scope > [slot="header"]'));
313
+ this.toggleAttribute(
314
+ '_t',
315
+ this.querySelector(':scope > [slot="title"]') && !this.querySelector(':scope > [slot="header"]'),
316
+ );
317
+ this.toggleAttribute(
318
+ '_st',
319
+ this.querySelector(':scope > [slot="subtitle"]') && !this.querySelector(':scope > [slot="header"]'),
320
+ );
321
+ this.toggleAttribute('_hp', this.querySelector(':scope > [slot="header-prefix"]'));
322
+ this.toggleAttribute('_hs', this.querySelector(':scope > [slot="header-suffix"]'));
323
+ this.toggleAttribute('_c', this.querySelector(':scope > :not([slot])'));
324
+ this.toggleAttribute('_f', this.querySelector(':scope > [slot="footer"]'));
325
+ }
326
+
327
+ /**
328
+ * @protected
329
+ * @override
330
+ */
331
+ createRenderRoot() {
332
+ const root = super.createRenderRoot();
333
+ root.addEventListener('slotchange', () => this._onSlotChange());
334
+ return root;
50
335
  }
51
336
  }
52
337
 
@@ -1,4 +1,6 @@
1
1
  import '@vaadin/vaadin-lumo-styles/color.js';
2
2
  import '@vaadin/vaadin-lumo-styles/style.js';
3
+ import '@vaadin/vaadin-lumo-styles/spacing.js';
4
+ import '@vaadin/vaadin-lumo-styles/typography.js';
3
5
  declare const card: import("lit").CSSResult;
4
6
  export { card };
@@ -1,5 +1,7 @@
1
1
  import '@vaadin/vaadin-lumo-styles/color.js';
2
2
  import '@vaadin/vaadin-lumo-styles/style.js';
3
+ import '@vaadin/vaadin-lumo-styles/spacing.js';
4
+ import '@vaadin/vaadin-lumo-styles/typography.js';
3
5
  import { addGlobalThemeStyles, css, registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
4
6
 
5
7
  const cardProps = css`
@@ -8,6 +10,8 @@ const cardProps = css`
8
10
  --vaadin-card-border-radius: var(--lumo-border-radius-l);
9
11
  --vaadin-card-border-width: 0;
10
12
  --vaadin-card-border-color: var(--lumo-contrast-20pct);
13
+ --vaadin-card-padding: var(--lumo-space-m);
14
+ --vaadin-card-gap: var(--lumo-space-m);
11
15
  }
12
16
  `;
13
17
 
@@ -26,7 +30,6 @@ const card = css`
26
30
  content: '';
27
31
  position: absolute;
28
32
  inset: 0;
29
- z-index: 999;
30
33
  pointer-events: none;
31
34
  border-radius: inherit;
32
35
  border: var(--vaadin-card-border, var(--vaadin-card-border-width) solid var(--vaadin-card-border-color));
@@ -49,6 +52,23 @@ const card = css`
49
52
  inset 0 -1px 0 0 var(--lumo-shade-10pct),
50
53
  var(--vaadin-card-box-shadow);
51
54
  }
55
+
56
+ :host(:where([theme~='stretch-media'])) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
57
+ border-radius: var(--lumo-border-radius-m);
58
+ }
59
+
60
+ ::slotted([slot='title']) {
61
+ font-size: var(--lumo-font-size-l);
62
+ line-height: var(--lumo-line-height-xs);
63
+ font-weight: 600;
64
+ color: var(--lumo-header-text-color);
65
+ }
66
+
67
+ ::slotted([slot='subtitle']) {
68
+ font-size: var(--lumo-font-size-m);
69
+ line-height: var(--lumo-line-height-xs);
70
+ color: var(--lumo-secondary-text-color);
71
+ }
52
72
  `;
53
73
 
54
74
  registerStyles('vaadin-card', card, { moduleId: 'lumo-card' });
@@ -1,4 +1,5 @@
1
1
  import '@vaadin/vaadin-material-styles/color.js';
2
2
  import '@vaadin/vaadin-material-styles/shadow.js';
3
+ import '@vaadin/vaadin-material-styles/typography.js';
3
4
  declare const card: import("lit").CSSResult;
4
5
  export { card };
@@ -1,5 +1,6 @@
1
1
  import '@vaadin/vaadin-material-styles/color.js';
2
2
  import '@vaadin/vaadin-material-styles/shadow.js';
3
+ import '@vaadin/vaadin-material-styles/typography.js';
3
4
  import { addGlobalThemeStyles, css, registerStyles } from '@vaadin/vaadin-themable-mixin/register-styles.js';
4
5
 
5
6
  const cardProps = css`
@@ -8,6 +9,8 @@ const cardProps = css`
8
9
  --vaadin-card-border-radius: 8px;
9
10
  --vaadin-card-border-width: 0;
10
11
  --vaadin-card-border-color: var(--material-divider-color);
12
+ --vaadin-card-padding: 16px;
13
+ --vaadin-card-gap: 16px;
11
14
  }
12
15
  `;
13
16
 
@@ -26,7 +29,6 @@ const card = css`
26
29
  content: '';
27
30
  position: absolute;
28
31
  inset: 0;
29
- z-index: 999;
30
32
  pointer-events: none;
31
33
  border-radius: inherit;
32
34
  border: var(--vaadin-card-border, var(--vaadin-card-border-width) solid var(--vaadin-card-border-color));
@@ -41,6 +43,19 @@ const card = css`
41
43
  --vaadin-card-background: var(--material-background-color);
42
44
  --vaadin-card-box-shadow: var(--material-shadow-elevation-2dp);
43
45
  }
46
+
47
+ :host(:where([theme~='stretch-media'])) ::slotted([slot='media']:is(img, video, svg, vaadin-icon)) {
48
+ border-radius: 4px;
49
+ }
50
+
51
+ ::slotted([slot='title']) {
52
+ font-size: var(--material-h6-font-size);
53
+ font-weight: 700;
54
+ }
55
+
56
+ ::slotted([slot='subtitle']) {
57
+ color: var(--material-secondary-text-color);
58
+ }
44
59
  `;
45
60
 
46
61
  registerStyles('vaadin-card', card, { moduleId: 'material-card' });
package/web-types.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/card",
4
- "version": "24.7.0-alpha4",
4
+ "version": "24.7.0-alpha6",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
10
  "name": "vaadin-card",
11
- "description": "`<vaadin-card>` is a visual content container.\n\n```html\n<vaadin-card>\n <div>Card content</div>\n</vaadin-card>\n```",
11
+ "description": "`<vaadin-card>` is a versatile container for grouping related content and actions.\nIt presents information in a structured and visually appealing manner, with\ncustomization options to fit various design requirements.\n\n```html\n<vaadin-card theme=\"outlined cover-media\">\n <img slot=\"media\" width=\"200\" src=\"...\" alt=\"\">\n <div slot=\"title\">Lapland</div>\n <div slot=\"subtitle\">The Exotic North</div>\n <div>Lapland is the northern-most region of Finland and an active outdoor destination.</div>\n <vaadin-button slot=\"footer\">Book Vacation</vaadin-button>\n</vaadin-card>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------|-------------\n`media` | The container for the media element (e.g., image, video, icon). Shown above of before the card content.\n`header` | The container for title and subtitle - or for custom header content - and header prefix and suffix elements.\n`content` | The container for the card content (usually text content).\n`footer` | The container for footer elements. This part is always at the bottom of the card.\n\nThe following custom properties are available for styling:\n\nCustom property | Description | Default\n----------------|-------------|-------------\n`--vaadin-card-padding` | The space between the card edge and its content. Needs to a unified value for all edges, i.e., a single length value. | `1em`\n`--vaadin-card-gap` | The space between content elements within the card. | `1em`\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "theme",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/card",
4
- "version": "24.7.0-alpha4",
4
+ "version": "24.7.0-alpha6",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,7 +16,7 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-card",
19
- "description": "`<vaadin-card>` is a visual content container.\n\n```html\n<vaadin-card>\n <div>Card content</div>\n</vaadin-card>\n```",
19
+ "description": "`<vaadin-card>` is a versatile container for grouping related content and actions.\nIt presents information in a structured and visually appealing manner, with\ncustomization options to fit various design requirements.\n\n```html\n<vaadin-card theme=\"outlined cover-media\">\n <img slot=\"media\" width=\"200\" src=\"...\" alt=\"\">\n <div slot=\"title\">Lapland</div>\n <div slot=\"subtitle\">The Exotic North</div>\n <div>Lapland is the northern-most region of Finland and an active outdoor destination.</div>\n <vaadin-button slot=\"footer\">Book Vacation</vaadin-button>\n</vaadin-card>\n```\n\n### Styling\n\nThe following shadow DOM parts are available for styling:\n\nPart name | Description\n----------|-------------\n`media` | The container for the media element (e.g., image, video, icon). Shown above of before the card content.\n`header` | The container for title and subtitle - or for custom header content - and header prefix and suffix elements.\n`content` | The container for the card content (usually text content).\n`footer` | The container for footer elements. This part is always at the bottom of the card.\n\nThe following custom properties are available for styling:\n\nCustom property | Description | Default\n----------------|-------------|-------------\n`--vaadin-card-padding` | The space between the card edge and its content. Needs to a unified value for all edges, i.e., a single length value. | `1em`\n`--vaadin-card-gap` | The space between content elements within the card. | `1em`\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
20
  "extension": true,
21
21
  "attributes": []
22
22
  }