@pine-ds/core 3.27.0 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/components/i18n-format.js +1 -0
  2. package/components/pds-alert.js +1 -1
  3. package/components/pds-avatar.js +1 -1
  4. package/components/pds-chip2.js +1 -1
  5. package/components/pds-multiselect.js +1 -1
  6. package/components/pds-textarea.js +1 -1
  7. package/components/pds-toast.js +1 -1
  8. package/dist/cjs/i18n-format-CrpIhahc.js +64 -0
  9. package/dist/cjs/loader.cjs.js +1 -1
  10. package/dist/cjs/pds-alert.cjs.entry.js +7 -1
  11. package/dist/cjs/pds-avatar.cjs.entry.js +8 -2
  12. package/dist/cjs/pds-chip.cjs.entry.js +8 -3
  13. package/dist/cjs/pds-multiselect.cjs.entry.js +91 -12
  14. package/dist/cjs/pds-textarea.cjs.entry.js +12 -5
  15. package/dist/cjs/pds-toast.cjs.entry.js +9 -3
  16. package/dist/cjs/pine-core.cjs.js +1 -1
  17. package/dist/collection/components/pds-alert/pds-alert.js +30 -1
  18. package/dist/collection/components/pds-avatar/pds-avatar.js +31 -2
  19. package/dist/collection/components/pds-chip/pds-chip.js +31 -3
  20. package/dist/collection/components/pds-multiselect/pds-multiselect.js +358 -17
  21. package/dist/collection/components/pds-textarea/pds-textarea.js +35 -5
  22. package/dist/collection/components/pds-toast/pds-toast.js +32 -3
  23. package/dist/collection/i18n/i18n-format.js +59 -0
  24. package/dist/collection/i18n/index.js +1 -0
  25. package/dist/docs.json +505 -6
  26. package/dist/esm/i18n-format-BKsJZTyn.js +61 -0
  27. package/dist/esm/loader.js +1 -1
  28. package/dist/esm/pds-alert.entry.js +7 -1
  29. package/dist/esm/pds-avatar.entry.js +8 -2
  30. package/dist/esm/pds-chip.entry.js +8 -3
  31. package/dist/esm/pds-multiselect.entry.js +91 -12
  32. package/dist/esm/pds-textarea.entry.js +12 -5
  33. package/dist/esm/pds-toast.entry.js +9 -3
  34. package/dist/esm/pine-core.js +1 -1
  35. package/dist/esm-es5/i18n-format-BKsJZTyn.js +1 -0
  36. package/dist/esm-es5/loader.js +1 -1
  37. package/dist/esm-es5/pds-alert.entry.js +1 -1
  38. package/dist/esm-es5/pds-avatar.entry.js +1 -1
  39. package/dist/esm-es5/pds-chip.entry.js +1 -1
  40. package/dist/esm-es5/pds-multiselect.entry.js +1 -1
  41. package/dist/esm-es5/pds-textarea.entry.js +1 -1
  42. package/dist/esm-es5/pds-toast.entry.js +1 -1
  43. package/dist/esm-es5/pine-core.js +1 -1
  44. package/dist/pine-core/p-041243ee.system.entry.js +1 -0
  45. package/dist/pine-core/{p-7b71f1bf.system.entry.js → p-1f4910b0.system.entry.js} +1 -1
  46. package/dist/pine-core/p-25f8690f.entry.js +1 -0
  47. package/dist/pine-core/p-2af1d1d3.system.entry.js +1 -0
  48. package/dist/pine-core/p-2cc1ec4c.entry.js +1 -0
  49. package/dist/pine-core/{p-1e1804ed.system.entry.js → p-5f36fafa.system.entry.js} +1 -1
  50. package/dist/pine-core/p-621fdce1.entry.js +1 -0
  51. package/dist/pine-core/{p-b0b6acdb.system.entry.js → p-8a00e32b.system.entry.js} +1 -1
  52. package/dist/pine-core/p-BKsJZTyn.js +1 -0
  53. package/dist/pine-core/p-C61CFP22.system.js +1 -1
  54. package/dist/pine-core/p-Cr7-rJtJ.system.js +1 -0
  55. package/dist/pine-core/p-af48e6ae.entry.js +1 -0
  56. package/dist/pine-core/{p-cce6dcf0.system.entry.js → p-c7c17fe3.system.entry.js} +1 -1
  57. package/dist/pine-core/p-e48161a5.entry.js +1 -0
  58. package/dist/pine-core/p-fda3f3c6.entry.js +1 -0
  59. package/dist/pine-core/pine-core.esm.js +1 -1
  60. package/dist/types/components/pds-alert/pds-alert.d.ts +6 -0
  61. package/dist/types/components/pds-avatar/pds-avatar.d.ts +6 -0
  62. package/dist/types/components/pds-chip/pds-chip.d.ts +5 -0
  63. package/dist/types/components/pds-multiselect/pds-multiselect.d.ts +67 -4
  64. package/dist/types/components/pds-textarea/pds-textarea.d.ts +6 -0
  65. package/dist/types/components/pds-toast/pds-toast.d.ts +6 -0
  66. package/dist/types/components.d.ts +187 -9
  67. package/dist/types/i18n/i18n-format.d.ts +38 -0
  68. package/dist/types/i18n/index.d.ts +2 -0
  69. package/hydrate/index.js +211 -28
  70. package/hydrate/index.mjs +211 -28
  71. package/package.json +3 -2
  72. package/dist/pine-core/p-190ba1df.entry.js +0 -1
  73. package/dist/pine-core/p-638e9cb3.entry.js +0 -1
  74. package/dist/pine-core/p-68121613.system.entry.js +0 -1
  75. package/dist/pine-core/p-829c52dc.entry.js +0 -1
  76. package/dist/pine-core/p-a739bdfa.entry.js +0 -1
  77. package/dist/pine-core/p-b88be8be.entry.js +0 -1
  78. package/dist/pine-core/p-f2315f2a.entry.js +0 -1
  79. package/dist/pine-core/p-f928817f.system.entry.js +0 -1
