@vaadin/card 24.8.0-alpha4 → 24.8.0-alpha5

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.8.0-alpha4",
3
+ "version": "24.8.0-alpha5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,15 +34,15 @@
34
34
  "web-component"
35
35
  ],
36
36
  "dependencies": {
37
- "@vaadin/component-base": "24.8.0-alpha4",
38
- "@vaadin/vaadin-lumo-styles": "24.8.0-alpha4",
39
- "@vaadin/vaadin-material-styles": "24.8.0-alpha4",
40
- "@vaadin/vaadin-themable-mixin": "24.8.0-alpha4",
37
+ "@vaadin/component-base": "24.8.0-alpha5",
38
+ "@vaadin/vaadin-lumo-styles": "24.8.0-alpha5",
39
+ "@vaadin/vaadin-material-styles": "24.8.0-alpha5",
40
+ "@vaadin/vaadin-themable-mixin": "24.8.0-alpha5",
41
41
  "lit": "^3.0.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@vaadin/chai-plugins": "24.8.0-alpha4",
45
- "@vaadin/test-runner-commands": "24.8.0-alpha4",
44
+ "@vaadin/chai-plugins": "24.8.0-alpha5",
45
+ "@vaadin/test-runner-commands": "24.8.0-alpha5",
46
46
  "@vaadin/testing-helpers": "^1.1.0",
47
47
  "sinon": "^18.0.0"
48
48
  },
@@ -50,5 +50,5 @@
50
50
  "web-types.json",
51
51
  "web-types.lit.json"
52
52
  ],
53
- "gitHead": "88251b4c84ebb8849dde982acb62cc2b20eeec31"
53
+ "gitHead": "3bb64b9ad9b00ac3adb94eb1bedd81b0f4ae574e"
54
54
  }
@@ -9,10 +9,10 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
9
9
  /**
10
10
  * `<vaadin-card>` is a versatile container for grouping related content and actions.
11
11
  * It presents information in a structured and visually appealing manner, with
12
- * customization options to fit various design requirements.
12
+ * customization options to fit various design requirements. The default ARIA role is `region`.
13
13
  *
14
14
  * ```html
15
- * <vaadin-card theme="outlined cover-media">
15
+ * <vaadin-card role="region" theme="outlined cover-media">
16
16
  * <img slot="media" width="200" src="..." alt="">
17
17
  * <div slot="title">Lapland</div>
18
18
  * <div slot="subtitle">The Exotic North</div>
@@ -41,7 +41,19 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
41
41
  *
42
42
  * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
43
43
  */
44
- declare class Card extends ElementMixin(ThemableMixin(HTMLElement)) {}
44
+ declare class Card extends ElementMixin(ThemableMixin(HTMLElement)) {
45
+ /**
46
+ * The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.
47
+ * @attr {string} card-title
48
+ */
49
+ cardTitle: string;
50
+
51
+ /**
52
+ * Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.
53
+ * @attr {number} title-heading-level
54
+ */
55
+ titleHeadingLevel: number | null | undefined;
56
+ }
45
57
 
