q2-tecton-elements 1.73.0 → 1.73.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 (94) hide show
  1. package/dist/bundle-report.json +16 -21
  2. package/dist/cjs/q2-avatar.cjs.entry.js +34 -1
  3. package/dist/cjs/q2-badge_2.cjs.entry.js +1 -1
  4. package/dist/cjs/q2-checkbox_2.cjs.entry.js +1 -1
  5. package/dist/cjs/q2-message.cjs.entry.js +1 -1
  6. package/dist/cjs/q2-pagination.cjs.entry.js +11 -5
  7. package/dist/cjs/q2-pill.cjs.entry.js +2 -2
  8. package/dist/cjs/q2-relative-time.cjs.entry.js +1 -1
  9. package/dist/cjs/q2-resize-observer.cjs.entry.js +1 -1
  10. package/dist/cjs/q2-search.cjs.entry.js +1 -1
  11. package/dist/cjs/q2-section.cjs.entry.js +2 -2
  12. package/dist/cjs/q2-stepper-pane.cjs.entry.js +1 -1
  13. package/dist/cjs/q2-stepper-vertical.cjs.entry.js +1 -1
  14. package/dist/cjs/q2-stepper.cjs.entry.js +1 -1
  15. package/dist/cjs/q2-surface.cjs.entry.js +1 -1
  16. package/dist/cjs/q2-tab-container.cjs.entry.js +1 -1
  17. package/dist/cjs/q2-tab-pane.cjs.entry.js +1 -1
  18. package/dist/cjs/tecton-tab-pane.cjs.entry.js +2 -2
  19. package/dist/collection/components/q2-avatar/q2-avatar.js +34 -1
  20. package/dist/collection/components/q2-avatar/test/q2-avatar-test.vr.js +79 -4
  21. package/dist/collection/components/q2-input/formatting/phone-number-formats.js +1 -1
  22. package/dist/collection/components/q2-message/q2-message.css +1 -1
  23. package/dist/collection/components/q2-message/test/q2-message-test.vr.js +11 -2
  24. package/dist/collection/components/q2-pagination/q2-pagination.css +17 -0
  25. package/dist/collection/components/q2-pagination/q2-pagination.js +10 -4
  26. package/dist/collection/components/q2-pagination/test/q2-pagination-test.vr.js +39 -0
  27. package/dist/collection/components/q2-pill/q2-pill.css +14 -10
  28. package/dist/collection/components/q2-pill/q2-pill.js +1 -1
  29. package/dist/collection/components/q2-pill/test/q2-pill-test.vr.js +25 -0
  30. package/dist/collection/components/q2-relative-time/q2-relative-time.js +1 -1
  31. package/dist/collection/components/q2-resize-observer/q2-resize-observer.js +1 -1
  32. package/dist/collection/components/q2-search/q2-search.js +1 -1
  33. package/dist/collection/components/q2-section/q2-section.js +2 -2
  34. package/dist/collection/components/q2-stepper/q2-stepper.js +1 -1
  35. package/dist/collection/components/q2-stepper-pane/q2-stepper-pane.js +1 -1
  36. package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.js +1 -1
  37. package/dist/collection/components/q2-surface/q2-surface.js +1 -1
  38. package/dist/collection/components/q2-tab-container/q2-tab-container.js +1 -1
  39. package/dist/collection/components/q2-tab-pane/q2-tab-pane.js +1 -1
  40. package/dist/collection/components/q2-tag/q2-tag.js +1 -1
  41. package/dist/collection/components/tecton-tab-pane/tecton-tab-pane.js +2 -2
  42. package/dist/components/q2-avatar2.js +41 -27
  43. package/dist/components/q2-input2.js +1 -1
  44. package/dist/components/q2-message2.js +1 -1
  45. package/dist/components/q2-pagination.js +37 -35
  46. package/dist/components/q2-pill.js +43 -40
  47. package/dist/components/q2-relative-time.js +1 -1
  48. package/dist/components/q2-resize-observer2.js +23 -23
  49. package/dist/components/q2-search.js +4 -4
  50. package/dist/components/q2-section.js +15 -15
  51. package/dist/components/q2-stepper-pane.js +29 -29
  52. package/dist/components/q2-stepper-vertical.js +4 -4
  53. package/dist/components/q2-stepper.js +12 -12
  54. package/dist/components/q2-surface.js +3 -3
  55. package/dist/components/q2-tab-container.js +16 -16
  56. package/dist/components/q2-tab-pane.js +6 -6
  57. package/dist/components/q2-tag2.js +5 -5
  58. package/dist/components/tecton-tab-pane.js +6 -6
  59. package/dist/esm/q2-avatar.entry.js +34 -1
  60. package/dist/esm/q2-badge_2.entry.js +1 -1
  61. package/dist/esm/q2-checkbox_2.entry.js +1 -1
  62. package/dist/esm/q2-message.entry.js +1 -1
  63. package/dist/esm/q2-pagination.entry.js +11 -5
  64. package/dist/esm/q2-pill.entry.js +2 -2
  65. package/dist/esm/q2-relative-time.entry.js +1 -1
  66. package/dist/esm/q2-resize-observer.entry.js +1 -1
  67. package/dist/esm/q2-search.entry.js +1 -1
  68. package/dist/esm/q2-section.entry.js +2 -2
  69. package/dist/esm/q2-stepper-pane.entry.js +1 -1
  70. package/dist/esm/q2-stepper-vertical.entry.js +1 -1
  71. package/dist/esm/q2-stepper.entry.js +1 -1
  72. package/dist/esm/q2-surface.entry.js +1 -1
  73. package/dist/esm/q2-tab-container.entry.js +1 -1
  74. package/dist/esm/q2-tab-pane.entry.js +1 -1
  75. package/dist/esm/tecton-tab-pane.entry.js +2 -2
  76. package/dist/q2-tecton-elements/q2-avatar.entry.js +24 -10
  77. package/dist/q2-tecton-elements/q2-badge_2.entry.js +1 -1
  78. package/dist/q2-tecton-elements/q2-checkbox_2.entry.js +5 -5
  79. package/dist/q2-tecton-elements/q2-message.entry.js +1 -1
  80. package/dist/q2-tecton-elements/q2-pagination.entry.js +51 -49
  81. package/dist/q2-tecton-elements/q2-pill.entry.js +38 -35
  82. package/dist/q2-tecton-elements/q2-relative-time.entry.js +4 -4
  83. package/dist/q2-tecton-elements/q2-resize-observer.entry.js +1 -1
  84. package/dist/q2-tecton-elements/q2-search.entry.js +30 -30
  85. package/dist/q2-tecton-elements/q2-section.entry.js +11 -11
  86. package/dist/q2-tecton-elements/q2-stepper-pane.entry.js +12 -12
  87. package/dist/q2-tecton-elements/q2-stepper-vertical.entry.js +4 -4
  88. package/dist/q2-tecton-elements/q2-stepper.entry.js +12 -12
  89. package/dist/q2-tecton-elements/q2-surface.entry.js +15 -15
  90. package/dist/q2-tecton-elements/q2-tab-container.entry.js +14 -14
  91. package/dist/q2-tecton-elements/q2-tab-pane.entry.js +4 -4
  92. package/dist/q2-tecton-elements/tecton-tab-pane.entry.js +9 -9
  93. package/dist/types/components/q2-avatar/q2-avatar.d.ts +5 -0
  94. package/package.json +3 -3