@@ -3,6 +3,7 @@ import { computePosition, flip, offset, shift, size, autoUpdate } from "@floatin
3
3
  import { debounceEvent } from "../../utils/utils";
4
4
  import { isSpecTest, messageId, assignDescription } from "../../utils/form";
5
5
  import { danger, enlarge } from "@pine-ds/icons/icons";
6
+ import { formatMessage, pluralize } from "../../i18n";
6
7
  /**
7
8
  * @slot (default) - Static option elements for the multiselect
8
9
  * @slot empty - Custom empty state message when no options match
@@ -13,14 +14,65 @@ import { danger, enlarge } from "@pine-ds/icons/icons";
13
14
  export class PdsMultiselect {
14
15
  constructor() {
15
16
  /**
16
- * Placeholder text for the input field.
17
+ * Placeholder text for the input field. Pass a translated string to localize it; defaults to English.
18
+ * @defaultValue 'Select...'
17
19
  */
18
20
  this.placeholder = 'Select...';
19
21
  /**
20
- * Placeholder text for the search input inside the dropdown panel.
21
- * @default 'Find...'
22
+ * Placeholder text for the search input inside the dropdown panel. Pass a translated string to localize it; defaults to English.
23
+ * @defaultValue 'Find...'
22
24
  */
23
25
  this.searchPlaceholder = 'Find...';
