@openproject/primer-view-components 0.80.2 → 0.81.0-rc.0426a0ac2

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.
@@ -84,7 +84,7 @@ let SelectPanelElement = class SelectPanelElement extends HTMLElement {
84
84
  return this.getAttribute('data-select-variant');
85
85
  }
86
86
  get ariaSelectionType() {
87
- return this.selectVariant === 'multiple' ? 'aria-checked' : 'aria-selected';
87
+ return 'aria-selected';
88
88
  }
89
89
  set selectVariant(variant) {
90
90
  if (variant) {
@@ -1 +1 @@
1
- .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow:hidden}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;flex-shrink:0;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}:is(.tabnav-tab.selected,.tabnav-tab[aria-selected=true],.tabnav-tab[aria-current]:not([aria-current=false])) .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:var(--base-size-2)}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
1
+ .tabnav{border-bottom:var(--borderWidth-thin) solid var(--borderColor-default);margin-bottom:var(--stack-gap-normal);margin-top:0}.tabnav-tabs{display:flex;margin-bottom:calc(var(--borderWidth-thin)*-1);overflow-x:auto;overflow-y:hidden}.tabnav-tab,.tabnav-tabs>li{flex-shrink:0}.tabnav-tab{background-color:initial;border:var(--borderWidth-thin) solid #0000;border-bottom:0;color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-medium);line-height:23px;padding:var(--base-size-8) var(--control-medium-paddingInline-spacious);-webkit-text-decoration:none;text-decoration:none;transition:color .2s cubic-bezier(.3,0,.5,1)}.tabnav-tab.selected,.tabnav-tab[aria-current]:not([aria-current=false]),.tabnav-tab[aria-selected=true]{background-color:var(--bgColor-default);border-color:var(--borderColor-default);border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0;color:var(--fgColor-default)}:is(.tabnav-tab.selected,.tabnav-tab[aria-selected=true],.tabnav-tab[aria-current]:not([aria-current=false])) .octicon{color:inherit}.tabnav-tab:hover{color:var(--fgColor-default);-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.tabnav-tab:focus,.tabnav-tab:focus-visible{border-radius:var(--borderRadius-medium) var(--borderRadius-medium) 0 0!important;outline-offset:-6px}.tabnav-tab .octicon,.tabnav-tab:active{color:var(--fgColor-muted)}.tabnav-tab .octicon{margin-right:var(--control-small-gap)}.tabnav-tab .Counter{color:inherit;margin-left:var(--control-small-gap)}.tabnav-extra{color:var(--fgColor-muted);display:inline-block;font-size:var(--text-body-size-small);margin-left:10px;padding-top:10px}.tabnav-extra>.octicon{margin-right:var(--base-size-2)}a.tabnav-extra:hover{color:var(--fgColor-accent);-webkit-text-decoration:none;text-decoration:none}.tabnav-btn{margin-left:var(--controlStack-medium-gap-condensed)}
@@ -4,6 +4,7 @@
4
4
  ".tabnav",
5
5
  ".tabnav-tabs",
6
6
  ".tabnav-tab",
7
+ ".tabnav-tabs>li",
7
8
  ".tabnav-tab.selected",
8
9
  ".tabnav-tab[aria-current]:not([aria-current=false])",
9
10
  ".tabnav-tab[aria-selected=true]",
@@ -9,7 +9,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_showReason, _ToolTipElement_update, _ToolTipElement_updateControl, _ToolTipElement_updateControlReference, _ToolTipElement_updateDirection, _ToolTipElement_updatePosition;
12
+ var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_showReason, _ToolTipElement_isControlsPopoverOpen, _ToolTipElement_update, _ToolTipElement_updateControl, _ToolTipElement_updateControlReference, _ToolTipElement_updateDirection, _ToolTipElement_updatePosition;
13
13
  import '@oddbird/popover-polyfill';
14
14
  import { getAnchoredPosition } from '@primer/behaviors';
15
15
  const isPopoverOpen = (() => {
@@ -78,6 +78,7 @@ class ToolTipElement extends HTMLElement {
78
78
  _ToolTipElement_side.set(this, 'outside-bottom');
79
79
  _ToolTipElement_allowUpdatePosition.set(this, false);
80
80
  _ToolTipElement_showReason.set(this, 'mouse');
81
+ _ToolTipElement_isControlsPopoverOpen.set(this, false);
81
82
  }
82
83
  styles() {
83
84
  return `
@@ -244,18 +245,24 @@ class ToolTipElement extends HTMLElement {
244
245
  if (!this.control)
245
246
  return;
246
247
  const showing = isPopoverOpen(this);
248
+ // Track when the control's popover (e.g an ActionMenu) is opened/closed
249
+ if (event.type === 'beforetoggle' && event.currentTarget !== this) {
250
+ __classPrivateFieldSet(this, _ToolTipElement_isControlsPopoverOpen, event.newState === 'open', "f");
251
+ }
247
252
  // Ensures that tooltip stays open when hovering between tooltip and element
248
253
  // WCAG Success Criterion 1.4.13 Hoverable
249
- const shouldShow = event.type === 'mouseenter' ||
254
+ const shouldShow = (event.type === 'mouseenter' ||
250
255
  // Only show tooltip on focus if running in headless browser (for tests) or if focus ring
251
256
  // is visible (i.e. if user is using keyboard navigation)
252
- (event.type === 'focus' && (navigator.webdriver || this.control.matches(':focus-visible')));
257
+ (event.type === 'focus' && (navigator.webdriver || this.control.matches(':focus-visible')))) &&
258
+ // Don't show tooltip if the control's popover is open (e.g. an ActionMenu)
259
+ !__classPrivateFieldGet(this, _ToolTipElement_isControlsPopoverOpen, "f");
253
260
  const isMouseLeaveFromButton = event.type === 'mouseleave' &&
254
261
  event.relatedTarget !== this.control &&
255
262
  event.relatedTarget !== this;
256
263
  const isEscapeKeydown = event.type === 'keydown' && event.key === 'Escape';
257
264
  const isMouseDownOnButton = event.type === 'mousedown' && event.currentTarget === this.control;
258
- const isOpeningOtherPopover = event.type === 'beforetoggle' && event.currentTarget !== this;
265
+ const isOpeningOtherPopover = event.type === 'beforetoggle' && event.currentTarget !== this && event.newState === 'open';
259
266
  const shouldHide = isMouseLeaveFromButton || isEscapeKeydown || isMouseDownOnButton || isOpeningOtherPopover;
260
267
  if (showing && isEscapeKeydown) {
261
268
  /* eslint-disable-next-line no-restricted-syntax */
@@ -288,7 +295,7 @@ class ToolTipElement extends HTMLElement {
288
295
  }
289
296
  }
290
297
  }
291
- _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new WeakMap(), _ToolTipElement_side = new WeakMap(), _ToolTipElement_allowUpdatePosition = new WeakMap(), _ToolTipElement_showReason = new WeakMap(), _ToolTipElement_instances = new WeakSet(), _ToolTipElement_update = function _ToolTipElement_update(isOpen) {
298
+ _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new WeakMap(), _ToolTipElement_side = new WeakMap(), _ToolTipElement_allowUpdatePosition = new WeakMap(), _ToolTipElement_showReason = new WeakMap(), _ToolTipElement_isControlsPopoverOpen = new WeakMap(), _ToolTipElement_instances = new WeakSet(), _ToolTipElement_update = function _ToolTipElement_update(isOpen) {
292
299
  if (isOpen) {
293
300
  openTooltips.add(this);
294
301
  this.classList.remove(TOOLTIP_SR_ONLY_CLASS);
@@ -22,6 +22,7 @@ import './beta/relative_time';
22
22
  import './alpha/tab_container';
23
23
  import '../../lib/primer/forms/primer_multi_input';
24
24
  import '../../lib/primer/forms/primer_text_field';
25
+ import '../../lib/primer/forms/primer_text_area';
25
26
  import '../../lib/primer/forms/toggle_switch_input';
26
27
  import './alpha/action_menu/action_menu_element';
27
28
  import './alpha/select_panel_element';
@@ -22,6 +22,7 @@ import './beta/relative_time';
22
22
  import './alpha/tab_container';
23
23
  import '../../lib/primer/forms/primer_multi_input';
24
24
  import '../../lib/primer/forms/primer_text_field';
25
+ import '../../lib/primer/forms/primer_text_area';
25
26
  import '../../lib/primer/forms/toggle_switch_input';
26
27
  import './alpha/action_menu/action_menu_element';
27
28
  import './alpha/select_panel_element';
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared character counting functionality for text inputs with character limits.
3
+ * Handles real-time character count updates, validation, and aria-live announcements.
4
+ */
5
+ export declare class CharacterCounter {
6
+ private inputElement;
7
+ private characterLimitElement;
8
+ private characterLimitSrElement;
9
+ private SCREEN_READER_DELAY;
10
+ private announceTimeout;
11
+ private isInitialLoad;
12
+ constructor(inputElement: HTMLInputElement | HTMLTextAreaElement, characterLimitElement: HTMLElement, characterLimitSrElement: HTMLElement);
13
+ /**
14
+ * Initialize character counting by setting up event listener and initial count
15
+ */
16
+ initialize(signal?: AbortSignal): void;
17
+ /**
18
+ * Clean up any pending timeouts
19
+ */
20
+ cleanup(): void;
21
+ /**
22
+ * Pluralizes a word based on the count
23
+ */
24
+ private pluralize;
25
+ /**
26
+ * Update the character count display and validation state
27
+ */
28
+ private updateCharacterCount;
29
+ /**
30
+ * Announce character count to screen readers with debouncing
31
+ */
32
+ private announceToScreenReader;
33
+ /**
34
+ * Set error when character limit is exceeded
35
+ */
36
+ private setError;
37
+ /**
38
+ * Clear error when back under character limit
39
+ */
40
+ private clearError;
41
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Shared character counting functionality for text inputs with character limits.
3
+ * Handles real-time character count updates, validation, and aria-live announcements.
4
+ */
5
+ export class CharacterCounter {
6
+ constructor(inputElement, characterLimitElement, characterLimitSrElement) {
7
+ this.inputElement = inputElement;
8
+ this.characterLimitElement = characterLimitElement;
9
+ this.characterLimitSrElement = characterLimitSrElement;
10
+ this.SCREEN_READER_DELAY = 500;
11
+ this.announceTimeout = null;
12
+ this.isInitialLoad = true;
13
+ }
14
+ /**
15
+ * Initialize character counting by setting up event listener and initial count
16
+ */
17
+ initialize(signal) {
18
+ this.inputElement.addEventListener('keyup', () => this.updateCharacterCount(), signal ? { signal } : undefined); // Keyup used over input for better screen reader support
19
+ this.inputElement.addEventListener('paste', () => setTimeout(() => this.updateCharacterCount(), 50), // Gives the pasted content time to register
20
+ signal ? { signal } : undefined);
21
+ this.updateCharacterCount();
22
+ this.isInitialLoad = false;
23
+ }
24
+ /**
25
+ * Clean up any pending timeouts
26
+ */
27
+ cleanup() {
28
+ if (this.announceTimeout) {
29
+ clearTimeout(this.announceTimeout);
30
+ }
31
+ }
32
+ /**
33
+ * Pluralizes a word based on the count
34
+ */
35
+ pluralize(count, string) {
36
+ return count === 1 ? string : `${string}s`;
37
+ }
38
+ /**
39
+ * Update the character count display and validation state
40
+ */
41
+ updateCharacterCount() {
42
+ if (!this.characterLimitElement)
43
+ return;
44
+ const maxLengthAttr = this.characterLimitElement.getAttribute('data-max-length');
45
+ if (!maxLengthAttr)
46
+ return;
47
+ const maxLength = parseInt(maxLengthAttr, 10);
48
+ const currentLength = this.inputElement.value.length;
49
+ const charactersRemaining = maxLength - currentLength;
50
+ let message = '';
51
+ if (charactersRemaining >= 0) {
52
+ const characterText = this.pluralize(charactersRemaining, 'character');
53
+ message = `${charactersRemaining} ${characterText} remaining`;
54
+ const textSpan = this.characterLimitElement.querySelector('.FormControl-caption-text');
55
+ if (textSpan) {
56
+ textSpan.textContent = message;
57
+ }
58
+ this.clearError();
59
+ }
60
+ else {
61
+ const charactersOver = -charactersRemaining;
62
+ const characterText = this.pluralize(charactersOver, 'character');
63
+ message = `${charactersOver} ${characterText} over`;
64
+ const textSpan = this.characterLimitElement.querySelector('.FormControl-caption-text');
65
+ if (textSpan) {
66
+ textSpan.textContent = message;
67
+ }
68
+ this.setError();
69
+ }
70
+ // We don't want this announced on initial load
71
+ if (!this.isInitialLoad) {
72
+ this.announceToScreenReader(message);
73
+ }
74
+ }
75
+ /**
76
+ * Announce character count to screen readers with debouncing
77
+ */
78
+ announceToScreenReader(message) {
79
+ if (this.announceTimeout) {
80
+ clearTimeout(this.announceTimeout);
81
+ }
82
+ this.announceTimeout = window.setTimeout(() => {
83
+ if (this.characterLimitSrElement) {
84
+ this.characterLimitSrElement.textContent = message;
85
+ }
86
+ }, this.SCREEN_READER_DELAY);
87
+ }
88
+ /**
89
+ * Set error when character limit is exceeded
90
+ */
91
+ setError() {
92
+ this.inputElement.setAttribute('invalid', 'true');
93
+ this.inputElement.setAttribute('aria-invalid', 'true');
94
+ this.characterLimitElement.classList.add('fgColor-danger');
95
+ // Show danger icon
96
+ const icon = this.characterLimitElement.querySelector('.FormControl-caption-icon');
97
+ if (icon) {
98
+ icon.removeAttribute('hidden');
99
+ }
100
+ }
101
+ /**
102
+ * Clear error when back under character limit
103
+ */
104
+ clearError() {
105
+ this.inputElement.removeAttribute('invalid');
106
+ this.inputElement.removeAttribute('aria-invalid');
107
+ this.characterLimitElement.classList.remove('fgColor-danger');
108
+ // Hide danger icon
109
+ const icon = this.characterLimitElement.querySelector('.FormControl-caption-icon');
110
+ if (icon) {
111
+ icon.setAttribute('hidden', '');
112
+ }
113
+ }
114
+ }
@@ -0,0 +1,13 @@
1
+ export declare class PrimerTextAreaElement extends HTMLElement {
2
+ #private;
3
+ inputElement: HTMLTextAreaElement;
4
+ characterLimitElement: HTMLElement;
5
+ characterLimitSrElement: HTMLElement;
6
+ connectedCallback(): void;
7
+ disconnectedCallback(): void;
8
+ }
9
+ declare global {
10
+ interface Window {
11
+ PrimerTextAreaElement: typeof PrimerTextAreaElement;
12
+ }
13
+ }
@@ -0,0 +1,53 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
14
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
15
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
16
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
17
+ };
18
+ var _PrimerTextAreaElement_characterCounter;
19
+ import { controller, target } from '@github/catalyst';
20
+ import { CharacterCounter } from './character_counter';
21
+ let PrimerTextAreaElement = class PrimerTextAreaElement extends HTMLElement {
22
+ constructor() {
23
+ super(...arguments);
24
+ _PrimerTextAreaElement_characterCounter.set(this, null);
25
+ }
26
+ connectedCallback() {
27
+ if (this.characterLimitElement) {
28
+ __classPrivateFieldSet(this, _PrimerTextAreaElement_characterCounter, new CharacterCounter(this.inputElement, this.characterLimitElement, this.characterLimitSrElement), "f");
29
+ __classPrivateFieldGet(this, _PrimerTextAreaElement_characterCounter, "f").initialize();
30
+ }
31
+ }
32
+ disconnectedCallback() {
33
+ __classPrivateFieldGet(this, _PrimerTextAreaElement_characterCounter, "f")?.cleanup();
34
+ }
35
+ };
36
+ _PrimerTextAreaElement_characterCounter = new WeakMap();
37
+ __decorate([
38
+ target
39
+ ], PrimerTextAreaElement.prototype, "inputElement", void 0);
40
+ __decorate([
41
+ target
42
+ ], PrimerTextAreaElement.prototype, "characterLimitElement", void 0);
43
+ __decorate([
44
+ target
45
+ ], PrimerTextAreaElement.prototype, "characterLimitSrElement", void 0);
46
+ PrimerTextAreaElement = __decorate([
47
+ controller
48
+ ], PrimerTextAreaElement);
49
+ export { PrimerTextAreaElement };
50
+ if (!window.customElements.get('primer-text-area')) {
51
+ Object.assign(window, { PrimerTextAreaElement });
52
+ window.customElements.define('primer-text-area', PrimerTextAreaElement);
53
+ }
@@ -15,6 +15,8 @@ export declare class PrimerTextFieldElement extends HTMLElement {
15
15
  validationErrorIcon: HTMLElement;
16
16
  leadingVisual: HTMLElement;
17
17
  leadingSpinner: HTMLElement;
18
+ characterLimitElement: HTMLElement;
19
+ characterLimitSrElement: HTMLElement;
18
20
  connectedCallback(): void;
19
21
  disconnectedCallback(): void;
20
22
  clearContents(): void;
@@ -1,4 +1,3 @@
1
- /* eslint-disable custom-elements/expose-class-on-global */
2
1
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
2
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
3
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -16,13 +15,15 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
16
15
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
17
16
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
18
17
  };
19
- var _PrimerTextFieldElement_abortController;
18
+ var _PrimerTextFieldElement_abortController, _PrimerTextFieldElement_characterCounter;
20
19
  import '@github/auto-check-element';
21
20
  import { controller, target } from '@github/catalyst';
21
+ import { CharacterCounter } from './character_counter';
22
22
  let PrimerTextFieldElement = class PrimerTextFieldElement extends HTMLElement {
23
23
  constructor() {
24
24
  super(...arguments);
25
25
  _PrimerTextFieldElement_abortController.set(this, void 0);
26
+ _PrimerTextFieldElement_characterCounter.set(this, null);
26
27
  }
27
28
  connectedCallback() {
28
29
  __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")?.abort();
@@ -40,9 +41,15 @@ let PrimerTextFieldElement = class PrimerTextFieldElement extends HTMLElement {
40
41
  const errorMessage = await event.detail.response.text();
41
42
  this.setError(errorMessage);
42
43
  }, { signal });
44
+ // Set up character limit tracking if present
45
+ if (this.characterLimitElement) {
46
+ __classPrivateFieldSet(this, _PrimerTextFieldElement_characterCounter, new CharacterCounter(this.inputElement, this.characterLimitElement, this.characterLimitSrElement), "f");
47
+ __classPrivateFieldGet(this, _PrimerTextFieldElement_characterCounter, "f").initialize(signal);
48
+ }
43
49
  }
44
50
  disconnectedCallback() {
45
51
  __classPrivateFieldGet(this, _PrimerTextFieldElement_abortController, "f")?.abort();
52
+ __classPrivateFieldGet(this, _PrimerTextFieldElement_characterCounter, "f")?.cleanup();
46
53
  }
47
54
  clearContents() {
48
55
  this.inputElement.value = '';
@@ -92,6 +99,7 @@ let PrimerTextFieldElement = class PrimerTextFieldElement extends HTMLElement {
92
99
  }
93
100
  };
94
101
  _PrimerTextFieldElement_abortController = new WeakMap();
102
+ _PrimerTextFieldElement_characterCounter = new WeakMap();
95
103
  __decorate([
96
104
  target
97
105
  ], PrimerTextFieldElement.prototype, "inputElement", void 0);
@@ -113,6 +121,12 @@ __decorate([
113
121
  __decorate([
114
122
  target
115
123
  ], PrimerTextFieldElement.prototype, "leadingSpinner", void 0);
124
+ __decorate([
125
+ target
126
+ ], PrimerTextFieldElement.prototype, "characterLimitElement", void 0);
127
+ __decorate([
128
+ target
129
+ ], PrimerTextFieldElement.prototype, "characterLimitSrElement", void 0);
116
130
  PrimerTextFieldElement = __decorate([
117
131
  controller
118
132
  ], PrimerTextFieldElement);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openproject/primer-view-components",
3
- "version": "0.80.2",
3
+ "version": "0.81.0-rc.0426a0ac2",
4
4
  "description": "ViewComponents of the Primer Design System for OpenProject",
5
5
  "main": "app/assets/javascripts/primer_view_components.js",
6
6
  "module": "app/components/primer/primer.js",
@@ -63,12 +63,12 @@
63
63
  "devDependencies": {
64
64
  "@changesets/changelog-github": "^0.5.0",
65
65
  "@changesets/cli": "^2.24.1",
66
- "@github/axe-github": "^0.7.0",
66
+ "@github/axe-github": "^0.8.1",
67
67
  "@github/browserslist-config": "^1.0.0",
68
68
  "@github/markdownlint-github": "^0.8.0",
69
69
  "@github/prettier-config": "0.0.6",
70
- "@playwright/test": "^1.49.1",
71
- "@primer/css": "22.0.2",
70
+ "@playwright/test": "^1.57.0",
71
+ "@primer/css": "22.1.0",
72
72
  "@primer/stylelint-config": "^13.1.1",
73
73
  "@rollup/plugin-node-resolve": "^16.0.1",
74
74
  "@rollup/plugin-typescript": "^8.3.3",
@@ -80,7 +80,7 @@
80
80
  "glob": "^11.0.2",
81
81
  "markdownlint-cli2": "^0.19.1",
82
82
  "mocha": "^11.0.1",
83
- "playwright": "^1.49.1",
83
+ "playwright": "^1.57.0",
84
84
  "postcss": "^8.4.16",
85
85
  "postcss-cli": "^11.0.0",
86
86
  "postcss-import": "^16.0.0",
@@ -92,7 +92,7 @@
92
92
  "stylelint-actions-formatters": "^16.3.1",
93
93
  "tslib": "^2.4.0",
94
94
  "typescript": "^5.2.2",
95
- "vite": "^6.2.5",
95
+ "vite": "^7.3.0",
96
96
  "vite-plugin-ruby": "^5.1.0"
97
97
  },
98
98
  "prettier": "@github/prettier-config",
@@ -2721,7 +2721,7 @@
2721
2721
  "name": "gap",
2722
2722
  "type": "Symbol",
2723
2723
  "default": "`GapArg::DEFAULT`",
2724
- "description": "Specify the gap between children elements in the stack. One of `nil`, `:condensed`, `:normal`, or `:spacious`."
2724
+ "description": "Specify the gap between children elements in the stack. One of `nil`, `:condensed`, `:none`, `:normal`, or `:spacious`."
2725
2725
  },
2726
2726
  {
2727
2727
  "name": "direction",
@@ -2951,6 +2951,12 @@
2951
2951
  "default": "N/A",
2952
2952
  "description": "When set to `true`, the field will take up all the horizontal space allowed by its container. Defaults to `true`."
2953
2953
  },
2954
+ {
2955
+ "name": "character_limit",
2956
+ "type": "Number",
2957
+ "default": "N/A",
2958
+ "description": "Optional character limit for the input. If provided, a character counter will be displayed below the input."
2959
+ },
2954
2960
  {
2955
2961
  "name": "name",
2956
2962
  "type": "String",
@@ -3087,6 +3093,12 @@
3087
3093
  "default": "N/A",
3088
3094
  "description": "When set to `true`, the field will take up all the horizontal space allowed by its container. Defaults to `true`."
3089
3095
  },
3096
+ {
3097
+ "name": "character_limit",
3098
+ "type": "Number",
3099
+ "default": "N/A",
3100
+ "description": "Optional character limit for the input. If provided, a character counter will be displayed below the input."
3101
+ },
3090
3102
  {
3091
3103
  "name": "name",
3092
3104
  "type": "String",
@@ -117,6 +117,16 @@
117
117
  "preview_path": "primer/forms/auto_complete_form",
118
118
  "name": "auto_complete_form",
119
119
  "snapshot": "true"
120
+ },
121
+ {
122
+ "preview_path": "primer/forms/text_area_with_character_limit_form",
123
+ "name": "text_area_with_character_limit_form",
124
+ "snapshot": "true"
125
+ },
126
+ {
127
+ "preview_path": "primer/forms/text_field_with_character_limit_form",
128
+ "name": "text_field_with_character_limit_form",
129
+ "snapshot": "true"
120
130
  }
121
131
  ]
122
132
  }