@@ -57,9 +57,9 @@ const TectonTabPane = class {
57
57
  // #endregion
58
58
  // #region Render Methods
59
59
  render() {
60
- return (index.h("div", { key: 'b55643965ef49af2e41a683686db00b97e1c90b7', id: `tab-pane-${this.guid}-${this.index}`, class: `tab-pane${this.selected ? '' : ' hidden'}`, role: "tabpanel", tabindex: "-1", "aria-hidden": `${!this.selected}`, "aria-labelledby": `tab-${this.guid}-${this.index}` }, this.selected && this.provided !== undefined && !this.provided && (index.h("div", { key: 'f04f1594eba66d962d9adbab48bf3559f658c650' }, index.h("slot", { key: '08804102412a6b57ac9b9db2002d1608f8b22c19', name: "loading-wrapper" }), index.h("iframe", { key: 'a2524435de8072fb27ebdcc9762a1f20367df098', hidden: true, name: this.moduleId, scrolling: "no", src: this.showForm && this.authPayload.length ? '' : this.url || '', "data-module-id": this.moduleId, style: this.minHeight ? { minHeight: this.minHeight } : null, onLoad: this.onIFrameLoad, title: this.iframeTitle, allow: "geolocation; camera" }), this._showForm && this.authPayload ? (index.h("form", { hidden: true, method: "post", action: this.url, target: this.moduleId, encType: "multipart/form-data" }, this.authPayload.map(element => {
60
+ return (index.h("div", { key: '313fa13779cd8ecb5439b1a96cb7aaf17f6c871b', id: `tab-pane-${this.guid}-${this.index}`, class: `tab-pane${this.selected ? '' : ' hidden'}`, role: "tabpanel", tabindex: "-1", "aria-hidden": `${!this.selected}`, "aria-labelledby": `tab-${this.guid}-${this.index}` }, this.selected && this.provided !== undefined && !this.provided && (index.h("div", { key: '5207414b205d1e9a25fb1455ca21ff7cc913a5fd' }, index.h("slot", { key: 'd883e909e38981f315bc1cab9ef57957a616c0d5', name: "loading-wrapper" }), index.h("iframe", { key: '2f0233d04d3c5be619cb54bfe637252a7ef42d77', hidden: true, name: this.moduleId, scrolling: "no", src: this.showForm && this.authPayload.length ? '' : this.url || '', "data-module-id": this.moduleId, style: this.minHeight ? { minHeight: this.minHeight } : null, onLoad: this.onIFrameLoad, title: this.iframeTitle, allow: "geolocation; camera" }), this._showForm && this.authPayload ? (index.h("form", { hidden: true, method: "post", action: this.url, target: this.moduleId, encType: "multipart/form-data" }, this.authPayload.map(element => {
61
61
  return (index.h("input", { type: "hidden", value: element.value, name: element.key }));
62
- }))) : (''))), index.h("div", { key: '59e9d5ddbabadb0e66615d998403d267c259f937', class: "slot-wrapper", hidden: this.selected && this.provided !== undefined && !this.provided }, index.h("slot", { key: '450c5724cf32ba05a2fc93b8adeba83b08e871e4' }))));
62
+ }))) : (''))), index.h("div", { key: 'ae5ee8d5a5a7d1b798f4111b33120d301b86a16b', class: "slot-wrapper", hidden: this.selected && this.provided !== undefined && !this.provided }, index.h("slot", { key: 'cb1057d2b6cb467a25da1577610bfcc5b6300047' }))));
63
63
  }
64
64
  get hostElement() { return index.getElement(this); }
65
65
  static get watchers() { return {
@@ -8,6 +8,7 @@ import { h } from "@stencil/core";
8
8
  */
9
9
  export class Q2Avatar {
10
10
  constructor() {
11
+ this.initialsFontScale = 1;
11
12
  // #endregion
12
13
  // #region State Properties
13
14
  this.badSrc = false;
@@ -29,9 +30,11 @@ export class Q2Avatar {
29
30
  // #endregion
30
31
  // #region Component Lifecycle Events
31
32
  disconnectedCallback() {
33
+ var _a;
32
34
  if (this.decoratorObserver) {
33
35
  this.decoratorObserver.disconnect();
34
36
  }
37
+ (_a = this.initialsResizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
35
38
  }
36
39
  componentWillLoad() {
37
40
  this.checkDecorator();
@@ -39,6 +42,20 @@ export class Q2Avatar {
39
42
  componentDidLoad() {
40
43
  this.setupDecoratorObserver();
41
44
  }
45
+ componentDidRender() {
46
+ var _a, _b, _c;
47
+ const text = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.avatar-initials text');
48
+ if (text !== this.observedInitialsText) {
49
+ (_b = this.initialsResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
50
+ this.observedInitialsText = text;
51
+ this.initialsFontScale = 1;
52
+ if (text && typeof ResizeObserver === 'function') {
53
+ (_c = this.initialsResizeObserver) !== null && _c !== void 0 ? _c : (this.initialsResizeObserver = new ResizeObserver(() => this.fitInitials()));
54
+ this.initialsResizeObserver.observe(text);
55
+ }
56
+ }
57
+ this.fitInitials();
58
+ }
42
59
  // #endregion
43
60
  // #region Watchers
44
61
  srcDidUpdate() {
@@ -69,6 +86,22 @@ export class Q2Avatar {
69
86
  const decoratorElements = Array.from(this.el.children).filter(child => child.getAttribute('slot') === 'decorator');
70
87
  this.hasDecorator = decoratorElements.length > 0;
71
88
  }
89
+ fitInitials() {
90
+ const text = this.observedInitialsText;
91
+ if (!text)
92
+ return;
93
+ const { x, y, width, height } = text.getBBox();
94
+ const requiredHalfExtent = Math.max(50 - x, x + width - 50, 50 - y, y + height - 50);
95
+ const baseHalfExtent = requiredHalfExtent / this.initialsFontScale;
96
+ const scale = baseHalfExtent > 50 ? 48 / baseHalfExtent : 1;
97
+ if (Math.abs(scale - this.initialsFontScale) < 0.00001)
98
+ return;
99
+ this.initialsFontScale = scale;
100
+ if (scale === 1)
101
+ text.style.removeProperty('font-size');
102
+ else
103
+ text.style.fontSize = `calc(var(--tct-avatar-font-size, var(--const-px-40, 40px)) * ${scale})`;
104
+ }
72
105
  setupDecoratorObserver() {
73
106
  // Set up MutationObserver to watch for changes to the host element's children
74
107
  this.decoratorObserver = new MutationObserver(() => {
@@ -90,7 +123,7 @@ export class Q2Avatar {
90
123
  const isLoaded = this.isLoaded;
91
124
  const showInitials = (this.name || this.initials) && (!this.src || this.badSrc);
92
125
  const showFallback = !this.name && !this.initials && (!this.src || this.badSrc);
93
- return (h("div", { key: '2a10f13b2ca606dab3563d026910d909e37ddcb0', class: `avatar-wrapper size-${this.size}` }, this.hasDecorator && (h("div", { key: 'e5deb3da74508a5731238724895ca9f1ab8b7a50', class: "decorator" }, h("slot", { key: '3cc01e88891a09f7917416a0acd0940e79decf26', name: "decorator" }))), showImg && (h("img", { key: 'cbed4e936072bca7bd23bd18b8679d0539c3fbd2', class: `${isLoaded ? 'avatar-img' : 'avatar-img-default'}`, "test-id": "userImage", src: this.src, onError: this.onError, onLoad: this.onLoad, alt: this.name || '' })), showInitials && (h("svg", { key: 'f1876a7748d3806e21e48f3de7b70c6faea499ca', viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid meet", "test-id": "userInitials", class: `avatar-initials initials-size-${computedInitials.length}`, "aria-label": this.name, "aria-hidden": !this.name && 'true' }, h("text", { key: 'a120d991968334f383efcb9d5ef920c7ee542880', x: "50", y: "50", "dominant-baseline": "central", "text-anchor": "middle", "aria-hidden": "true" }, computedInitials))), showFallback && (h("div", { key: '598457dc937327172221fab317246d1085a57b02', "test-id": "fallbackIcon", class: "fallback" }, h("q2-icon", { key: '578836c985252ea19c06d5499e6ad8f9c311e09f', type: this.icon })))));
126
+ return (h("div", { key: 'd5a32129734a7923c61ecfbace6af0799051b8c9', class: `avatar-wrapper size-${this.size}` }, this.hasDecorator && (h("div", { key: 'a20e35425d03a0b45df79846b1613be993935bab', class: "decorator" }, h("slot", { key: '082a7d3022be63825ac0237b0f458eb3fc328737', name: "decorator" }))), showImg && (h("img", { key: 'bc092a5fe3996d53f89bc69146aceb2af53b571a', class: `${isLoaded ? 'avatar-img' : 'avatar-img-default'}`, "test-id": "userImage", src: this.src, onError: this.onError, onLoad: this.onLoad, alt: this.name || '' })), showInitials && (h("svg", { key: '385335ea2b6d35d48179cbea4aa3ac3d99e56093', viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid meet", "test-id": "userInitials", class: `avatar-initials initials-size-${computedInitials.length}`, "aria-label": this.name, "aria-hidden": !this.name && 'true' }, h("text", { key: 'fb331a07ddc746787341e31febcf2a267f8f0e33', x: "50", y: "50", "dominant-baseline": "central", "text-anchor": "middle", "aria-hidden": "true" }, computedInitials))), showFallback && (h("div", { key: 'da7a75cc5e5b4e62eeaa63c399ed0dc6c869e99c', "test-id": "fallbackIcon", class: "fallback" }, h("q2-icon", { key: '626219dd1528fa7e39d298856be8205f21a6708e', type: this.icon })))));
94
127
  }
95
128
  static get is() { return "q2-avatar"; }
96
129
  static get encapsulation() { return "shadow"; }
@@ -3,6 +3,10 @@ import { test } from "@stencil/playwright";
3
3
  import { setupPage, THEMES, FONT_SCALE_PX, FONT_SCALE_SUFFIX } from "../../../utils/test/vr-helpers";
4
4
  // Inline 2x2 solid-blue PNG — keeps the image variant hermetic (no network).
5
5
  const IMAGE_DATA_URI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVQI12NkYGD4z8DAwMTAwMDAAAALzAEFwQ7e7AAAAABJRU5ErkJggg==';
6
+ const waitForInitialsToSettle = (page) => page.evaluate(async () => {
7
+ await document.fonts.ready;
8
+ await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
9
+ });
6
10
  const VARIANTS = [
7
11
  {
8
12
  name: 'icon-small',
@@ -30,7 +34,7 @@ const VARIANTS = [
30
34
  },
31
35
  {
32
36
  name: 'initials-4',
33
- html: `<q2-avatar initials="LSMA"></q2-avatar>`,
37
+ html: `<q2-avatar initials="WWWW"></q2-avatar>`,
34
38
  },
35
39
  {
36
40
  name: 'image',
@@ -48,7 +52,9 @@ const VARIANTS = [
48
52
  const restingCase = (variant, theme) => {
49
53
  test(`q2-avatar--${variant.name}--resting — ${theme}`, async ({ page }) => {
50
54
  await setupPage(page, variant.html, { theme });
51
- await expect(page).toHaveScreenshot(`q2-avatar--${variant.name}--resting--${theme}.png`);
55
+ if (variant.name.startsWith('initials-'))
56
+ await waitForInitialsToSettle(page);
57
+ await expect(page).toHaveScreenshot(`q2-avatar--${variant.name}--resting--${theme}.png`, variant.name === 'initials-4' ? { maxDiffPixels: 50 } : undefined);
52
58
  });
53
59
  };
54
60
  test.describe('q2-avatar — variants × themes', () => {
@@ -59,14 +65,83 @@ test.describe('q2-avatar — variants × themes', () => {
59
65
  }
60
66
  });
61
67
  // Initials variants exercise --tct-avatar-font-size (SVG text element).
62
- const AVATAR_FONT_SCALE_VARIANTS = VARIANTS.filter(v => v.name === 'initials-1');
68
+ const AVATAR_FONT_SCALE_VARIANTS = VARIANTS.filter(v => v.name.startsWith('initials-'));
63
69
  test.describe(`q2-avatar — scaled font size × themes`, () => {
64
70
  for (const variant of AVATAR_FONT_SCALE_VARIANTS) {
65
71
  for (const theme of THEMES) {
66
72
  test(`q2-avatar--${variant.name}--resting--${FONT_SCALE_SUFFIX} — ${theme}`, async ({ page }) => {
67
73
  await setupPage(page, variant.html, { theme, fontSizePx: FONT_SCALE_PX });
68
- await expect(page).toHaveScreenshot(`q2-avatar--${variant.name}--resting--${FONT_SCALE_SUFFIX}--${theme}.png`);
74
+ await waitForInitialsToSettle(page);
75
+ await expect(page).toHaveScreenshot(`q2-avatar--${variant.name}--resting--${FONT_SCALE_SUFFIX}--${theme}.png`, variant.name === 'initials-4' ? { maxDiffPixels: 50 } : undefined);
69
76
  });
70
77
  }
71
78
  }
72
79
  });
80
+ test.describe('q2-avatar — initials fit inside the circle', () => {
81
+ for (const theme of THEMES) {
82
+ test(`q2-avatar--initials-fit — ${theme}`, async ({ page }) => {
83
+ const html = ['small', 'medium', 'large']
84
+ .map(size => `<div style="display: flex; gap: 8px; margin-bottom: 16px">
85
+ ${['E', 'ES', 'ESS', 'ESSS', 'LSMA', 'W', 'WW', 'WWW', 'WWWW']
86
+ .map(initials => `<q2-avatar size="${size}" initials="${initials}"></q2-avatar>`)
87
+ .join('')}
88
+ </div>`)
89
+ .join('');
90
+ await setupPage(page, html, { theme, fontSizePx: FONT_SCALE_PX });
91
+ await expect
92
+ .poll(() => page.locator('q2-avatar text').evaluateAll(elements => elements.every(element => {
93
+ const { x, y, width, height } = element.getBBox();
94
+ return x >= 0 && x + width <= 100 && y >= 0 && y + height <= 100;
95
+ })))
96
+ .toBe(true);
97
+ const bounds = await page.locator('q2-avatar text').evaluateAll(elements => elements.map(element => {
98
+ const { x, y, width, height } = element.getBBox();
99
+ return {
100
+ initials: element.textContent,
101
+ x,
102
+ y,
103
+ right: x + width,
104
+ bottom: y + height,
105
+ };
106
+ }));
107
+ for (const { initials, x, y, right, bottom } of bounds) {
108
+ expect(x, `${initials} left edge`).toBeGreaterThanOrEqual(-0.25);
109
+ expect(right, `${initials} right edge`).toBeLessThanOrEqual(100.25);
110
+ expect(y, `${initials} top edge`).toBeGreaterThanOrEqual(-0.25);
111
+ expect(bottom, `${initials} bottom edge`).toBeLessThanOrEqual(100.25);
112
+ }
113
+ });
114
+ }
115
+ });
116
+ test('q2-avatar — initials fit at font-32 root size', async ({ page }) => {
117
+ const html = ['small', 'medium', 'large']
118
+ .map(size => `<div style="display: flex; gap: 8px; margin-bottom: 16px">
119
+ ${['ES', 'ESS', 'LSM', 'LSMA', 'WWWW']
120
+ .map(initials => `<q2-avatar size="${size}" initials="${initials}"></q2-avatar>`)
121
+ .join('')}
122
+ </div>`)
123
+ .join('');
124
+ // Set the font size before hydration, as a browser preference would be.
125
+ await setupPage(page, `<style>html { font-size: 32px; --t-px-1: calc(1 / 16 * 1rem); }</style>${html}`, {
126
+ theme: 'standard',
127
+ });
128
+ expect(await page.evaluate(() => getComputedStyle(document.documentElement).fontSize)).toBe('32px');
129
+ const allInitialsFit = () => page.locator('q2-avatar text').evaluateAll(elements => elements.every(element => {
130
+ const { x, y, width, height } = element.getBBox();
131
+ return x >= 0 && x + width <= 100 && y >= 0 && y + height <= 100;
132
+ }));
133
+ await expect.poll(allInitialsFit).toBe(true);
134
+ const bounds = await page.locator('q2-avatar text').evaluateAll(elements => elements.map(element => {
135
+ const { x, y, width, height } = element.getBBox();
136
+ return { initials: element.textContent, x, y, right: x + width, bottom: y + height };
137
+ }));
138
+ for (const { initials, x, y, right, bottom } of bounds) {
139
+ expect(x, `${initials} left edge`).toBeGreaterThanOrEqual(0);
140
+ expect(right, `${initials} right edge`).toBeLessThanOrEqual(100);
141
+ expect(y, `${initials} top edge`).toBeGreaterThanOrEqual(0);
142
+ expect(bottom, `${initials} bottom edge`).toBeLessThanOrEqual(100);
143
+ }
144
+ // Also verify an already-rendered avatar refits when the font scale changes.
145
+ await page.evaluate(() => document.documentElement.style.setProperty('--t-px-1', '3px'));
146
+ await expect.poll(allInitialsFit).toBe(true);
147
+ });
@@ -412,7 +412,7 @@ export const phoneNumberFormats = {
412
412
  prefix: '+44 ',
413
413
  },
414
414
  IN: {
415
- mask: '###### #####',
415
+ mask: '##### #####?',
416
416
  prefix: '+91 ',
417
417
  },
418
418
  IO: {
@@ -161,8 +161,8 @@ button {
161
161
 
162
162
  .message-content {
163
163
  flex: 1;
164
- line-height: var(--comp-line-height);
165
164
  font-size: var(--tct-message-font-size, inherit);
165
+ line-height: max(1.2em, var(--comp-line-height));
166
166
  }
167
167
 
168
168
  ::slotted(ul) {
@@ -40,11 +40,20 @@ const VARIANTS = [
40
40
  name: 'long-content',
41
41
  html: `<q2-message type="info">${LONG_BODY}</q2-message>`,
42
42
  },
43
+ ...[200, 400].map(scale => ({
44
+ name: `font-scale-${scale}-percent`,
45
+ fontSizePx: (16 * scale) / 100,
46
+ html: '<q2-message type="error" style="--tct-message-font-size: 1rem; --tct-message-line-height: 20px">Please fill out all required fields. Read More</q2-message>',
47
+ })),
43
48
  ];
44
49
  const restingCase = (variant, theme) => {
45
50
  test(`q2-message--${variant.name}--resting — ${theme}`, async ({ page }) => {
46
- await setupPage(page, variant.html, { theme, setupLoc: true });
47
- await expect(page).toHaveScreenshot(`q2-message--${variant.name}--resting--${theme}.png`);
51
+ if (variant.fontSizePx)
52
+ await page.setViewportSize({ width: 375, height: 812 });
53
+ await setupPage(page, variant.html, { theme, setupLoc: true, fontSizePx: variant.fontSizePx });
54
+ await expect(page).toHaveScreenshot(`q2-message--${variant.name}--resting--${theme}.png`, {
55
+ fullPage: !!variant.fontSizePx,
56
+ });
48
57
  });
49
58
  };
50
59
  test.describe('q2-message — variants × themes', () => {
@@ -163,6 +163,23 @@ button {
163
163
  --tct-select-margin: 0;
164
164
  width: var(--tct-pagination-perpage-width, 60%);
165
165
  }
166
+ .container.small {
167
+ flex-wrap: wrap;
168
+ row-gap: var(--tct-pagination-row-gap, var(--app-scale-2x, 10px));
169
+ height: auto;
170
+ max-width: 100%;
171
+ }
172
+ .container.small .description {
173
+ flex-basis: 100%;
174
+ min-width: 0;
175
+ overflow-wrap: anywhere;
176
+ text-align: center;
177
+ white-space: normal;
178
+ line-height: max(1.2em, var(--app-line-height, 1.428571429em));
179
+ }
180
+ .container.small .controls {
181
+ margin-inline: auto;
182
+ }
166
183
 
167
184
  .controls {
168
185
  display: flex;
@@ -14,7 +14,9 @@ export class Q2Pagination {
14
14
  this.disabled = false;
15
15
  this.checkSize = () => {
16
16
  const { hostElement, containerElement } = this;
17
- const isOverflowing = this.containerWidth > hostElement.clientWidth;
17
+ const fontSize = parseFloat(getComputedStyle(containerElement).fontSize);
18
+ // Reserve enough space for the full controls as the text grows.
19
+ const isOverflowing = this.containerWidth > hostElement.clientWidth || hostElement.clientWidth < fontSize * 42;
18
20
  this.isSmall = isOverflowing;
19
21
  nextPaint(() => {
20
22
  const currentContainerWidth = containerElement.clientWidth;
@@ -69,7 +71,9 @@ export class Q2Pagination {
69
71
  }
70
72
  }
71
73
  componentDidLoad() {
74
+ var _a;
72
75
  this.containerWidth = this.containerElement.clientWidth;
76
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(this.containerElement);
73
77
  overrideFocus(this.hostElement);
74
78
  }
75
79
  // #endregion
@@ -209,6 +213,8 @@ export class Q2Pagination {
209
213
  const classes = ['container'];
210
214
  if (this.stacked)
211
215
  classes.push('stacked');
216
+ if (this.isSmall)
217
+ classes.push('small');
212
218
  return classes;
213
219
  }
214
220
  get currentRange() {
@@ -312,7 +318,7 @@ export class Q2Pagination {
312
318
  total,
313
319
  });
314
320
  }
315
- return (h("nav", { key: '647c141a9df399b3764fdc90c5ae05f113e0019d', class: this.containerClasses.join(' '), ref: el => (this.containerElement = el), "aria-label": loc('tecton.element.pagination.title') }, h("div", { key: 'fd595002af27dd639391665573433783342d2aee', class: "description", "test-id": "description" }, pagesOnly
321
+ return (h("nav", { key: 'a427944d7134621fe5c1cc469d554cf60ea69271', class: this.containerClasses.join(' '), ref: el => (this.containerElement = el), "aria-label": loc('tecton.element.pagination.title') }, h("div", { key: 'ab5e3a0dc0a8c3ab99c8d6754097c37ae1c10193', class: "description", "test-id": "description" }, pagesOnly
316
322
  ? loc('tecton.element.pagination.pages', {
317
323
  current: page,
318
324
  total: totalPages,
@@ -321,10 +327,10 @@ export class Q2Pagination {
321
327
  range: currentRange,
322
328
  recordType: recordType.toLowerCase(),
323
329
  total: total.toLocaleString(),
324
- })), h("div", { key: 'da4c7137ed566532a9471a7b83a63c49c51c8e82', class: "controls" }, h("div", { key: 'ef59aadb7b6cfb82707ffb1ee9e1626428a84801', class: "btn-group" }, h("q2-btn", { key: 'e5d551764bec56fed3dc34684c4ff2cdfadd95ea', ref: el => (this.firstPageBtn = el), label: loc('tecton.element.pagination.goToFirstPage'), disabled: disabled || onFirstPage, hidden: isFullViewHidden, onTctClick: () => this.handlePageChange(1), "test-id": "firstPageBtn", "hide-label": true }, h("q2-icon", { key: '7423721c4c3082b8f0fdea5d6bde9fc62640fa24', type: "chevron-double-left" })), h("q2-btn", { key: '90b3544e9983fa652f225eda9d18d08883b31c39', ref: el => (this.prevPageBtn = el), label: prevButtonLabel, disabled: disabled || onFirstPage, onTctClick: () => this.handlePageChange(page - 1), "test-id": "prevPageBtn", "hide-label": true }, h("q2-icon", { key: '6535f2c3745421cbf1dd5750e3ab8d08288bc148', type: "chevron-left" }))), h("div", { key: 'd4a581982a62f360e5b693a110a7d75eaf0ba24c', class: "input-display", hidden: isFullViewHidden }, h("span", { key: '45a28afc71ee038d829cbe64550bf929210002a9', "aria-hidden": "true" }, loc('tecton.element.pagination.page')), h("div", { key: 'ba5df7f89aed5be2f882057d8cf344981e3f1127', class: "input-wrapper", onClick: () => this.inputField.dispatchEvent(new FocusEvent('focus')) }, h("q2-input", { key: '686c5c8891bd64a40ba9abe8436475bf3ef8fd38', ref: el => (this.inputField = el), type: "number", value: `${page}`, min: 1, max: this.totalPages, hideLabel: true, optional: true, label: `${loc('tecton.element.pagination.page')} (${loc('tecton.element.pagination.ofPages', [totalPages.toLocaleString()])})`, onChange: event => event.stopImmediatePropagation(), onTctChange: event => {
330
+ })), h("div", { key: 'e84213e3dbeac1bb54fcd8244e486274869c5fa5', class: "controls" }, h("div", { key: 'f5a4cb3a4d467b2ce412afa2bb016e1843ccb364', class: "btn-group" }, h("q2-btn", { key: 'b4d315503de340e482ffb042d3cd4dbaff1aa3eb', ref: el => (this.firstPageBtn = el), label: loc('tecton.element.pagination.goToFirstPage'), disabled: disabled || onFirstPage, hidden: isFullViewHidden, onTctClick: () => this.handlePageChange(1), "test-id": "firstPageBtn", "hide-label": true }, h("q2-icon", { key: '8d437e9a6b00999eee091accd8581b84a2dbe4fe', type: "chevron-double-left" })), h("q2-btn", { key: 'bd91788b84cbe8a55fb7e7b53342a6c9a75e3694', ref: el => (this.prevPageBtn = el), label: prevButtonLabel, disabled: disabled || onFirstPage, onTctClick: () => this.handlePageChange(page - 1), "test-id": "prevPageBtn", "hide-label": true }, h("q2-icon", { key: 'bf9285d825da06e43e330b565ecf46f72a9ad930', type: "chevron-left" }))), h("div", { key: '76ce1e31814ec56e7d060200ee8a87c720c5fc1e', class: "input-display", hidden: isFullViewHidden }, h("span", { key: 'b1768b78ca08e2f76892823a165448c298d2a5b4', "aria-hidden": "true" }, loc('tecton.element.pagination.page')), h("div", { key: '8909fdeaf8832ec6a104ffad86258d0d3034fbb3', class: "input-wrapper", onClick: () => this.inputField.dispatchEvent(new FocusEvent('focus')) }, h("q2-input", { key: '96e0ce1764dc542fcac5a516b608b379bd1453a9', ref: el => (this.inputField = el), type: "number", value: `${page}`, min: 1, max: this.totalPages, hideLabel: true, optional: true, label: `${loc('tecton.element.pagination.page')} (${loc('tecton.element.pagination.ofPages', [totalPages.toLocaleString()])})`, onChange: event => event.stopImmediatePropagation(), onTctChange: event => {
325
331
  event.stopPropagation();
326
332
  this.handlePageChange(event.detail.value);
327
- }, "test-id": "pageInput", current: "page", disabled: disabled })), h("span", { key: '59853a0308d1f97b6722f40c29219d887842c54c', "aria-hidden": "true" }, loc('tecton.element.pagination.ofPages', [totalPages.toLocaleString()]))), h("div", { key: '17fa28deff49d5a3a28b6d66b5639428a309057a', class: "btn-group" }, h("q2-btn", { key: '0e5eca8dc228a8285015d5941d9c4e44af5e5353', ref: el => (this.nextPageBtn = el), label: nextButtonLabel, disabled: disabled || onLastPage, onTctClick: () => this.handlePageChange(page + 1), "test-id": "nextPageBtn", "hide-label": true }, h("q2-icon", { key: '9a42a4961ac7efd40c176145a39f0c63540daf14', type: "chevron-right" })), h("q2-btn", { key: 'fe0c41536c25d7deffa26fdab4f91405e5b197d6', ref: el => (this.lastPageBtn = el), label: "tecton.element.pagination.goToLastPage", disabled: disabled || onLastPage, hidden: isFullViewHidden, onTctClick: () => this.handlePageChange(totalPages), "test-id": "lastPageBtn", "hide-label": true }, h("q2-icon", { key: '5beccc87ad5ef95350cb21d969b15c0996911126', type: "chevron-double-right" })))), h("div", { key: 'd60b56b2f8173ea2a6fcf3cf4fd1b5f2807fbc5c', class: "per-page", hidden: isFullViewHidden || !((_a = this.perPageIncrements) === null || _a === void 0 ? void 0 : _a.length) }, showPerPageSelect && this.renderPerPage())));
333
+ }, "test-id": "pageInput", current: "page", disabled: disabled })), h("span", { key: '3914f78404deab10b4173df5b16c205067c7e15e', "aria-hidden": "true" }, loc('tecton.element.pagination.ofPages', [totalPages.toLocaleString()]))), h("div", { key: 'b5b441d213d99d04b18c976628ba07142e00856f', class: "btn-group" }, h("q2-btn", { key: '3299b27a7d24045f2258288e86702a4b7e6d1e37', ref: el => (this.nextPageBtn = el), label: nextButtonLabel, disabled: disabled || onLastPage, onTctClick: () => this.handlePageChange(page + 1), "test-id": "nextPageBtn", "hide-label": true }, h("q2-icon", { key: 'd63e7679e5087a1a03bb17fd0a7c24c0d07bdf87', type: "chevron-right" })), h("q2-btn", { key: 'f575528380b7d239db48f49353d71b88ba0e2d9e', ref: el => (this.lastPageBtn = el), label: "tecton.element.pagination.goToLastPage", disabled: disabled || onLastPage, hidden: isFullViewHidden, onTctClick: () => this.handlePageChange(totalPages), "test-id": "lastPageBtn", "hide-label": true }, h("q2-icon", { key: 'c76d0fe0dff9095f893604fc41cd4d615075045e', type: "chevron-double-right" })))), h("div", { key: '71ad1c246e16a1c84318d7ccf75d50a37246af12', class: "per-page", hidden: isFullViewHidden || !((_a = this.perPageIncrements) === null || _a === void 0 ? void 0 : _a.length) }, showPerPageSelect && this.renderPerPage())));
328
334
  }
329
335
  static get is() { return "q2-pagination"; }
330
336
  static get encapsulation() { return "shadow"; }
@@ -142,3 +142,42 @@ test.describe('q2-pagination — variants × themes', () => {
142
142
  }
143
143
  }
144
144
  });
145
+ test.describe('q2-pagination — mobile large font scale', () => {
146
+ for (const theme of ['standard', 'default-2026']) {
147
+ for (const scale of [200, 400]) {
148
+ test(`q2-pagination--mobile-font-scale-${scale}--${theme}`, async ({ page }) => {
149
+ await page.setViewportSize({ width: 375, height: 812 });
150
+ await setupPage(page, `<q2-pagination record-type="International account transactions" total="123456789" page="5000000" per-page="10"></q2-pagination>`, { theme, fontSizePx: (16 * scale) / 100, setupLoc: true });
151
+ await expect(page.locator('q2-pagination nav.container')).toHaveClass(/small/);
152
+ await page.locator('q2-pagination').evaluate(host => {
153
+ host.style.lineHeight = '20px';
154
+ });
155
+ const layout = await page.locator('q2-pagination').evaluate(host => {
156
+ const description = host.shadowRoot.querySelector('.description');
157
+ const controls = host.shadowRoot.querySelector('.controls');
158
+ const descriptionRect = description.getBoundingClientRect();
159
+ const controlsRect = controls.getBoundingClientRect();
160
+ const hostRect = host.getBoundingClientRect();
161
+ const descriptionStyle = getComputedStyle(description);
162
+ return {
163
+ controlsBelowDescription: controlsRect.top >= descriptionRect.bottom,
164
+ descriptionFits: description.scrollWidth <= description.clientWidth,
165
+ controlsFit: controlsRect.right <= hostRect.right,
166
+ descriptionWrapped: descriptionRect.height > parseFloat(descriptionStyle.lineHeight) * 1.5,
167
+ lineHeightFitsFont: parseFloat(descriptionStyle.lineHeight) >= parseFloat(descriptionStyle.fontSize) * 1.2 - 1,
168
+ };
169
+ });
170
+ await expect(page).toHaveScreenshot(`q2-pagination--mobile-font-scale-${scale}--${theme}.png`, {
171
+ fullPage: true,
172
+ });
173
+ expect(layout).toEqual({
174
+ controlsBelowDescription: true,
175
+ descriptionFits: true,
176
+ controlsFit: true,
177
+ descriptionWrapped: true,
178
+ lineHeightFitsFont: true,
179
+ });
180
+ });
181
+ }
182
+ }
183
+ });
@@ -90,9 +90,8 @@ button {
90
90
  /**
91
91
  * @prop --tct-pill-margin: (<length-percentage>) Controls the trailing inline margin between sibling pills.
92
92
  * @prop --tct-pill-min-height: (<length>) Controls the minimum height of the pill (and its popover container).
93
- * @prop --tct-pill-max-width: (<length-percentage>) Controls the maximum width of the pill label when options are present.
93
+ * @prop --tct-pill-max-width: (<length-percentage>) Controls the maximum width of the pill button. Use font-scaling units to scale with text.
94
94
  * @prop --tct-pill-disabled-opacity: (<number>) Controls the opacity of the pill when disabled.
95
- * @prop --tct-pill-btn-height: (<length>) Controls the height of the pill button.
96
95
  * @prop --tct-pill-btn-padding-inline: (<length-percentage>+) Controls the inline padding of the pill button.
97
96
  * @prop --tct-pill-btn-border-radius: (<length-percentage>) Controls the corner radius of the pill button.
98
97
  * @prop --tct-pill-btn-border-width: (<length>+) Controls the border width of the pill button.
@@ -147,6 +146,7 @@ button {
147
146
  */
148
147
  :host {
149
148
  display: inline-block;
149
+ max-width: 100%;
150
150
  position: relative;
151
151
  line-height: 0;
152
152
  }
@@ -227,7 +227,7 @@ q2-popover,
227
227
  }
228
228
 
229
229
  .btn-height-wrapper {
230
- height: var(--comp-pill-min-height);
230
+ min-height: var(--comp-pill-min-height);
231
231
  display: flex;
232
232
  align-items: center;
233
233
  cursor: pointer;
@@ -242,7 +242,7 @@ q2-popover,
242
242
  .btn-close,
243
243
  .btn-primary {
244
244
  cursor: pointer;
245
- height: var(--comp-pill-btn-height);
245
+ min-height: var(--comp-pill-btn-height);
246
246
  border-style: solid;
247
247
  border-radius: var(--tct-pill-btn-border-radius, var(--t-pill-btn-border-radius, 30px));
248
248
  transition-property: background, color, padding, width, opacity;
@@ -272,9 +272,12 @@ q2-popover,
272
272
  align-items: center;
273
273
  gap: var(--app-scale-1x, 5px);
274
274
  width: 100%;
275
+ max-width: var(--tct-pill-max-width, var(--t-pill-max-width, calc(200 * var(--t-px-1, 1px))));
276
+ min-width: 0;
275
277
  text-align: start;
276
278
  }
277
279
  .btn-primary ::slotted(q2-icon[slot=decorator]) {
280
+ flex-shrink: 0;
278
281
  --tct-icon-size: 1em;
279
282
  --tct-icon-stroke-primary: var(--tct-pill-decorator-icon-primary-stroke, var(--comp-btn-color));
280
283
  --tct-icon-stroke-secondary: var(--tct-pill-decorator-icon-secondary-stroke, var(--comp-btn-color));
@@ -291,12 +294,6 @@ q2-popover,
291
294
  .has-options .btn-primary, .has-icon .btn-primary {
292
295
  padding-right: calc(var(--tct-pill-icon-gap, var(--t-pill-icon-gap, var(--app-scale-1x, 5px))) + var(--comp-close-size));
293
296
  }
294
- .has-options .btn-primary {
295
- text-overflow: ellipsis;
296
- overflow: hidden;
297
- white-space: nowrap;
298
- max-width: var(--tct-pill-max-width, var(--t-pill-max-width, 200px));
299
- }
300
297
  :host([active]:not([active=false])) .btn-primary {
301
298
  background: var(--comp-active-btn-background);
302
299
  box-shadow: var(--comp-active-btn-box-shadow);
@@ -319,6 +316,13 @@ q2-popover,
319
316
  --tct-icon-stroke-secondary: var(--tct-pill-active-decorator-icon-secondary-stroke, var(--tct-pill-decorator-icon-secondary-stroke, var(--comp-active-btn-color)));
320
317
  }
321
318
 
319
+ .pill-label {
320
+ text-overflow: ellipsis;
321
+ overflow: hidden;
322
+ white-space: nowrap;
323
+ min-width: 0;
324
+ }
325
+
322
326
  .btn-close {
323
327
  background: transparent;
324
328
  border-color: transparent;
@@ -413,7 +413,7 @@ export class Q2Pill {
413
413
  wrapperClassNames.push('has-icon');
414
414
  if (optionCount)
415
415
  wrapperClassNames.push('has-options');
416
- return (h("click-elsewhere", { key: '8cba59cde3746d0397305512334eb56357e9e5d4', onChange: this.onClickElsewhere }, h("div", { key: '391da54f9fd870e223765e6266291dff9775abe6', class: wrapperClassNames.join(' ') }, h("div", { key: '06431fd76c0a9d30833756407c89ff59609bc3a3', class: "btn-height-wrapper", ref: el => (this.primaryBtnWrapper = el), onClick: this.handleWrapperClick, tabIndex: -1 }, h("button", { key: '609557b9206c91511e78e26c990230e61f7e5c19', class: "btn-primary", "test-id": "btn-control", type: "button", role: (optionCount && 'combobox') || undefined, ref: el => (this.primaryBtn = el), onClick: this.handleClick, onKeyDown: this.handleKeydown, onFocusout: this.handleFocusOut, disabled: this.disabled, "aria-roledescription": !optionCount && 'filter', "aria-controls": (optionCount && 'option-list') || undefined, "aria-expanded": (optionCount && `${!!open}`) || undefined, "aria-label": text, "aria-pressed": !optionCount ? `${!!active}` : undefined, "aria-describedby": (optionCount && 'option-description') || undefined }, h("slot", { key: 'e1f4c57b7526f714cf0242e101ec0f5c39ebafa5', name: "decorator" }), truncatedText)), this.renderIcon(), !!optionCount && this.renderHiddenElement()), this.optionCount > 0 && (h("q2-popover", { key: '2777b45efbd94516a633ca4ff1e2d6a452ecbd81', ref: el => (this.popoverElement = el), controlElement: this.primaryBtn, open: this.open, "max-height": this.popoverMaxHeight, minHeight: this.popoverMinHeight, direction: this.popoverDirection, align: this.popoverAlignment, onFocusout: this.handleFocusOut }, h("div", { key: '54d2c1c8814be9265b4ed8092bd3360da76cc2b0', class: "popover-content" }, h("div", { key: 'fb95b6f0ab78119f0bf944fa67ec0bcf391088dc', ref: el => (this.popoverTopContainer = el), class: "popover-top-container", tabindex: "-1", hidden: !this.hasPopoverTop, onKeyDown: this.handleSlotKeydown }, h("slot", { key: '8e522c96fa1241e7c05fbc989d59f71ec2bc1d98', name: "popover-top" })), h("q2-option-list", { key: '5e7a827ac08395399e0b04fa9074f5b6a3fa1c48', type: "listbox", ref: el => (this.optionList = el), id: "option-list", onChange: this.handleChange, multiple: this.multiple, selectedOptions: this.selectedOptions, onReady: () => this.updateSelectedOptionElements(), onPopoverState: this.onPopoverState, label: loc('tecton.element.optionList.label', [this.optionListLabel]) }, h("slot", { key: '4197780a058b3937ac748b53aef6afc5eabd8c7a' })), h("div", { key: '78992c83515dcfe6acbf7e09a5efced2d65c1903', ref: el => (this.popoverBottomContainer = el), class: "popover-bottom-container", tabindex: "-1", hidden: !this.hasPopoverBottom, onKeyDown: this.handleSlotKeydown }, h("slot", { key: '553f959ec8b866111b2e5c5f9090d8ddee5fd208', name: "popover-bottom" })))))));
416
+ return (h("click-elsewhere", { key: '8cba59cde3746d0397305512334eb56357e9e5d4', onChange: this.onClickElsewhere }, h("div", { key: '391da54f9fd870e223765e6266291dff9775abe6', class: wrapperClassNames.join(' ') }, h("div", { key: '06431fd76c0a9d30833756407c89ff59609bc3a3', class: "btn-height-wrapper", ref: el => (this.primaryBtnWrapper = el), onClick: this.handleWrapperClick, tabIndex: -1 }, h("button", { key: '609557b9206c91511e78e26c990230e61f7e5c19', class: "btn-primary", "test-id": "btn-control", type: "button", role: (optionCount && 'combobox') || undefined, ref: el => (this.primaryBtn = el), onClick: this.handleClick, onKeyDown: this.handleKeydown, onFocusout: this.handleFocusOut, disabled: this.disabled, "aria-roledescription": !optionCount && 'filter', "aria-controls": (optionCount && 'option-list') || undefined, "aria-expanded": (optionCount && `${!!open}`) || undefined, "aria-label": text, "aria-pressed": !optionCount ? `${!!active}` : undefined, "aria-describedby": (optionCount && 'option-description') || undefined }, h("slot", { key: 'e1f4c57b7526f714cf0242e101ec0f5c39ebafa5', name: "decorator" }), h("span", { key: '98a770f6f4fabe04d886f66d57e76a4febb31353', class: "pill-label" }, truncatedText))), this.renderIcon(), !!optionCount && this.renderHiddenElement()), this.optionCount > 0 && (h("q2-popover", { key: '30fb581a9eeb008262bbb3fc4a82537f1b78af28', ref: el => (this.popoverElement = el), controlElement: this.primaryBtn, open: this.open, "max-height": this.popoverMaxHeight, minHeight: this.popoverMinHeight, direction: this.popoverDirection, align: this.popoverAlignment, onFocusout: this.handleFocusOut }, h("div", { key: '6fc858b2064b78b2ccaafd35aefaa2e4c9e1ea07', class: "popover-content" }, h("div", { key: '75134f4a5d4296f6f69a70197bf1bd450c05a8e0', ref: el => (this.popoverTopContainer = el), class: "popover-top-container", tabindex: "-1", hidden: !this.hasPopoverTop, onKeyDown: this.handleSlotKeydown }, h("slot", { key: 'f570a1a19b97bd7eb4b2ae38975db95ff1153b00', name: "popover-top" })), h("q2-option-list", { key: 'aca9ff86903dcf5b4e5138541ac20dac68955fb7', type: "listbox", ref: el => (this.optionList = el), id: "option-list", onChange: this.handleChange, multiple: this.multiple, selectedOptions: this.selectedOptions, onReady: () => this.updateSelectedOptionElements(), onPopoverState: this.onPopoverState, label: loc('tecton.element.optionList.label', [this.optionListLabel]) }, h("slot", { key: '89c5f3739c36206ceecb06245ba3052491b89898' })), h("div", { key: '8f98c6b4a59c2c0675b5648aed4a1110f0136d87', ref: el => (this.popoverBottomContainer = el), class: "popover-bottom-container", tabindex: "-1", hidden: !this.hasPopoverBottom, onKeyDown: this.handleSlotKeydown }, h("slot", { key: '75ef6c235c31755e0a5b9905db16e02ff8c4eea3', name: "popover-bottom" })))))));
417
417
  }
418
418
  static get is() { return "q2-pill"; }
419
419
  static get encapsulation() { return "shadow"; }
@@ -125,6 +125,16 @@ test.describe('q2-pill — variants × themes', () => {
125
125
  });
126
126
  // 'default' (inactive, no value) exercises --tct-pill-btn-font-size (button label text).
127
127
  const PILL_DEFAULT_VARIANT = VARIANTS.find(v => v.name === 'default');
128
+ const LONG_LABEL = 'ExtraordinarilyLongAccountDescription WithoutAnyAvailableSpace';
129
+ const LONG_LABEL_VARIANTS = [
130
+ { name: 'long-label', html: `<q2-pill label="${LONG_LABEL}"></q2-pill>` },
131
+ { name: 'long-label-active', html: `<q2-pill label="${LONG_LABEL}" active></q2-pill>` },
132
+ {
133
+ name: 'long-label-decorator',
134
+ html: `<q2-pill label="${LONG_LABEL}"><q2-icon slot="decorator" type="star"></q2-icon></q2-pill>`,
135
+ },
136
+ { name: 'long-label-options', html: `<q2-pill label="${LONG_LABEL}">${OPTIONS}</q2-pill>` },
137
+ ];
128
138
  test.describe(`q2-pill — scaled font size × themes`, () => {
129
139
  for (const theme of THEMES) {
130
140
  test(`q2-pill--default--resting--${FONT_SCALE_SUFFIX} — ${theme}`, async ({ page }) => {
@@ -132,4 +142,19 @@ test.describe(`q2-pill — scaled font size × themes`, () => {
132
142
  await expect(page).toHaveScreenshot(`q2-pill--default--resting--${FONT_SCALE_SUFFIX}--${theme}.png`);
133
143
  });
134
144
  }
145
+ for (const variant of LONG_LABEL_VARIANTS) {
146
+ for (const theme of THEMES) {
147
+ test(`q2-pill--${variant.name}--${FONT_SCALE_SUFFIX} — ${theme}`, async ({ page }) => {
148
+ await setupPage(page, `<div style="width: 180px">${variant.html}</div>`, {
149
+ theme,
150
+ fontSizePx: FONT_SCALE_PX,
151
+ });
152
+ const maxWidth = await page
153
+ .locator('q2-pill .btn-primary')
154
+ .evaluate(el => parseFloat(getComputedStyle(el).maxWidth));
155
+ expect(maxWidth).toBeCloseTo((200 * FONT_SCALE_PX) / 16, 0);
156
+ await expect(page).toHaveScreenshot(`q2-pill--${variant.name}--${FONT_SCALE_SUFFIX}--${theme}.png`);
157
+ });
158
+ }
159
+ }
135
160
  });
@@ -153,7 +153,7 @@ export class Q2RelativeTime {
153
153
  // #region Render Methods
154
154
  render() {
155
155
  const { shouldShow, displayedMessage } = this;
156
- return h(Fragment, { key: 'c6d24ac6d794284c3f0ea654f1999ff6e201f8b1' }, shouldShow ? h("time", { dateTime: displayedMessage }, displayedMessage) : null);
156
+ return h(Fragment, { key: 'e32fc9201354f10456368f47c0a7b6e50fd3eeb2' }, shouldShow ? h("time", { dateTime: displayedMessage }, displayedMessage) : null);
157
157
  }
158
158
  static get is() { return "q2-relative-time"; }
159
159
  static get encapsulation() { return "shadow"; }
@@ -76,7 +76,7 @@ export class Q2ResizeObserver {
76
76
  // #endregion
77
77
  // #region Render Methods
78
78
  render() {
79
- return h("slot", { key: 'cd3c22934ee46501f6ab1dc317ab702ba97150f3', onSlotchange: this.handleSlotChange });
79
+ return h("slot", { key: '78ea06c9c3963fe4fe145d66c42b546432d10e95', onSlotchange: this.handleSlotChange });
80
80
  }
81
81
  static get is() { return "q2-resize-observer"; }
82
82
  static get encapsulation() { return "shadow"; }
@@ -771,7 +771,7 @@ export class Q2Search {
771
771
  return (h("q2-popover", { ref: el => (this.popoverElement = el), controlElement: (_a = this.innerInputContainer) !== null && _a !== void 0 ? _a : undefined, open: this.open, maxHeight: this.popoverMaxHeight, minHeight: this.popoverMinHeight, align: useBlock ? undefined : this.popoverAlignment, block: useBlock }, h("div", { class: "popover-content", "data-loading": this.loading ? 'true' : 'false', "aria-busy": this.loading ? 'true' : null }, h("div", { class: "popover-top-container", hidden: !this.hasPopoverTop && !(this.multiple && this.showSelectedToggle), tabindex: "-1" }, h("slot", { name: "popover-top" }), !this.loading && this.renderMultiSelectHeader()), h("q2-option-list", { ref: el => (this.optionList = el), type: "listbox", id: this.optionListId, label: loc(this.listLabel), multiple: this.multiple, selectedOptions: this.structuredSelectedOptions, showSelected: this.showSelected, customSearch: true, hidden: this.loading, onChange: (e) => e.stopPropagation(), onTctChange: this.onOptionListChange }, h("slot", null)), showEmpty && this.renderEmpty(), h("div", { class: "popover-bottom-container", hidden: !this.hasPopoverBottom, tabindex: "-1" }, h("slot", { name: "popover-bottom" })), this.loading && (h("div", { class: "loading-overlay", "aria-hidden": "true" }, h("q2-loading", { type: "spinner" }))))));
772
772
  }
773
773
  render() {
774
- return (h(Fragment, { key: '282a0d7a6fc3199a2ae52a9a6f1c3ace8b58c00d' }, h("div", { key: 'b45c3a05cfb004bf7dfbf266af0e983c9740f7e6', "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage), h("click-elsewhere", { key: '603d6b423bd6e2a6f3b90b85f13e744d157c7c61', class: this.wrapperClasses, role: "presentation", onChange: this.onClickElsewhere }, h("q2-input", { key: '267c12c340e038bb5d10133d59955b4067699fbf', ref: el => (this.inputField = el), class: "q2-search-input", label: (this.label && loc(this.label)) || '', value: this.searchText, iconLeft: "search", clearable: this.clearable && !this.loading && !!this.searchText, disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder ? loc(this.placeholder) : undefined, hideLabel: this.hideLabel, errors: (Array.isArray(this.errors) && this.errors.length > 0 && this.errors.map(e => loc(e))) ||
774
+ return (h(Fragment, { key: '4b3787554c37521bc3467345cdd1d733cffba3a5' }, h("div", { key: '696caa142cffecf1e0d62afafd826dce37f75512', "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage), h("click-elsewhere", { key: 'f8b493ec8f7da09fad48f9fa30f0e9be7fbaedf4', class: this.wrapperClasses, role: "presentation", onChange: this.onClickElsewhere }, h("q2-input", { key: '44e0ad4b7825ac319dd4277ccb93d4dd66acef12', ref: el => (this.inputField = el), class: "q2-search-input", label: (this.label && loc(this.label)) || '', value: this.searchText, iconLeft: "search", clearable: this.clearable && !this.loading && !!this.searchText, disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder ? loc(this.placeholder) : undefined, hideLabel: this.hideLabel, errors: (Array.isArray(this.errors) && this.errors.length > 0 && this.errors.map(e => loc(e))) ||
775
775
  (this.invalid && ['tecton.element.search.invalid']) ||
776
776
  [], ariaExpanded: this.isInputOnlyMode ? undefined : `${this.open}`, ariaControls: this.isInputOnlyMode ? undefined : this.optionListId, ariaHaspopup: this.isInputOnlyMode ? undefined : 'listbox', hideMessages: true, _role: this.isInputOnlyMode ? undefined : 'combobox', onTctInput: this.inputInputHandler, onInput: (e) => e.stopImmediatePropagation(), onChange: (e) => e.stopPropagation(), onTctChange: (e) => e.stopPropagation(), badgeValue: this.badgeValue }, this.renderCustomDisplay()), this.renderOptionsDropdown())));
777
777
  }
@@ -186,9 +186,9 @@ export class Q2Section {
186
186
  wrapperClasses.push('is-transitioning');
187
187
  }
188
188
  const showDefaultHeader = !this.hasYieldedHeader && !!this.label;
189
- return (h("section", { key: '671c4611adeaff5c3e53d05a43955851d682c792', class: "wrapper" }, h("header", { key: 'fb724579804c9c3dd4da39bbc45d6df5cfad3815', class: hasHeader ? 'has-header' : '' }, h("div", { key: '76ad513b058264c1dbbeac7732120fea97586e1f', class: "header-content", id: this.titleId, onClick: this.collapsible && this.onHeaderClick }, showDefaultHeader && h("h2", { key: '6717219e621e8b605e4cbc7fa4f1f84bd4b1f20a', class: "title" }, loc(this.label)), h("div", { key: '61acf1ce4b3281aed6f35571a62f4da58d692d10', ref: el => (this.headerSlotWrapper = el), class: "header-slot-wrapper" }, h("slot", { key: 'acd5b6f6337700edf60fd03ce3d35a634eb2f97c', ref: (el) => (this.headerSlot = el), name: "q2-section-header" }))), this.collapsible && !this.noCollapseIcon && (h("q2-btn", { key: '02543820b86cf3d8fd103e0384d283e130fc2212', label: loc(this.label || 'tecton.element.section.defaultToggleLabel'), ariaExpanded: `${!!this.expanded}`, ariaControls: this.contentId, "test-id": "toggleButton", "hide-label": true, onClick: this.onHeaderClick }, h("q2-icon", { key: 'fc7484a585f815948d1bed037948f21e777336f5', type: "chevron-up" })))), h("div", { key: 'f57ce6b9a2e8f8ca589274d496362f106148b499', class: wrapperClasses.join(' '), id: this.contentId, "aria-labelledby": this.titleId, role: "region", onTransitionEnd: this.onTransitionEnd, style: this.collapsible && {
189
+ return (h("section", { key: '5adb22a7e6cf098fa3cf2325c945c6aa1c20b2d5', class: "wrapper" }, h("header", { key: 'c04df6d07756c27374e4be85ad88848a0c1ac897', class: hasHeader ? 'has-header' : '' }, h("div", { key: '8cd09e8bf367a7510b91106b8ebd4f419faff861', class: "header-content", id: this.titleId, onClick: this.collapsible && this.onHeaderClick }, showDefaultHeader && h("h2", { key: '195e1523e68c83e294bd92d617b8c4d44e679494', class: "title" }, loc(this.label)), h("div", { key: 'e493986ee113d44bf74b11116003939f3db24bd7', ref: el => (this.headerSlotWrapper = el), class: "header-slot-wrapper" }, h("slot", { key: '44f2dc2ca76acfd800a1435608a75bf6e3258d37', ref: (el) => (this.headerSlot = el), name: "q2-section-header" }))), this.collapsible && !this.noCollapseIcon && (h("q2-btn", { key: 'b2602555b9282c8149780f65d2fbaa65febc1f50', label: loc(this.label || 'tecton.element.section.defaultToggleLabel'), ariaExpanded: `${!!this.expanded}`, ariaControls: this.contentId, "test-id": "toggleButton", "hide-label": true, onClick: this.onHeaderClick }, h("q2-icon", { key: '62728524b58cf5cf7aa2531df1218d3bf0b40b0a', type: "chevron-up" })))), h("div", { key: '13ef854a01937880007fb4021b1528c1b83fe937', class: wrapperClasses.join(' '), id: this.contentId, "aria-labelledby": this.titleId, role: "region", onTransitionEnd: this.onTransitionEnd, style: this.collapsible && {
190
190
  height: this.contentHeight,
191
- } }, h("div", { key: 'e1473a0a5f86918df19119a62f99918e8f2203f2', ref: el => (this.contentContainer = el), class: "content", tabindex: "-1" }, h("slot", { key: 'f4f92ebdb06b45be6d70759b6b59caf31f816b04', ref: (el) => (this.contentSlot = el) })))));
191
+ } }, h("div", { key: '866d8b0301a9c5979f5b3bd31086d25f73373709', ref: el => (this.contentContainer = el), class: "content", tabindex: "-1" }, h("slot", { key: '36c97155aa106dc1587537066e031c7d6c032295', ref: (el) => (this.contentSlot = el) })))));
192
192
  }
193
193
  static get is() { return "q2-section"; }
194
194
  static get encapsulation() { return "shadow"; }
@@ -295,7 +295,7 @@ export class Q2Stepper {
295
295
  const containerClasses = ['step-container'];
296
296
  if (scrollEnabled)
297
297
  containerClasses.push('has-scroll');
298
- return (h(Fragment, { key: 'c9839ff458e2d71fb66c42cb5b4ae394c7ffb9ff' }, h("div", { key: '51d8a914662c2794e16928c971ef995bca933776', class: containerClasses.join(' ') }, scrollEnabled && (h(Fragment, { key: '0b1d1dd0c973d2266a468a8f81d0c9bdd2a430cc' }, h("div", { key: '87b9ae7e5ab260ee8743e78302017389941c3ead', class: "gradient-left", hidden: !showScrollLeft }), h("div", { key: 'a5d487517c497ae927a1fd05d7c4631aa00d76bf', class: "gradient-right", hidden: !showScrollRight }), h("q2-btn", { key: 'fe008283e673c2b51acf1cc654ed1c844a6d33bf', class: "btn-left", hideLabel: true, hidden: !this.showScrollLeft, label: loc('tecton.element.stepper.scrollLeft'), onTctClick: () => this.onScrollBtnClick('left') }, h("q2-icon", { key: '7d83dfafb861da55085fa33a4aca620416849e27', type: "chevron-left" })), h("q2-btn", { key: 'c81adb720c387ddabb7eead010db863b0e295208', class: "btn-right", hideLabel: true, hidden: !this.showScrollRight, label: loc('tecton.element.stepper.scrollRight'), onTctClick: () => this.onScrollBtnClick('right') }, h("q2-icon", { key: 'c0d5939662d35c18ea9c486a1dc8da243b779ea2', type: "chevron-right" })))), h("ul", { key: '07501b7abbe4e828686b87c057b79bae4059e826', onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, stepCount > 0 && [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))), h("div", { key: 'df8d51e7b40ee1999b0a280fa8524559accfec9a', role: "list" }, h("slot", { key: 'a8ce54b65b8c7d8542e60811a7215fed12400e38', onSlotchange: () => this.onSlotChange() }))));
298
+ return (h(Fragment, { key: '423f7d50f787abf21c14730ae9cd50cd3638b17b' }, h("div", { key: '2ffacd2f9792075956748eb6960975d9aeda28ad', class: containerClasses.join(' ') }, scrollEnabled && (h(Fragment, { key: 'da90a671295ce6702c3bc6f1ab71f671cda2c9c8' }, h("div", { key: '319c4a75dfafd7b03d3f7f13156f24bd1ca7b0c3', class: "gradient-left", hidden: !showScrollLeft }), h("div", { key: '80a08dc979685d94f6cfe20d66787d06e7d46014', class: "gradient-right", hidden: !showScrollRight }), h("q2-btn", { key: '43a71cb3212ddbe37c6e7d7051850efd49ced456', class: "btn-left", hideLabel: true, hidden: !this.showScrollLeft, label: loc('tecton.element.stepper.scrollLeft'), onTctClick: () => this.onScrollBtnClick('left') }, h("q2-icon", { key: '19ee5abc690bba84016fb8c692a74b5c233aa426', type: "chevron-left" })), h("q2-btn", { key: 'f26bc502269a5d60308aba041a6d9a75efcf2573', class: "btn-right", hideLabel: true, hidden: !this.showScrollRight, label: loc('tecton.element.stepper.scrollRight'), onTctClick: () => this.onScrollBtnClick('right') }, h("q2-icon", { key: '7f35a54468433010427213e18d213b1c227413a6', type: "chevron-right" })))), h("ul", { key: '0bc4eed617263c7e4a6138c3a884f6a1b8bc2ca6', onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, stepCount > 0 && [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))), h("div", { key: '87945c612fcaa70164faa50d78bb63c9b290e3f2', role: "list" }, h("slot", { key: '4b55529f41b4731dc1424c8be4fcd941ff2c2f33', onSlotchange: () => this.onSlotChange() }))));
299
299
  }
300
300
  static get is() { return "q2-stepper"; }
301
301
  static get encapsulation() { return "shadow"; }
@@ -73,7 +73,7 @@ export class Q2StepperPane {
73
73
  // #region Render Methods
74
74
  render() {
75
75
  const { label, isActive } = this;
76
- return (h(Host, { key: '6cbcc9f6363bf6f60ff2d999b9317e32691168da', role: "listitem" }, h(Fragment, { key: 'f9b8d56b05e6d26978feab6386849498f797cca6' }, h("div", { key: '383a77ce1848255574680375e7df122bf4468f95', role: "group", "aria-labelledby": "pane-label", tabindex: "0", hidden: !isActive && !(this.isChildActive && this.showWithChildren) }, h("slot", { key: '9b9cf0bd60e23d9860174c5525c3f688c70411f4' })), h("div", { key: '8f628fe11acfc7a8df7c84013a7eaca9d5a1327a', hidden: true }, h("span", { key: '6c03721fb71d8e3c5c48a6af80ae8723575e0205', id: "pane-label" }, h("slot", { key: 'da9a253e3399d0552478a29c743fc4a73f432ddf', name: "label", onSlotchange: () => this.contentChange.emit() }, label && loc(label))), h("slot", { key: 'd7229f76aedb1c96623fac655982b88d2769b9ae', name: "description", onSlotchange: () => this.contentChange.emit() })), h("slot", { key: '7670d7b17b74732d0dd14198dd50560d005700d1', name: "children" }))));
76
+ return (h(Host, { key: '3929b6bdb716394892be2bcdd933864e43f0204e', role: "listitem" }, h(Fragment, { key: 'd913741a6b71aebef92be14fd7ee541a3d5568da' }, h("div", { key: '038d29ac861f70ad15350da7733b39eece30e538', role: "group", "aria-labelledby": "pane-label", tabindex: "0", hidden: !isActive && !(this.isChildActive && this.showWithChildren) }, h("slot", { key: '56f4c0d9edfe134886d46367f2c801348267b53d' })), h("div", { key: '88bf8a9e1a6124c39d9ac4ee8906f61ac026966a', hidden: true }, h("span", { key: 'db485a5e84ab67fe714f0861fcd05c4b0bd7722f', id: "pane-label" }, h("slot", { key: '940a9a3a8543fd4c64425db2b7ea7b9cf079c947', name: "label", onSlotchange: () => this.contentChange.emit() }, label && loc(label))), h("slot", { key: '74a78697ed1aa85fca66743023d303c7abea0116', name: "description", onSlotchange: () => this.contentChange.emit() })), h("slot", { key: '4fb660b547a2da7dca37de9106b20b93b72aaf83', name: "children" }))));
77
77
  }
78
78
  static get is() { return "q2-stepper-pane"; }
79
79
  static get encapsulation() { return "shadow"; }