26
+ /**
27
+ * Accessible label for the search input. Pass a translated string to localize it; defaults to English.
28
+ * @defaultValue 'Search options'
29
+ */
30
+ this.searchOptionsLabel = 'Search options';
31
+ /**
32
+ * Accessible label for the selected-items region. Pass a translated string to localize it; defaults to English.
33
+ * @defaultValue 'Selected items'
34
+ */
35
+ this.selectedItemsLabel = 'Selected items';
36
+ /**
37
+ * Accessible label for the options listbox (falls back to this when `label` is unset). Pass a translated string to localize it; defaults to English.
38
+ * @defaultValue 'Options'
39
+ */
40
+ this.optionsLabel = 'Options';
41
+ /**
42
+ * Text shown when no options match the search. Pass a translated string to localize it; defaults to English.
43
+ * @defaultValue 'No options found'
44
+ */
45
+ this.noOptionsFoundLabel = 'No options found';
46
+ /**
47
+ * Visible label for the create-new-option row. Pass a translated string to localize it; `{text}` is interpolated.
48
+ * @defaultValue 'Add "{text}"'
49
+ */
50
+ this.createOptionLabel = 'Add "{text}"';
51
+ /**
52
+ * Accessible label for the create-new-option row. Pass a translated string to localize it; `{text}` is interpolated.
53
+ * @defaultValue 'Create new tag: {text}'
54
+ */
55
+ this.createOptionAriaLabel = 'Create new tag: {text}';
56
+ /**
57
+ * Screen-reader announcement when an item is removed. Pass a translated string to localize it; `{item}` is interpolated.
58
+ * @defaultValue '{item} removed'
59
+ */
60
+ this.itemRemovedLabel = '{item} removed';
61
+ /**
62
+ * Accessible label for the remove button on each selected-item pill. Pass a translated string to localize it; defaults to English.
63
+ * @defaultValue 'Remove'
64
+ */
65
+ this.pillRemoveLabel = 'Remove';
66
+ /**
67
+ * Singular form of the selected-count trigger text. Pass a translated string to localize it; `{count}` is interpolated.
68
+ * @defaultValue '{count} item'
69
+ */
70
+ this.selectedCountLabelOne = '{count} item';
71
+ /**
72
+ * Plural (and fallback) form of the selected-count trigger text — used for English and any locale whose selected plural category isn't supplied via `selectedCountLabels`. Pass a translated string to localize it; `{count}` is interpolated.
73
+ * @defaultValue '{count} items'
74
+ */
75
+ this.selectedCountLabelOther = '{count} items';
24
76
  /**
25
77
  * Whether to close the panel after an option is selected.
26
78
  * Defaults to `false` (panel stays open for multi-select).
@@ -259,7 +311,7 @@ export class PdsMultiselect {
259
311
  this.pdsMultiselectChange.emit({ values: this.value, items: this.selectedItems });
260
312
  // Clear first so screen readers re-announce even when the same item is removed twice
261
313
  this.removalAnnouncement = '';
262
- queueMicrotask(() => { this.removalAnnouncement = `${item.text} removed`; });
314
+ queueMicrotask(() => { this.removalAnnouncement = formatMessage(this.itemRemovedLabel, { item: item.text }); });
263
315
  this.isClosingViaSelection = true;
264
316
  if (this.isOpen) {
265
317
  (_a = this.searchInputEl) === null || _a === void 0 ? void 0 : _a.focus();
@@ -896,7 +948,7 @@ export class PdsMultiselect {
896
948
  'pds-multiselect__option--selected': isSelected,
897
949
  'pds-multiselect__option--create': isCreateOption,
898
950
  'pds-multiselect__option--disabled': isDisabled || isCreateDisabled,
899
- }, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": isDisabled || isCreateDisabled ? 'true' : undefined, "aria-label": isCreateOption ? `Create new tag: ${option.text}` : undefined, "data-index": index, onMouseDown: this.handleOptionMouseDown(option), onMouseEnter: this.handleOptionMouseEnter(index, option) }, isCreateOption ? (h("pds-box", { class: "pds-multiselect__create-option", "align-items": "center", gap: "xs" }, h("pds-icon", { name: "add", size: "small" }), h("pds-text", null, "Add \"", option.text, "\""))) : (h("pds-checkbox", { componentId: `${this.componentId}-checkbox-${index}`, checked: isSelected, label: option.text, disabled: isDisabled, style: { pointerEvents: 'none' } }))));
951
+ }, role: "option", "aria-selected": isSelected ? 'true' : 'false', "aria-disabled": isDisabled || isCreateDisabled ? 'true' : undefined, "aria-label": isCreateOption ? formatMessage(this.createOptionAriaLabel, { text: option.text }) : undefined, "data-index": index, onMouseDown: this.handleOptionMouseDown(option), onMouseEnter: this.handleOptionMouseEnter(index, option) }, isCreateOption ? (h("pds-box", { class: "pds-multiselect__create-option", "align-items": "center", gap: "xs" }, h("pds-icon", { name: "add", size: "small" }), h("pds-text", null, formatMessage(this.createOptionLabel, { text: option.text })))) : (h("pds-checkbox", { componentId: `${this.componentId}-checkbox-${index}`, checked: isSelected, label: option.text, disabled: isDisabled, style: { pointerEvents: 'none' } }))));
900
952
  }
901
953
  renderSelectedItemsList() {
902
954
  if (this.hideSelectedItems || this.selectedItems.length === 0)
@@ -910,7 +962,7 @@ export class PdsMultiselect {
910
962
  const valueArray = this.ensureValueArray();
911
963
  const hasSlottedEmpty = !!this.el.querySelector('[slot="empty"]');
912
964
  const hasSlottedLoading = !!this.el.querySelector('[slot="loading"]');
913
- return (h("div", { class: "pds-multiselect__panel", ref: el => (this.panelEl = el), style: { minWidth: this.minWidth } }, h("div", { class: "pds-multiselect__search" }, h("pds-icon", { name: "search", size: "small" }), h("input", { ref: el => (this.searchInputEl = el), type: "text", class: "pds-multiselect__search-input", placeholder: this.searchPlaceholder, value: this.searchQuery, "aria-label": "Search options", "aria-controls": `${this.componentId}-listbox`, "aria-activedescendant": this.highlightedIndex >= 0 ? `${this.componentId}-option-${this.highlightedIndex}` : undefined, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": "true", "aria-autocomplete": "list", autocomplete: "off", onInput: this.handleSearchInputChange, onKeyDown: this.handleSearchInputKeyDown })), this.renderSelectedItemsList(), h("ul", { class: "pds-multiselect__listbox", role: "listbox", "aria-multiselectable": "true", "aria-label": this.label || 'Options', id: `${this.componentId}-listbox`, ref: el => (this.listboxEl = el), style: { maxHeight: this.maxHeight }, onScroll: this.handleScroll }, this.loading && (h("li", { class: "pds-multiselect__loading", role: "presentation" }, hasSlottedLoading ? (h("slot", { name: "loading" })) : (h("pds-loader", { size: "small" })))), !this.loading && filteredOptions.length === 0 && (h("li", { class: "pds-multiselect__empty", role: "presentation" }, hasSlottedEmpty ? (h("slot", { name: "empty" })) : (h("span", null, "No options found")))), this.getGroupedRenderItems(filteredOptions).map((item, itemIndex) => {
965
+ return (h("div", { class: "pds-multiselect__panel", ref: el => (this.panelEl = el), style: { minWidth: this.minWidth } }, h("div", { class: "pds-multiselect__search" }, h("pds-icon", { name: "search", size: "small" }), h("input", { ref: el => (this.searchInputEl = el), type: "text", class: "pds-multiselect__search-input", placeholder: this.searchPlaceholder, value: this.searchQuery, "aria-label": this.searchOptionsLabel, "aria-controls": `${this.componentId}-listbox`, "aria-activedescendant": this.highlightedIndex >= 0 ? `${this.componentId}-option-${this.highlightedIndex}` : undefined, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": "true", "aria-autocomplete": "list", autocomplete: "off", onInput: this.handleSearchInputChange, onKeyDown: this.handleSearchInputKeyDown })), this.renderSelectedItemsList(), h("ul", { class: "pds-multiselect__listbox", role: "listbox", "aria-multiselectable": "true", "aria-label": this.label || this.optionsLabel, id: `${this.componentId}-listbox`, ref: el => (this.listboxEl = el), style: { maxHeight: this.maxHeight }, onScroll: this.handleScroll }, this.loading && (h("li", { class: "pds-multiselect__loading", role: "presentation" }, hasSlottedLoading ? (h("slot", { name: "loading" })) : (h("pds-loader", { size: "small" })))), !this.loading && filteredOptions.length === 0 && (h("li", { class: "pds-multiselect__empty", role: "presentation" }, hasSlottedEmpty ? (h("slot", { name: "empty" })) : (h("span", null, this.noOptionsFoundLabel)))), this.getGroupedRenderItems(filteredOptions).map((item, itemIndex) => {
914
966
  if (item.type === 'group') {
915
967
  return (h("li", { key: `group-${itemIndex}`, role: "group", "aria-label": item.group, class: "pds-multiselect__group" }, h("span", { class: "pds-multiselect__group-header", "aria-hidden": "true" }, item.group), h("ul", { class: "pds-multiselect__group-list", role: "presentation" }, item.options.map(({ option, index }) => this.renderOption(option, index, valueArray)))));
916
968
  }
@@ -925,27 +977,54 @@ export class PdsMultiselect {
925
977
  const variant = this.disabled ? 'text' : 'tag';
926
978
  const visibleItems = this.selectedItems.slice(0, Math.max(1, this.maxInlinePills));
927
979
  const overflowCount = this.selectedItems.length - visibleItems.length;
928
- return (h("div", { class: "pds-multiselect__pill-list pds-multiselect__pill-list--inline", "aria-label": "Selected items" }, visibleItems.map(item => (h("pds-chip", { key: String(item.id), "component-id": `${this.componentId}-pill-${item.id}`, variant: variant, size: "sm", sentiment: "neutral", onPdsTagCloseClick: this.handlePillRemove(item) }, item.text))), overflowCount > 0 && (h("span", { class: "pds-multiselect__pill-overflow" }, "+", overflowCount))));
980
+ return (h("div", { class: "pds-multiselect__pill-list pds-multiselect__pill-list--inline", "aria-label": this.selectedItemsLabel }, visibleItems.map(item => (h("pds-chip", { key: String(item.id), "component-id": `${this.componentId}-pill-${item.id}`, variant: variant, size: "sm", sentiment: "neutral", "dismiss-label": this.pillRemoveLabel, onPdsTagCloseClick: this.handlePillRemove(item) }, item.text))), overflowCount > 0 && (h("span", { class: "pds-multiselect__pill-overflow" }, "+", overflowCount))));
929
981
  }
930
982
  renderBelowPills() {
931
983
  if (this.selectedItems.length === 0)
932
984
  return null;
933
985
  const variant = this.disabled ? 'text' : 'tag';
934
- return (h("div", { class: "pds-multiselect__pill-list pds-multiselect__pill-list--below", "aria-label": "Selected items" }, this.selectedItems.map(item => (h("pds-chip", { key: String(item.id), "component-id": `${this.componentId}-pill-${item.id}`, variant: variant, size: "md", sentiment: "neutral", onPdsTagCloseClick: this.handlePillRemove(item) }, item.text)))));
986
+ return (h("div", { class: "pds-multiselect__pill-list pds-multiselect__pill-list--below", "aria-label": this.selectedItemsLabel }, this.selectedItems.map(item => (h("pds-chip", { key: String(item.id), "component-id": `${this.componentId}-pill-${item.id}`, variant: variant, size: "md", sentiment: "neutral", "dismiss-label": this.pillRemoveLabel, onPdsTagCloseClick: this.handlePillRemove(item) }, item.text)))));
935
987
  }
936
988
  getTriggerText() {
937
989
  const count = this.selectedItems.length;
938
990
  if (count === 0 || (this.selectedDisplay === 'pill' && this.pillPosition === 'below')) {
991
+ // Fall back to a non-empty string: the trigger's accessible name comes from
992
+ // this text, so an empty/undefined placeholder must never leave it nameless
993
+ // (WCAG 4.1.2). The prop is localizable; this last-resort default is not.
939
994
  return this.placeholder || 'Select...';
940
995
  }
941
- return `${count} item${count === 1 ? '' : 's'}`;
996
+ return pluralize(this.el, count, this.resolveCountForms());
997
+ }
998
+ /**
999
+ * The `one`/`other` props are the ergonomic English defaults; `selectedCountLabels`
1000
+ * (object or JSON-string attribute) layers full CLDR forms on top for locales
1001
+ * that need `few`/`many`/`two`/`zero`. Malformed JSON degrades to the defaults.
1002
+ */
1003
+ resolveCountForms() {
1004
+ const base = {
1005
+ one: this.selectedCountLabelOne,
1006
+ other: this.selectedCountLabelOther,
1007
+ };
1008
+ const extra = this.selectedCountLabels;
1009
+ if (!extra)
1010
+ return base;
1011
+ if (typeof extra === 'string') {
1012
+ try {
1013
+ const parsed = JSON.parse(extra);
1014
+ return parsed && typeof parsed === 'object' ? Object.assign(Object.assign({}, base), parsed) : base;
1015
+ }
1016
+ catch (_a) {
1017
+ return base; // not valid JSON → fall back to the English-shape defaults
1018
+ }
1019
+ }
1020
+ return Object.assign(Object.assign({}, base), extra);
942
1021
  }