46
58
  declare global {
47
59
  interface HTMLElementTagNameMap {
@@ -7,15 +7,16 @@ import { css, html, LitElement } from 'lit';
7
7
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
8
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
9
9
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
10
+ import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
10
11
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
12
 
12
13
  /**
13
14
  * `<vaadin-card>` is a versatile container for grouping related content and actions.
14
15
  * It presents information in a structured and visually appealing manner, with
15
- * customization options to fit various design requirements.
16
+ * customization options to fit various design requirements. The default ARIA role is `region`.
16
17
  *
17
18
  * ```html
18
- * <vaadin-card theme="outlined cover-media">
19
+ * <vaadin-card role="region" theme="outlined cover-media">
19
20
  * <img slot="media" width="200" src="..." alt="">
20
21
  * <div slot="title">Lapland</div>
21
22
  * <div slot="subtitle">The Exotic North</div>
@@ -279,10 +280,47 @@ class Card extends ElementMixin(ThemableMixin(PolylitMixin(LitElement))) {
279
280
  `;
280
281
  }
281
282
 
283
+ static get properties() {
284
+ return {
285
+ /**
286
+ * The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.
287
+ *
288
+ * @attr {string} card-title
289
+ */
290
+ cardTitle: {
291
+ type: String,
292
+ notify: true,
293
+ observer: '__cardTitleChanged',
294
+ },
295
+
296
+ /**
297
+ * Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.
298
+ *
299
+ * @attr {number} title-heading-level
300
+ */
301
+ titleHeadingLevel: {
302
+ type: Number,
303
+ reflectToAttribute: true,
304
+ observer: '__titleHeadingLevelChanged',
305
+ },
306
+ };
307
+ }
308
+
282
309
  static get experimental() {
283
310
  return true;
284
311
  }
285
312
 
313
+ /** @protected */
314
+ ready() {
315
+ super.ready();
316
+
317
+ // By default, if the user hasn't provided a custom role,
318
+ // the role attribute is set to "region".
319
+ if (!this.hasAttribute('role')) {
320
+ this.setAttribute('role', 'region');
321
+ }
322
+ }
323
+
286
324
  /** @protected */
287
325
  render() {
288
326
  return html`
@@ -322,6 +360,79 @@ class Card extends ElementMixin(ThemableMixin(PolylitMixin(LitElement))) {
322
360
  this.toggleAttribute('_hs', this.querySelector(':scope > [slot="header-suffix"]'));
323
361
  this.toggleAttribute('_c', this.querySelector(':scope > :not([slot])'));
324
362
  this.toggleAttribute('_f', this.querySelector(':scope > [slot="footer"]'));
363
+ if (this.__getCustomTitleElement()) {
364
+ this.__clearStringTitle();
365
+ }
366
+ }
367
+
368
+ /** @private */
369
+ __clearStringTitle() {
370
+ const stringTitleElement = this.__getStringTitleElement();
371
+ if (stringTitleElement) {
372
+ this.removeChild(stringTitleElement);
373
+ }
374
+ const ariaLabelledby = this.getAttribute('aria-labelledby');
375
+ if (ariaLabelledby && ariaLabelledby.startsWith('card-title-')) {
376
+ this.removeAttribute('aria-labelledby');
377
+ }
378
+ if (this.cardTitle) {
379
+ this.cardTitle = '';
380
+ }
381
+ }
382
+
383
+ /** @private */
384
+ __getCustomTitleElement() {
385
+ return Array.from(this.querySelectorAll('[slot="title"]')).find((el) => {
386
+ return !el.hasAttribute('card-string-title');
387
+ });
388
+ }
389
+
390
+ /** @private */
391
+ __cardTitleChanged(title) {
392
+ if (!title) {
393
+ this.__clearStringTitle();
394
+ return;
395
+ }
396
+ const customTitleElement = this.__getCustomTitleElement();
397
+ if (customTitleElement) {
398
+ this.removeChild(customTitleElement);
399
+ }
400
+ let stringTitleElement = this.__getStringTitleElement();
401
+ if (!stringTitleElement) {
402
+ stringTitleElement = this.__createStringTitleElement();
403
+ this.appendChild(stringTitleElement);
404
+ this.setAttribute('aria-labelledby', stringTitleElement.id);
405
+ }
406
+ stringTitleElement.textContent = title;
407
+ }
408
+
409
+ /** @private */
410
+ __createStringTitleElement() {
411
+ const stringTitleElement = document.createElement('div');
412
+ stringTitleElement.setAttribute('slot', 'title');
413
+ stringTitleElement.setAttribute('role', 'heading');
414
+ this.__setTitleHeadingLevel(stringTitleElement, this.titleHeadingLevel);
415
+ stringTitleElement.setAttribute('card-string-title', '');
416
+ stringTitleElement.id = `card-title-${generateUniqueId()}`;
417
+ return stringTitleElement;
418
+ }
419
+
420
+ /** @private */
421
+ __titleHeadingLevelChanged(titleHeadingLevel) {
422
+ const stringTitleElement = this.__getStringTitleElement();
423
+ if (stringTitleElement) {
424
+ this.__setTitleHeadingLevel(stringTitleElement, titleHeadingLevel);
425
+ }
426
+ }
427
+
428
+ /** @private */
429
+ __setTitleHeadingLevel(stringTitleElement, titleHeadingLevel) {
430
+ stringTitleElement.setAttribute('aria-level', titleHeadingLevel || 2);
431
+ }
432
+
433
+ /** @private */
434
+ __getStringTitleElement() {
435
+ return this.querySelector('[slot="title"][card-string-title]');
325
436
  }
326
437
 
327
438
  /**
package/web-types.json CHANGED
@@ -1,15 +1,37 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/card",
4
- "version": "24.8.0-alpha4",
4
+ "version": "24.8.0-alpha5",
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 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.",
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. The default ARIA role is `region`.\n\n```html\n<vaadin-card role=\"region\" 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
+ {
14
+ "name": "card-title",
15
+ "description": "The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.",
16
+ "value": {
17
+ "type": [
18
+ "string",
19
+ "null",
20
+ "undefined"
21
+ ]
22
+ }
23
+ },
24
+ {
25
+ "name": "title-heading-level",
26
+ "description": "Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.",
27
+ "value": {
28
+ "type": [
29
+ "number",
30
+ "null",
31
+ "undefined"
32
+ ]
33
+ }
34
+ },
13
35
  {
14
36
  "name": "theme",
15
37
  "description": "The theme variants to apply to the component.",
@@ -23,8 +45,36 @@
23
45
  }
24
46
  ],