943
1022
  render() {
944
1023
  const hasSelections = this.selectedItems.length > 0;
945
- return (h(Host, { key: '086b6d2d199b35110e64ba1da3c12f1a81360581', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: 'c2faf217a97de056a9111a78e7077025e4ab5ee1', class: "pds-multiselect", onFocusout: this.handleContainerFocusOut }, this.label && (h("label", { key: '0aff86a3a0054aef256bac5c0204dd914a9bd3ae', id: `${this.componentId}-label`, htmlFor: this.componentId, class: {
1024
+ return (h(Host, { key: '4a54a778522d0a1d2f45c32928e7a663f19c0189', "aria-disabled": this.disabled ? 'true' : null }, h("div", { key: '3593eb4fa1a0ae575b1c0ed03f0763dcea04c9e6', class: "pds-multiselect", onFocusout: this.handleContainerFocusOut }, this.label && (h("label", { key: 'f91a680ae3c3021bac6bd99368d3ef6ad6438898', id: `${this.componentId}-label`, htmlFor: this.componentId, class: {
946
1025
  'pds-multiselect__label': true,
947
1026
  'visually-hidden': this.hideLabel,
948
- } }, this.label)), h("div", { key: '3b92119871dc32bb3c9a559be816bdece2fc30a6', class: "pds-multiselect__wrapper", ref: el => (this.containerEl = el), style: { width: this.triggerWidth } }, this.selectedDisplay === 'pill' && this.pillPosition === 'inline' ? (h("div", { ref: el => (this.pillInlineTriggerEl = el || undefined), part: "trigger", class: {
1027
+ } }, this.label)), h("div", { key: 'de2899f19057b8cd19cf3467251d03c1b43b73f5', class: "pds-multiselect__wrapper", ref: el => (this.containerEl = el), style: { width: this.triggerWidth } }, this.selectedDisplay === 'pill' && this.pillPosition === 'inline' ? (h("div", { ref: el => (this.pillInlineTriggerEl = el || undefined), part: "trigger", class: {
949
1028
  'pds-multiselect__trigger': true,
950
1029
  'pds-multiselect__trigger--open': this.isOpen,
951
1030
  'pds-multiselect__trigger--disabled': this.disabled,
@@ -961,7 +1040,7 @@ export class PdsMultiselect {
961
1040
  }, id: this.componentId, disabled: this.disabled, "aria-required": this.required ? 'true' : undefined, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-haspopup": "listbox", "aria-describedby": assignDescription(this.componentId, this.invalid || !!this.errorMessage, this.errorMessage || this.helperMessage), "aria-invalid": this.invalid || !!this.errorMessage ? 'true' : undefined, onClick: this.handleTriggerClick, onKeyDown: this.handleTriggerKeyDown }, h("span", { class: {
962
1041
  'pds-multiselect__trigger-text': true,
963
1042
  'pds-multiselect__trigger-text--placeholder': !hasSelections || (this.selectedDisplay === 'pill' && this.pillPosition === 'below'),
964
- } }, this.getTriggerText()), h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: '07d6a6bf9ccc2fe8bfcf9502a1cd4b7abf5c5e6f', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: 'a94bb6f31805d31ec3cd5b5f2ca8b1984f4d41d1', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: '15afc6b9313e1fe22bd56b00eee1ebcf9e085c2e', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: '452814577b14ca8f891b101903bd1a7a7e5d8bb1', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: 'd8ce787886e666303759cd2654c78b44269a40ff', style: { display: 'none' } }, h("slot", { key: '8295376fb03b23d44c5baeca9bc967514e433e0f' })))));
1043
+ } }, this.getTriggerText()), h("pds-icon", { class: "pds-multiselect__icon", icon: enlarge }))), this.renderDropdown()), this.selectedDisplay === 'pill' && this.pillPosition === 'below' && this.renderBelowPills(), h("span", { key: '973443f9eb29dcf7fb1bde3f9101ac02967a8fd9', class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }, this.removalAnnouncement), this.helperMessage && !(this.errorMessage && this.errorMessage.length > 0) && (h("p", { key: '568aab2b278abb7f4426d84ee926b4883375fb11', class: "pds-multiselect__helper", id: messageId(this.componentId, 'helper') }, this.helperMessage)), this.errorMessage && (h("p", { key: 'daddf192efd47df8c15267b9896913b926e02544', class: "pds-multiselect__error", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: 'd0c72ab75a8e02e61c09e980ae817790804a776a', icon: danger, size: "small" }), this.errorMessage)), h("div", { key: '0453db2fca10b3573b1dd244875f90c856c8887b', style: { display: 'none' } }, h("slot", { key: 'a612741afc9545e5e50c47d27c3c27c1d7cade3c' })))));
965
1044
  }
966
1045
  static get is() { return "pds-multiselect"; }
967
1046
  static get encapsulation() { return "shadow"; }
@@ -1025,10 +1104,13 @@ export class PdsMultiselect {
1025
1104
  "references": {}
1026
1105
  },
1027
1106
  "required": false,
1028
- "optional": true,
1107
+ "optional": false,
1029
1108
  "docs": {
1030
- "tags": [],
1031
- "text": "Placeholder text for the input field."
1109
+ "tags": [{
1110
+ "name": "defaultValue",
1111
+ "text": "'Select...'"
1112
+ }],
1113
+ "text": "Placeholder text for the input field. Pass a translated string to localize it; defaults to English."
1032
1114
  },
1033
1115
  "getter": false,
1034
1116
  "setter": false,
@@ -1048,10 +1130,10 @@ export class PdsMultiselect {
1048
1130
  "optional": false,
1049
1131
  "docs": {
1050
1132
  "tags": [{
1051
- "name": "default",
1133
+ "name": "defaultValue",
1052
1134
  "text": "'Find...'"
1053
1135
  }],
1054
- "text": "Placeholder text for the search input inside the dropdown panel."
1136
+ "text": "Placeholder text for the search input inside the dropdown panel. Pass a translated string to localize it; defaults to English."
1055
1137
  },
1056
1138
  "getter": false,
1057
1139
  "setter": false,
@@ -1059,6 +1141,265 @@ export class PdsMultiselect {
1059
1141
  "attribute": "search-placeholder",
1060
1142
  "defaultValue": "'Find...'"
1061
1143
  },
1144
+ "searchOptionsLabel": {
1145
+ "type": "string",
1146
+ "mutable": false,
1147
+ "complexType": {
1148
+ "original": "string",
1149
+ "resolved": "string",
1150
+ "references": {}
1151
+ },
1152
+ "required": false,
1153
+ "optional": false,
1154
+ "docs": {
1155
+ "tags": [{
1156
+ "name": "defaultValue",
1157
+ "text": "'Search options'"
1158
+ }],
1159
+ "text": "Accessible label for the search input. Pass a translated string to localize it; defaults to English."
1160
+ },
1161
+ "getter": false,
1162
+ "setter": false,
1163
+ "reflect": false,
1164
+ "attribute": "search-options-label",
1165
+ "defaultValue": "'Search options'"
1166
+ },
1167
+ "selectedItemsLabel": {
1168
+ "type": "string",
1169
+ "mutable": false,
1170
+ "complexType": {
1171
+ "original": "string",
1172
+ "resolved": "string",
1173
+ "references": {}
1174
+ },
1175
+ "required": false,
1176
+ "optional": false,
1177
+ "docs": {
1178
+ "tags": [{
1179
+ "name": "defaultValue",
1180
+ "text": "'Selected items'"
1181
+ }],
1182
+ "text": "Accessible label for the selected-items region. Pass a translated string to localize it; defaults to English."
1183
+ },
1184
+ "getter": false,
1185
+ "setter": false,
1186
+ "reflect": false,
1187
+ "attribute": "selected-items-label",
1188
+ "defaultValue": "'Selected items'"
1189
+ },
1190
+ "optionsLabel": {
1191
+ "type": "string",
1192
+ "mutable": false,
1193
+ "complexType": {
1194
+ "original": "string",
1195
+ "resolved": "string",
1196
+ "references": {}
1197
+ },
1198
+ "required": false,
1199
+ "optional": false,
1200
+ "docs": {
1201
+ "tags": [{
1202
+ "name": "defaultValue",
1203
+ "text": "'Options'"
1204
+ }],
1205
+ "text": "Accessible label for the options listbox (falls back to this when `label` is unset). Pass a translated string to localize it; defaults to English."
1206
+ },
1207
+ "getter": false,
1208
+ "setter": false,
1209
+ "reflect": false,
1210
+ "attribute": "options-label",
1211
+ "defaultValue": "'Options'"
1212
+ },
1213
+ "noOptionsFoundLabel": {
1214
+ "type": "string",
1215
+ "mutable": false,
1216
+ "complexType": {
1217
+ "original": "string",
1218
+ "resolved": "string",
1219
+ "references": {}
1220
+ },
1221
+ "required": false,
1222
+ "optional": false,
1223
+ "docs": {
1224
+ "tags": [{
1225
+ "name": "defaultValue",
1226
+ "text": "'No options found'"
1227
+ }],
1228
+ "text": "Text shown when no options match the search. Pass a translated string to localize it; defaults to English."
1229
+ },
1230
+ "getter": false,
1231
+ "setter": false,
1232
+ "reflect": false,
1233
+ "attribute": "no-options-found-label",
1234
+ "defaultValue": "'No options found'"
1235
+ },
1236
+ "createOptionLabel": {
1237
+ "type": "string",
1238
+ "mutable": false,
1239
+ "complexType": {
1240
+ "original": "string",
1241
+ "resolved": "string",
1242
+ "references": {}
1243
+ },
1244
+ "required": false,
1245
+ "optional": false,
1246
+ "docs": {
1247
+ "tags": [{
1248
+ "name": "defaultValue",
1249
+ "text": "'Add \"{text}\"'"
1250
+ }],
1251
+ "text": "Visible label for the create-new-option row. Pass a translated string to localize it; `{text}` is interpolated."
1252
+ },
1253
+ "getter": false,
1254
+ "setter": false,
1255
+ "reflect": false,
1256
+ "attribute": "create-option-label",
1257
+ "defaultValue": "'Add \"{text}\"'"
1258
+ },
1259
+ "createOptionAriaLabel": {
1260
+ "type": "string",
1261
+ "mutable": false,
1262
+ "complexType": {
1263
+ "original": "string",
1264
+ "resolved": "string",
1265
+ "references": {}
1266
+ },
1267
+ "required": false,
1268
+ "optional": false,
1269
+ "docs": {
1270
+ "tags": [{
1271
+ "name": "defaultValue",
1272
+ "text": "'Create new tag: {text}'"
1273
+ }],
1274
+ "text": "Accessible label for the create-new-option row. Pass a translated string to localize it; `{text}` is interpolated."
1275
+ },
1276
+ "getter": false,
1277
+ "setter": false,
1278
+ "reflect": false,
1279
+ "attribute": "create-option-aria-label",
1280
+ "defaultValue": "'Create new tag: {text}'"
1281
+ },
1282
+ "itemRemovedLabel": {
1283
+ "type": "string",
1284
+ "mutable": false,
1285
+ "complexType": {
1286
+ "original": "string",
1287
+ "resolved": "string",
1288
+ "references": {}
1289
+ },
1290
+ "required": false,
1291
+ "optional": false,
1292
+ "docs": {
1293
+ "tags": [{
1294
+ "name": "defaultValue",
1295
+ "text": "'{item} removed'"
1296
+ }],
1297
+ "text": "Screen-reader announcement when an item is removed. Pass a translated string to localize it; `{item}` is interpolated."
1298
+ },
1299
+ "getter": false,
1300
+ "setter": false,
1301
+ "reflect": false,
1302
+ "attribute": "item-removed-label",
1303
+ "defaultValue": "'{item} removed'"
1304
+ },
1305
+ "pillRemoveLabel": {
1306
+ "type": "string",
1307
+ "mutable": false,
1308
+ "complexType": {
1309
+ "original": "string",
1310
+ "resolved": "string",
1311
+ "references": {}
1312
+ },
1313
+ "required": false,
1314
+ "optional": false,
1315
+ "docs": {
1316
+ "tags": [{
1317
+ "name": "defaultValue",
1318
+ "text": "'Remove'"
1319
+ }],
1320
+ "text": "Accessible label for the remove button on each selected-item pill. Pass a translated string to localize it; defaults to English."
1321
+ },
1322
+ "getter": false,
1323
+ "setter": false,
1324
+ "reflect": false,
1325
+ "attribute": "pill-remove-label",
1326
+ "defaultValue": "'Remove'"
1327
+ },
1328
+ "selectedCountLabelOne": {
1329
+ "type": "string",
1330
+ "mutable": false,
1331
+ "complexType": {
1332
+ "original": "string",
1333
+ "resolved": "string",
1334
+ "references": {}
1335
+ },
1336
+ "required": false,
1337
+ "optional": false,
1338
+ "docs": {
1339
+ "tags": [{
1340
+ "name": "defaultValue",
1341
+ "text": "'{count} item'"
1342
+ }],
1343
+ "text": "Singular form of the selected-count trigger text. Pass a translated string to localize it; `{count}` is interpolated."
1344
+ },
1345
+ "getter": false,
1346
+ "setter": false,
1347
+ "reflect": false,
1348
+ "attribute": "selected-count-label-one",
1349
+ "defaultValue": "'{count} item'"
1350
+ },
1351
+ "selectedCountLabelOther": {
1352
+ "type": "string",
1353
+ "mutable": false,
1354
+ "complexType": {
1355
+ "original": "string",
1356
+ "resolved": "string",
1357
+ "references": {}
1358
+ },
1359
+ "required": false,
1360
+ "optional": false,
1361
+ "docs": {
1362
+ "tags": [{
1363
+ "name": "defaultValue",
1364
+ "text": "'{count} items'"
1365
+ }],
1366
+ "text": "Plural (and fallback) form of the selected-count trigger text \u2014 used for English and any locale whose selected plural category isn't supplied via `selectedCountLabels`. Pass a translated string to localize it; `{count}` is interpolated."
1367
+ },
1368
+ "getter": false,
1369
+ "setter": false,
1370
+ "reflect": false,
1371
+ "attribute": "selected-count-label-other",
1372
+ "defaultValue": "'{count} items'"
1373
+ },
1374
+ "selectedCountLabels": {
1375
+ "type": "string",
1376
+ "mutable": false,
1377
+ "complexType": {
1378
+ "original": "PluralForms | string",
1379
+ "resolved": "\"few\" | \"many\" | \"one\" | \"other\" | \"two\" | \"zero\" | string",
1380
+ "references": {
1381
+ "PluralForms": {
1382
+ "location": "import",
1383
+ "path": "../../i18n",
1384
+ "id": "src/i18n/index.ts::PluralForms",
1385
+ "referenceLocation": "PluralForms"
1386
+ }
1387
+ }
1388
+ },
1389
+ "required": false,
1390
+ "optional": true,
1391
+ "docs": {
1392
+ "tags": [{
1393
+ "name": "defaultValue",
1394
+ "text": "undefined"
1395
+ }],
1396
+ "text": "Full CLDR plural forms for the selected-count trigger text, for locales with more than the English `one`/`other` categories (e.g. Polish `few`/`many`, Arabic `zero`/`two`). Accepts an object property or a JSON string attribute keyed by CLDR category \u2014 `{ one, other, few, many, two, zero }`. Any form omitted here falls back to `selectedCountLabelOne`/`selectedCountLabelOther`. `{count}` is interpolated."
1397
+ },
1398
+ "getter": false,
1399
+ "setter": false,
1400
+ "reflect": false,
1401
+ "attribute": "selected-count-labels"
1402
+ },
1062
1403
  "closePanelOnSelect": {
1063
1404
  "type": "boolean",
1064
1405
  "mutable": false,
@@ -3,6 +3,7 @@ import { assignDescription, isRequired, isSpecTest, messageId, exposeTypePropert
3
3
  import { debounceEvent } from "../../utils/utils";
4
4
  import { inheritAttributes, inheritAriaAttributes } from "../../utils/attributes";
5
5
  import { danger } from "@pine-ds/icons/icons";
6
+ import { formatMessage } from "../../i18n";
6
7
  /**
7
8
  * @slot action - Content to be displayed in the label area, typically for help icons or links
8
9
  */
@@ -43,6 +44,12 @@ export class PdsTextarea {
43
44
  * If true, the textarea has action content in the label area
44
45
  */
45
46
  this.hasAction = false;
47
+ /**
48
+ * Template for the character-counter's accessible label. Pass a translated
49
+ * string to localize it; `{current}` and `{max}` are interpolated.
50
+ * @defaultValue '{current} of {max} characters'
51
+ */
52
+ this.characterCountLabel = '{current} of {max} characters';
46
53
  this.onBlur = (ev) => {
47
54
  this.hasFocus = false;
48
55
  if (this.focusedValue !== this.value) {
@@ -240,7 +247,7 @@ export class PdsTextarea {
240
247
  return null;
241
248
  }
242
249
  const currentLength = this.getValue().length;
243
- return (h("div", { class: "pds-textarea__character-counter", ref: (el) => this.characterCounter = el, role: "status", "aria-live": "polite", "aria-label": `${currentLength} of ${this.maxLength} characters` }, currentLength, " / ", this.maxLength));
250
+ return (h("div", { class: "pds-textarea__character-counter", ref: (el) => this.characterCounter = el, role: "status", "aria-live": "polite", "aria-label": formatMessage(this.characterCountLabel, { current: currentLength, max: this.maxLength }) }, currentLength, " / ", this.maxLength));
244
251
  }
245
252
  renderAction() {
246
253
  const hasAction = this.el.querySelector('[slot="action"]') !== null;
@@ -294,10 +301,10 @@ export class PdsTextarea {
294
301
  }
295
302
  render() {
296
303
  const value = this.getValue();
297
- return (h(Host, { key: '09726ef6454fe84a5c8d0ea25c6e8a7a6da128f9', "aria-disabled": this.disabled ? 'true' : null, "aria-readonly": this.readonly ? 'true' : null, "has-action": this.hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: '6244104f11d26b25a908fbaf13a815988a3c33d9', class: "pds-textarea" }, this.label &&
298
- h("div", { key: '5dd7f6caedd7ebf5ecaacf8d111ec5e2426e84ae', class: "pds-textarea__label-wrapper" }, h("label", { key: 'd19f62cd28612423abf0d5696ff1cd88f39d32fe', htmlFor: this.componentId }, h("span", { key: '37f4e9e34ae3205bafa5f1bc8574a98d3a90060d', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), !this.hideLabel && this.renderAction()), h("div", { key: '4c3c8fadc5596630485ee1775f5d87d77c11d95b', class: "pds-textarea__field-wrapper" }, h("textarea", Object.assign({ key: 'a60be5f3d362cb9bcd2ecf5af16ffc467fc8322a', ref: (el) => this.nativeTextarea = el, "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, autocomplete: this.autocomplete, class: this.textareaClassNames(), disabled: this.disabled, id: this.componentId, maxlength: this.maxLength, name: this.name, placeholder: this.placeholder, readOnly: this.readonly, required: this.required, rows: this.rows, onBlur: this.onBlur, onChange: this.onTextareaChange, onFocus: this.onFocus, onInput: this.onInput, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value), this.renderCharacterCounter()), this.helperMessage &&
299
- h("p", { key: 'ae03337ef85ac2a3995e967fe671e0ad2c352710', class: "pds-textarea__helper-message", id: messageId(this.componentId, 'helper') }, this.helperMessage), this.invalid &&
300
- h("p", { key: 'a2bda9a477e7d2b81862833da43158a626d8cc6f', "aria-live": "assertive", class: "pds-textarea__error-message", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: '5ac785e8012aeb49dd0b1c5823233671531b0a7a', icon: danger, size: "small" }), this.errorMessage))));
304
+ return (h(Host, { key: '838d12ba686fb041996c44522d3fd30e1b56c610', "aria-disabled": this.disabled ? 'true' : null, "aria-readonly": this.readonly ? 'true' : null, "has-action": this.hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: 'bd3eef138a5c8f2cd4e48c007561bb1b12f4e575', class: "pds-textarea" }, this.label &&
305
+ h("div", { key: 'f83f23b17cd157d48bb5c0c5067ca5f611d73529', class: "pds-textarea__label-wrapper" }, h("label", { key: '896b7b495ad6f7deb8d4738e623f0676f0a98c1f', htmlFor: this.componentId }, h("span", { key: '02b06db969467f6c4e83e0f713bee0be76f8dfff', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), !this.hideLabel && this.renderAction()), h("div", { key: '15c5964576e73db36cee4a9ca868c28571250a27', class: "pds-textarea__field-wrapper" }, h("textarea", Object.assign({ key: '74713a5d438fc01103ca99f0c77abd84b7d2d16a', ref: (el) => this.nativeTextarea = el, "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, autocomplete: this.autocomplete, class: this.textareaClassNames(), disabled: this.disabled, id: this.componentId, maxlength: this.maxLength, name: this.name, placeholder: this.placeholder, readOnly: this.readonly, required: this.required, rows: this.rows, onBlur: this.onBlur, onChange: this.onTextareaChange, onFocus: this.onFocus, onInput: this.onInput, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value), this.renderCharacterCounter()), this.helperMessage &&
306
+ h("p", { key: 'e42f174f4153363ce745db264fd3a9ee46178a03', class: "pds-textarea__helper-message", id: messageId(this.componentId, 'helper') }, this.helperMessage), this.invalid &&
307
+ h("p", { key: '44189515611ff9fa51d2815a7066626b6ba5df2c', "aria-live": "assertive", class: "pds-textarea__error-message", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: '64d275da09cdf1c2cc27d4c0a780dd414c265534', icon: danger, size: "small" }), this.errorMessage))));
301
308
  }
302
309
  static get is() { return "pds-textarea"; }
303
310
  static get encapsulation() { return "shadow"; }
@@ -654,6 +661,29 @@ export class PdsTextarea {
654
661
  "reflect": false,
655
662
  "attribute": "value",
656
663
  "defaultValue": "''"
664
+ },
665
+ "characterCountLabel": {
666
+ "type": "string",
667
+ "mutable": false,
668
+ "complexType": {
669
+ "original": "string",
670
+ "resolved": "string",
671
+ "references": {}
672
+ },
673
+ "required": false,
674
+ "optional": false,
675
+ "docs": {
676
+ "tags": [{
677
+ "name": "defaultValue",
678
+ "text": "'{current} of {max} characters'"
679
+ }],
680
+ "text": "Template for the character-counter's accessible label. Pass a translated\nstring to localize it; `{current}` and `{max}` are interpolated."
681
+ },
682
+ "getter": false,
683
+ "setter": false,
684
+ "reflect": false,
685
+ "attribute": "character-count-label",
686
+ "defaultValue": "'{current} of {max} characters'"
657
687
  }
658
688
  };
659
689
  }
@@ -26,6 +26,12 @@ export class PdsToast {
26
26
  * @default 'default'
27
27
  */
28
28
  this.type = 'default';
29
+ /**
30
+ * Accessible label for the dismiss button. Pass a translated string to
31
+ * localize it; defaults to English.
32
+ * @defaultValue 'Dismiss message'
33
+ */
34
+ this.dismissLabel = 'Dismiss message';
29
35
  /**
30
36
  * Whether the toast is currently visible.
31
37
  */
@@ -115,13 +121,13 @@ export class PdsToast {
115
121
  return this.icon && h("pds-icon", { name: this.icon, class: "pds-toast__icon" });
116
122
  }
117
123
  render() {
118
- return (h(Host, { key: '7768cbf398d4592b774734abdf5e9f1f4d4fb7e8', hidden: !this.isVisible }, h("div", { key: 'c17b00c76bd42d1040b8ef08a354e10346a79aa4', class: {
124
+ return (h(Host, { key: 'a1ec97158a6665aa25b58b1954b4b5c622590615', hidden: !this.isVisible }, h("div", { key: 'd9b01164364c76512852a260cede50000b73a563', class: {
119
125
  'pds-toast': true,
120
126
  [`pds-toast--${this.type}`]: this.type !== 'default',
121
127
  'pds-toast--animating-out': this.isAnimatingOut
122
- }, role: "alert", "aria-live": "polite" }, this.renderIcon(), h("span", { key: 'cb7066fd49ae8674d5de80ecde21e63eecbcdf29', class: "pds-toast__message" }, h("slot", { key: '5c08d8b5cc54e02bed2906c2d52b894301fdca5d' })), this.dismissible && (h("button", { key: '4edd83a8521f76a2abddfe64caaac932962745ff', type: "button", part: "dismiss", class: "pds-toast__button", onClick: () => {
128
+ }, role: "alert", "aria-live": "polite" }, this.renderIcon(), h("span", { key: '1f581c7c29ea3fc795dfca061d3575c5a9895b3c', class: "pds-toast__message" }, h("slot", { key: '645b31eae3be23de63ab2562234caf0be2510645' })), this.dismissible && (h("button", { key: '44a62b304468c0fca0b8d490ad9c8b5932176ac9', type: "button", part: "dismiss", class: "pds-toast__button", onClick: () => {
123
129
  this.dismiss();
124
- }, "aria-label": "Dismiss message" }, h("pds-icon", { key: 'c5cf65f889bfcd85e3fdab437539e7ee3f6e0465', name: "remove" }))))));
130
+ }, "aria-label": this.dismissLabel }, h("pds-icon", { key: 'fde63f279f696d9f02875cc1beee3542c97f0c7e', name: "remove" }))))));
125
131
  }
126
132
  static get is() { return "pds-toast"; }
127
133
  static get encapsulation() { return "shadow"; }
@@ -243,6 +249,29 @@ export class PdsToast {
243
249
  "reflect": false,
244
250
  "attribute": "type",
245
251
  "defaultValue": "'default'"
252
+ },
253
+ "dismissLabel": {
254
+ "type": "string",
255
+ "mutable": false,
256
+ "complexType": {
257
+ "original": "string",
258
+ "resolved": "string",
259
+ "references": {}
260
+ },
261
+ "required": false,
262
+ "optional": false,
263
+ "docs": {
264
+ "tags": [{
265
+ "name": "defaultValue",
266
+ "text": "'Dismiss message'"
267
+ }],
268
+ "text": "Accessible label for the dismiss button. Pass a translated string to\nlocalize it; defaults to English."
269
+ },
270
+ "getter": false,
271
+ "setter": false,
272
+ "reflect": false,
273
+ "attribute": "dismiss-label",
274
+ "defaultValue": "'Dismiss message'"
246
275
  }
247
276
  };
248
277
  }