25
47
  "js": {
26
- "properties": [],
27
- "events": []
48
+ "properties": [
49
+ {
50
+ "name": "cardTitle",
51
+ "description": "The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.",
52
+ "value": {
53
+ "type": [
54
+ "string",
55
+ "null",
56
+ "undefined"
57
+ ]
58
+ }
59
+ },
60
+ {
61
+ "name": "titleHeadingLevel",
62
+ "description": "Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.",
63
+ "value": {
64
+ "type": [
65
+ "number",
66
+ "null",
67
+ "undefined"
68
+ ]
69
+ }
70
+ }
71
+ ],
72
+ "events": [
73
+ {
74
+ "name": "card-title-changed",
75
+ "description": "Fired when the `cardTitle` property changes."
76
+ }
77
+ ]
28
78
  }
29
79
  }
30
80
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/card",
4
- "version": "24.8.0-alpha4",
4
+ "version": "24.8.0-alpha5",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,9 +16,31 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-card",
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.",
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. The default ARIA role is `region`.\n\n```html\n<vaadin-card role=\"region\" 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
- "attributes": []
21
+ "attributes": [
22
+ {
23
+ "name": ".cardTitle",
24
+ "description": "The title of the card. When set, any custom slotted title is removed and this string-based title is used instead. If this title is used, an `aria-labelledby` attribute that points to the generated title element is set.",
25
+ "value": {
26
+ "kind": "expression"
27
+ }
28
+ },
29
+ {
30
+ "name": ".titleHeadingLevel",
31
+ "description": "Sets the heading level (`aria-level`) for the string-based title. If not set, the level defaults to 2. Setting values outside the range [1, 6] can cause accessibility issues.",
32
+ "value": {
33
+ "kind": "expression"
34
+ }
35
+ },
36
+ {
37
+ "name": "@card-title-changed",
38
+ "description": "Fired when the `cardTitle` property changes.",
39
+ "value": {
40
+ "kind": "expression"
41
+ }
42
+ }
43
+ ]
22
44
  }
23
45
  ]
24
46
  }