@nova-design-system/nova-webcomponents 3.10.0 → 3.11.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 (55) hide show
  1. package/dist/cjs/nv-alert.cjs.entry.js +1 -1
  2. package/dist/cjs/nv-alert.cjs.entry.js.map +1 -1
  3. package/dist/cjs/nv-badge_2.cjs.entry.js +7 -1
  4. package/dist/cjs/nv-badge_2.cjs.entry.js.map +1 -1
  5. package/dist/cjs/nv-fieldmultiselect.cjs.entry.js +112 -72
  6. package/dist/cjs/nv-fieldmultiselect.cjs.entry.js.map +1 -1
  7. package/dist/cjs/nv-tooltip.cjs.entry.js +1 -1
  8. package/dist/cjs/nv-tooltip.cjs.entry.js.map +1 -1
  9. package/dist/collection/components/nv-alert/nv-alert.css +1 -0
  10. package/dist/collection/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.js +7 -1
  11. package/dist/collection/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.js.map +1 -1
  12. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.js +112 -72
  13. package/dist/collection/components/nv-fieldmultiselect/nv-fieldmultiselect.js.map +1 -1
  14. package/dist/collection/components/nv-tooltip/nv-tooltip.css +2 -2
  15. package/dist/components/nv-alert.js +1 -1
  16. package/dist/components/nv-alert.js.map +1 -1
  17. package/dist/components/nv-breadcrumb.js +1 -1
  18. package/dist/components/nv-fielddropdownitemcheck.js +1 -1
  19. package/dist/components/nv-fieldmultiselect.js +113 -73
  20. package/dist/components/nv-fieldmultiselect.js.map +1 -1
  21. package/dist/components/nv-tooltip.js +1 -1
  22. package/dist/components/{p-51a156ff.js → p-ec4558aa.js} +8 -2
  23. package/dist/components/p-ec4558aa.js.map +1 -0
  24. package/dist/components/{p-2ef4fb88.js → p-f47a1e1e.js} +2 -2
  25. package/dist/{native/p-49504fd6.entry.js.map → components/p-f47a1e1e.js.map} +1 -1
  26. package/dist/esm/nv-alert.entry.js +1 -1
  27. package/dist/esm/nv-alert.entry.js.map +1 -1
  28. package/dist/esm/nv-badge_2.entry.js +7 -1
  29. package/dist/esm/nv-badge_2.entry.js.map +1 -1
  30. package/dist/esm/nv-fieldmultiselect.entry.js +112 -72
  31. package/dist/esm/nv-fieldmultiselect.entry.js.map +1 -1
  32. package/dist/esm/nv-tooltip.entry.js +1 -1
  33. package/dist/esm/nv-tooltip.entry.js.map +1 -1
  34. package/dist/native/native.css +1 -1
  35. package/dist/native/native.esm.js +1 -1
  36. package/dist/native/p-019d164d.entry.js +2 -0
  37. package/dist/native/p-019d164d.entry.js.map +1 -0
  38. package/dist/native/p-4f4ed012.entry.js +2 -0
  39. package/dist/native/p-4f4ed012.entry.js.map +1 -0
  40. package/dist/native/p-8a577f91.entry.js +2 -0
  41. package/dist/native/p-8a577f91.entry.js.map +1 -0
  42. package/dist/native/{p-13032ec1.entry.js → p-9991116a.entry.js} +2 -2
  43. package/dist/native/{p-13032ec1.entry.js.map → p-9991116a.entry.js.map} +1 -1
  44. package/dist/types/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.d.ts +2 -0
  45. package/dist/types/components/nv-fieldmultiselect/nv-fieldmultiselect.d.ts +3 -0
  46. package/hydrate/index.js +122 -76
  47. package/hydrate/index.mjs +122 -76
  48. package/package.json +1 -1
  49. package/dist/components/p-2ef4fb88.js.map +0 -1
  50. package/dist/components/p-51a156ff.js.map +0 -1
  51. package/dist/native/p-2a3325fb.entry.js +0 -2
  52. package/dist/native/p-2a3325fb.entry.js.map +0 -1
  53. package/dist/native/p-49504fd6.entry.js +0 -2
  54. package/dist/native/p-b2442d4b.entry.js +0 -2
  55. package/dist/native/p-b2442d4b.entry.js.map +0 -1
@@ -93,6 +93,7 @@ nv-alert > nv-icon.icon-neutral {
93
93
  nv-alert > .content {
94
94
  display: flex;
95
95
  padding: var(--alert-padding);
96
+ padding-right: calc(var(--alert-padding) + var(--icon-md) + var(--spacing-1));
96
97
  padding-left: 0;
97
98
  flex-direction: column;
98
99
  gap: var(--alert-gap-y);
@@ -17,6 +17,9 @@ export class NvFielddropdownitemcheck {
17
17
  * Disables the item, preventing any user interaction.
18
18
  */
19
19
  this.disabled = false;
20
+ //#endregion EVENTS
21
+ /****************************************************************************/
22
+ //#region METHODS
20
23
  /**
21
24
  * when the child <nv-fieldcheckbox> change its `checked` state,
22
25
  * update `this.checked` and emit `itemChecked`.
@@ -45,8 +48,11 @@ export class NvFielddropdownitemcheck {
45
48
  }
46
49
  };
47
50
  }
51
+ //#endregion METHODS
52
+ /****************************************************************************/
53
+ //#region RENDER
48
54
  render() {
49
- return (h(Host, { key: '869eb969c0cff66f1947673e5aa3e0c677a07421', onClick: this.handleClick }, h("nv-fieldcheckbox", { key: '4bbe45597bdd0f30c8e9a255e52d08be476fab1a', checked: this.checked, name: this.label || this.value, label: this.label || this.value, labelPlacement: "after", description: this.description, disabled: this.disabled, tabindex: "-1", onCheckedChanged: this.onFieldcheckboxChanged }, h("slot", { key: 'f53f44e3fdb78894e9bb37fa455b1407efea17b1' }), h("slot", { key: 'aacd757c1fec541a4fc7b4f2683281aef31ee135', name: "main" }), h("slot", { key: 'ef2f761a3a1f05dcba6145efc89830ddc82af27d', name: "label" }), h("slot", { key: '610700f871b524f1f89538d03bd6c16167e3b24e', name: "description" }))));
55
+ return (h(Host, { key: 'cb922f0c0224c950ab5a87783028f2909eb1e39c', onClick: this.handleClick }, h("nv-fieldcheckbox", { key: '6f8748022131a8cd31b0f69851313f80c330172a', checked: this.checked, name: this.label || this.value, label: this.label || this.value, labelPlacement: "after", description: this.description, disabled: this.disabled, tabindex: "-1", onCheckedChanged: this.onFieldcheckboxChanged }, h("slot", { key: '20d1014accc6cfc00658703057b25037175287af' }), h("slot", { key: 'a7e61eed6bc72d3a14096cac2c195629a0ce2928', name: "main" }), h("slot", { key: '93f6bce370ac36f1ce3e0f2c1d9cdd598c14cb14', name: "label" }), h("slot", { key: '837359fc1fea49e0dea221039dc7466cdc86b757', name: "description" }))));
50
56
  }
51
57
  static get is() { return "nv-fielddropdownitemcheck"; }
52
58
  static get originalStyleUrls() {
@@ -1 +1 @@
1
- {"version":3,"file":"nv-fielddropdownitemcheck.js","sourceRoot":"","sources":["../../../src/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,KAAK,EAEL,OAAO,GACR,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AAMH,MAAM,OAAO,wBAAwB;IALrC;QAQE,8EAA8E;QAC9E,oBAAoB;QAEpB;;WAEG;QAEH,YAAO,GAAY,KAAK,CAAC;QA2BzB;;WAEG;QAEM,aAAQ,GAAY,KAAK,CAAC;QA0BnC;;;;WAIG;QACK,2BAAsB,GAAG,CAAC,KAA2B,EAAE,EAAE;YAC/D,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAC1B,6CAA6C;YAC7C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,oBAAoB;YACjD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;gBACpB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,2EAA2E;QACnE,gBAAW,GAAG,GAAG,EAAE;YACzB,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAC1B,IAAI,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC3C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;KAuBH;IArBC,MAAM;QACJ,OAAO,CACL,EAAC,IAAI,qDAAC,OAAO,EAAE,IAAI,CAAC,WAAW;YAC7B,yEACE,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAC9B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAC/B,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,IAAI,CAAC,WAAW,EAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,QAAQ,EAAC,IAAI,EACb,gBAAgB,EAAE,IAAI,CAAC,sBAAsB;gBAE7C,8DAAa;gBACb,6DAAM,IAAI,EAAC,MAAM,GAAQ;gBACzB,6DAAM,IAAI,EAAC,OAAO,GAAQ;gBAC1B,6DAAM,IAAI,EAAC,aAAa,GAAQ,CACf,CACd,CACR,CAAC;IACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF","sourcesContent":["import {\n Component,\n Host,\n h,\n Prop,\n Event,\n EventEmitter,\n Element,\n} from '@stencil/core';\n\n/**\n * @slot default - Next to the label and description.\n * @slot main - Replaces the label and description.\n * @slot label - Content to be placed as the label, will override the label prop.\n * @slot description - Content to be placed as the description, will override the description prop.\n */\n@Component({\n tag: 'nv-fielddropdownitemcheck',\n styleUrl: 'nv-fielddropdownitemcheck.scss',\n shadow: false,\n})\nexport class NvFielddropdownitemcheck {\n @Element() el: HTMLNvFielddropdownitemcheckElement;\n\n /****************************************************************************/\n //#region PROPERTIES\n\n /**\n * Indicates whether the checkbox is selected.\n */\n @Prop({ reflect: true, mutable: true })\n checked: boolean = false;\n\n /**\n * The value associated with this item.\n */\n @Prop({ reflect: true })\n readonly value?: string;\n\n /**\n * The label displayed alongside the checkbox.\n */\n @Prop({ reflect: true })\n readonly label?: string;\n\n /**\n * A description providing additional context or information about the\n * checkbox.\n */\n @Prop({ reflect: true })\n readonly description?: string;\n\n /**\n * The group this item belongs to, if applicable.\n */\n @Prop({ reflect: true })\n readonly group?: string;\n\n /**\n * Disables the item, preventing any user interaction.\n */\n @Prop({ reflect: true })\n readonly disabled: boolean = false;\n\n //#endregion PROPERTIES\n /****************************************************************************/\n //#region EVENTS\n\n /**\n * Event emitted when the checkbox is toggled.\n * It provides details about the current state of the item.\n */\n @Event()\n itemChecked: EventEmitter<{\n /**\n * The value associated with this item\n */\n value: string | undefined;\n /**\n * Whether the checkbox is currently checked\n */\n checked: boolean;\n /**\n * The group this item belongs to, if any\n */\n group?: string | undefined;\n }>;\n\n /**\n * when the child <nv-fieldcheckbox> change its `checked` state,\n * update `this.checked` and emit `itemChecked`.\n * @param {CustomEvent<boolean>} event - The event emitted by the <nv-fieldcheckbox> component.\n */\n private onFieldcheckboxChanged = (event: CustomEvent<boolean>) => {\n if (this.disabled) return;\n // NvFieldcheckbox has emitted checkedChanged\n this.checked = event.detail; // get the new state\n this.itemChecked.emit({\n value: this.value,\n checked: this.checked,\n group: this.group,\n });\n };\n\n /** Make sure the checkbox is checked when clicked anywhere in the item. */\n private handleClick = () => {\n if (this.disabled) return;\n if (this.el.querySelector('input').checked) {\n this.checked = false;\n } else {\n this.checked = true;\n }\n };\n\n render() {\n return (\n <Host onClick={this.handleClick}>\n <nv-fieldcheckbox\n checked={this.checked}\n name={this.label || this.value}\n label={this.label || this.value}\n labelPlacement=\"after\"\n description={this.description}\n disabled={this.disabled}\n tabindex=\"-1\"\n onCheckedChanged={this.onFieldcheckboxChanged}\n >\n <slot></slot>\n <slot name=\"main\"></slot>\n <slot name=\"label\"></slot>\n <slot name=\"description\"></slot>\n </nv-fieldcheckbox>\n </Host>\n );\n }\n}\n"]}
1
+ {"version":3,"file":"nv-fielddropdownitemcheck.js","sourceRoot":"","sources":["../../../src/components/nv-fielddropdownitemcheck/nv-fielddropdownitemcheck.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,KAAK,EAEL,OAAO,GACR,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AAMH,MAAM,OAAO,wBAAwB;IALrC;QAQE,8EAA8E;QAC9E,oBAAoB;QAEpB;;WAEG;QAEH,YAAO,GAAY,KAAK,CAAC;QA2BzB;;WAEG;QAEM,aAAQ,GAAY,KAAK,CAAC;QA0BnC,mBAAmB;QACnB,8EAA8E;QAC9E,iBAAiB;QAEjB;;;;WAIG;QACK,2BAAsB,GAAG,CAAC,KAA2B,EAAE,EAAE;YAC/D,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAE1B,6CAA6C;YAC7C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,oBAAoB;YACjD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;gBACpB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,2EAA2E;QACnE,gBAAW,GAAG,GAAG,EAAE;YACzB,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAE1B,IAAI,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC3C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;KA8BH;IA5BC,oBAAoB;IACpB,8EAA8E;IAC9E,gBAAgB;IAEhB,MAAM;QACJ,OAAO,CACL,EAAC,IAAI,qDAAC,OAAO,EAAE,IAAI,CAAC,WAAW;YAC7B,yEACE,OAAO,EAAE,IAAI,CAAC,OAAO,EACrB,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAC9B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAC/B,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,IAAI,CAAC,WAAW,EAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,QAAQ,EAAC,IAAI,EACb,gBAAgB,EAAE,IAAI,CAAC,sBAAsB;gBAE7C,8DAAa;gBACb,6DAAM,IAAI,EAAC,MAAM,GAAQ;gBACzB,6DAAM,IAAI,EAAC,OAAO,GAAQ;gBAC1B,6DAAM,IAAI,EAAC,aAAa,GAAQ,CACf,CACd,CACR,CAAC;IACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIF","sourcesContent":["import {\n Component,\n Host,\n h,\n Prop,\n Event,\n EventEmitter,\n Element,\n} from '@stencil/core';\n\n/**\n * @slot default - Next to the label and description.\n * @slot main - Replaces the label and description.\n * @slot label - Content to be placed as the label, will override the label prop.\n * @slot description - Content to be placed as the description, will override the description prop.\n */\n@Component({\n tag: 'nv-fielddropdownitemcheck',\n styleUrl: 'nv-fielddropdownitemcheck.scss',\n shadow: false,\n})\nexport class NvFielddropdownitemcheck {\n @Element() el: HTMLNvFielddropdownitemcheckElement;\n\n /****************************************************************************/\n //#region PROPERTIES\n\n /**\n * Indicates whether the checkbox is selected.\n */\n @Prop({ reflect: true, mutable: true })\n checked: boolean = false;\n\n /**\n * The value associated with this item.\n */\n @Prop({ reflect: true })\n readonly value?: string;\n\n /**\n * The label displayed alongside the checkbox.\n */\n @Prop({ reflect: true })\n readonly label?: string;\n\n /**\n * A description providing additional context or information about the\n * checkbox.\n */\n @Prop({ reflect: true })\n readonly description?: string;\n\n /**\n * The group this item belongs to, if applicable.\n */\n @Prop({ reflect: true })\n readonly group?: string;\n\n /**\n * Disables the item, preventing any user interaction.\n */\n @Prop({ reflect: true })\n readonly disabled: boolean = false;\n\n //#endregion PROPERTIES\n /****************************************************************************/\n //#region EVENTS\n\n /**\n * Event emitted when the checkbox is toggled.\n * It provides details about the current state of the item.\n */\n @Event()\n itemChecked: EventEmitter<{\n /**\n * The value associated with this item\n */\n value: string | undefined;\n /**\n * Whether the checkbox is currently checked\n */\n checked: boolean;\n /**\n * The group this item belongs to, if any\n */\n group?: string | undefined;\n }>;\n\n //#endregion EVENTS\n /****************************************************************************/\n //#region METHODS\n\n /**\n * when the child <nv-fieldcheckbox> change its `checked` state,\n * update `this.checked` and emit `itemChecked`.\n * @param {CustomEvent<boolean>} event - The event emitted by the <nv-fieldcheckbox> component.\n */\n private onFieldcheckboxChanged = (event: CustomEvent<boolean>) => {\n if (this.disabled) return;\n\n // NvFieldcheckbox has emitted checkedChanged\n this.checked = event.detail; // get the new state\n this.itemChecked.emit({\n value: this.value,\n checked: this.checked,\n group: this.group,\n });\n };\n\n /** Make sure the checkbox is checked when clicked anywhere in the item. */\n private handleClick = () => {\n if (this.disabled) return;\n\n if (this.el.querySelector('input').checked) {\n this.checked = false;\n } else {\n this.checked = true;\n }\n };\n\n //#endregion METHODS\n /****************************************************************************/\n //#region RENDER\n\n render() {\n return (\n <Host onClick={this.handleClick}>\n <nv-fieldcheckbox\n checked={this.checked}\n name={this.label || this.value}\n label={this.label || this.value}\n labelPlacement=\"after\"\n description={this.description}\n disabled={this.disabled}\n tabindex=\"-1\"\n onCheckedChanged={this.onFieldcheckboxChanged}\n >\n <slot></slot>\n <slot name=\"main\"></slot>\n <slot name=\"label\"></slot>\n <slot name=\"description\"></slot>\n </nv-fieldcheckbox>\n </Host>\n );\n }\n\n //#endregion RENDER\n /****************************************************************************/\n}\n"]}
@@ -11,6 +11,7 @@ import { v4 as uuidv4 } from "uuid";
11
11
  */
12
12
  export class NvFieldmultiselect {
13
13
  constructor() {
14
+ this.isBulkOperation = false;
14
15
  /**
15
16
  * Sets the ID for the input element and the for attribute of the associated
16
17
  * label. If no ID is provided, a random one will be automatically generated
@@ -118,6 +119,9 @@ export class NvFieldmultiselect {
118
119
  this.isSelectAllSectionVisible = true;
119
120
  // Add the flag to the class
120
121
  this.preventBlurClose = false;
122
+ this.handleMouseDownPreventBlur = () => {
123
+ this.preventBlurClose = true;
124
+ };
121
125
  /**
122
126
  * Handle badge close for options mode.
123
127
  */
@@ -304,6 +308,11 @@ export class NvFieldmultiselect {
304
308
  */
305
309
  this.handleInputBlurSlots = () => {
306
310
  setTimeout(() => {
311
+ // Honor preventBlurClose to avoid closing when interacting inside the popover
312
+ if (this.preventBlurClose) {
313
+ this.preventBlurClose = false;
314
+ return; // Don't close the popover
315
+ }
307
316
  if (!this.el.contains(document.activeElement)) {
308
317
  // Close the popover without affecting the divider
309
318
  this.open = false;
@@ -340,24 +349,33 @@ export class NvFieldmultiselect {
340
349
  this.toggleSelectAllOptions = (selectAll) => {
341
350
  if (!this.options)
342
351
  return;
343
- // Get visible and enabled option values from DOM
344
- const visibleOptionValues = this.getVisibleEnabledOptionItems();
345
- console.info('[SelectAll][Options] toggleSelectAllOptions called. selectAll:', selectAll, 'visibleOptionValues:', visibleOptionValues, 'Current value:', this.value);
346
- if (selectAll) {
347
- // Select all visible options - merge with existing selections
348
- this.value = [...new Set([...this.value, ...visibleOptionValues])];
352
+ this.isBulkOperation = true; // Set flag to suppress individual emissions
353
+ try {
354
+ // Get visible and enabled option values from DOM
355
+ const visibleOptionValues = this.getVisibleEnabledOptionItems();
356
+ console.info('[SelectAll][Options] toggleSelectAllOptions called. selectAll:', selectAll, 'visibleOptionValues:', visibleOptionValues, 'Current value:', this.value);
357
+ if (selectAll) {
358
+ // Select all visible options - merge with existing selections
359
+ this.value = [...new Set([...this.value, ...visibleOptionValues])];
360
+ }
361
+ else {
362
+ // Deselect only the visible options, keep others that might be filtered out
363
+ this.value = this.value.filter(val => !visibleOptionValues.includes(val));
364
+ }
365
+ console.info('[SelectAll][Options] New value after toggle:', this.value);
366
+ // Emit the change event
367
+ this.valueChanged.emit(this.value);
368
+ // Synchronize child components
369
+ this.syncChildComponents();
370
+ // Reorder content to move selected items to top
371
+ this.reorderOptionsContent();
349
372
  }
350
- else {
351
- // Deselect only the visible options, keep others that might be filtered out
352
- this.value = this.value.filter(val => !visibleOptionValues.includes(val));
373
+ finally {
374
+ // Defer reset to next frame to ensure any async child emissions are ignored
375
+ requestAnimationFrame(() => {
376
+ this.isBulkOperation = false; // Reset flag
377
+ });
353
378
  }
354
- console.info('[SelectAll][Options] New value after toggle:', this.value);
355
- // Emit the change event
356
- this.valueChanged.emit(this.value);
357
- // Synchronize child components
358
- this.syncChildComponents();
359
- // Reorder content to move selected items to top
360
- this.reorderOptionsContent();
361
379
  };
362
380
  /**
363
381
  * Toggles the selection state of all non-disabled slot items.
@@ -366,31 +384,40 @@ export class NvFieldmultiselect {
366
384
  this.toggleSelectAllSlots = (selectAll) => {
367
385
  if (this.options)
368
386
  return; // Only for slots mode
369
- // Get visible and enabled items
370
- const items = this.getVisibleEnabledSlotItems();
371
- console.info('[SelectAll][Slots] toggleSelectAllSlots called. selectAll:', selectAll, 'visible slot items:', items.map(item => item.getAttribute('value') || item.getAttribute('label')), 'Current value:', this.value);
372
- if (selectAll) {
373
- // Select all visible items
374
- const allActiveValues = items
375
- .map(item => item.getAttribute('value') || item.getAttribute('label') || '')
376
- .filter(value => value !== '');
377
- this.value = [...new Set([...this.value, ...allActiveValues])];
387
+ this.isBulkOperation = true; // Set flag to suppress individual emissions
388
+ try {
389
+ // Get visible and enabled items
390
+ const items = this.getVisibleEnabledSlotItems();
391
+ console.info('[SelectAll][Slots] toggleSelectAllSlots called. selectAll:', selectAll, 'visible slot items:', items.map(item => item.getAttribute('value') || item.getAttribute('label')), 'Current value:', this.value);
392
+ if (selectAll) {
393
+ // Select all visible items
394
+ const allActiveValues = items
395
+ .map(item => item.getAttribute('value') || item.getAttribute('label') || '')
396
+ .filter(value => value !== '');
397
+ this.value = [...new Set([...this.value, ...allActiveValues])];
398
+ }
399
+ else {
400
+ // Deselect only the visible items, keep others that might be filtered out
401
+ const visibleValues = items
402
+ .map(item => item.getAttribute('value') || item.getAttribute('label') || '')
403
+ .filter(value => value !== '');
404
+ this.value = this.value.filter(val => !visibleValues.includes(val));
405
+ }
406
+ console.info('[SelectAll][Slots] New value after toggle:', this.value);
407
+ // Emit the change event
408
+ this.valueChanged.emit(this.value);
409
+ // Force synchronization with a small delay to ensure DOM is updated
410
+ requestAnimationFrame(() => {
411
+ this.syncChildComponents();
412
+ this.reorderSlotContent();
413
+ });
378
414
  }
379
- else {
380
- // Deselect only the visible items, keep others that might be filtered out
381
- const visibleValues = items
382
- .map(item => item.getAttribute('value') || item.getAttribute('label') || '')
383
- .filter(value => value !== '');
384
- this.value = this.value.filter(val => !visibleValues.includes(val));
415
+ finally {
416
+ // Defer reset to next frame to ensure any async child emissions are ignored
417
+ requestAnimationFrame(() => {
418
+ this.isBulkOperation = false; // Reset flag
419
+ });
385
420
  }
386
- console.info('[SelectAll][Slots] New value after toggle:', this.value);
387
- // Emit the change event
388
- this.valueChanged.emit(this.value);
389
- // Force synchronization with a small delay to ensure DOM is updated
390
- requestAnimationFrame(() => {
391
- this.syncChildComponents();
392
- this.reorderSlotContent();
393
- });
394
421
  };
395
422
  /**
396
423
  * Handle click on the select all checkbox in options mode.
@@ -442,16 +469,10 @@ export class NvFieldmultiselect {
442
469
  width: '0',
443
470
  height: '0',
444
471
  pointerEvents: 'none',
445
- }, tabIndex: -1, "aria-hidden": "true", autoComplete: this.autocomplete, name: this.name, onFocus: this.handleInputFocusOptions }), h("p", { id: this.inputId, class: "non-filterable-text", onClick: this.handleInputContainerClickOptions, tabIndex: 0, onKeyDown: this.handleKeyDown, onFocus: this.handleInputFocusOptions, "aria-label": this.label, "aria-controls": `${this.inputId}-listbox`, "data-scope": "focusable", role: "button" }, h("span", null, this.placeholder)))), this.error && (h("nv-icon", { name: "alert-circle", class: "validation", size: "md" })), this.filterable && this.filterText.length > 0 && (h("nv-iconbutton", { "data-scope": "clear-filter", name: "x", size: "md", emphasis: "lower", "aria-label": "Clear filter text", tabindex: "-1", title: "Clear filter text", onMouseDown: () => {
446
- this.preventBlurClose = true;
447
- }, onClick: this.clearFilterText })), h("nv-iconbutton", { "data-scope": "toggle-dropdown", name: this.open ? 'chevron-top' : 'chevron-down', size: "md", emphasis: "lower", "aria-label": this.open ? 'Hide dropdown' : 'Show dropdown', title: this.open ? 'Hide dropdown' : 'Show dropdown', onMouseDown: () => {
448
- this.preventBlurClose = true;
449
- }, onClick: this.togglePopoverOptions })), h("slot", { name: "after-input" })), h("div", { id: `${this.inputId}-listbox`, slot: "content", style: this.maxHeight ? { maxHeight: this.maxHeight } : {} }, this.shouldShowToggleAllOptionsButton() && (h("div", { class: "select-all-container" }, h("div", { class: "select-all-header" }, this.isSelectAllSectionVisible && (h("nv-fieldcheckbox", { checked: this.getSelectAllCheckboxStateOptions() === 'checked', indeterminate: this.getSelectAllCheckboxStateOptions() ===
472
+ }, tabIndex: -1, "aria-hidden": "true", autoComplete: this.autocomplete, name: this.name, onFocus: this.handleInputFocusOptions }), h("p", { id: this.inputId, class: "non-filterable-text", onClick: this.handleInputContainerClickOptions, tabIndex: 0, onKeyDown: this.handleKeyDown, onFocus: this.handleInputFocusOptions, "aria-label": this.label, "aria-controls": `${this.inputId}-listbox`, "data-scope": "focusable", role: "button" }, h("span", null, this.placeholder)))), this.error && (h("nv-icon", { name: "alert-circle", class: "validation", size: "md" })), this.filterable && this.filterText.length > 0 && (h("nv-iconbutton", { "data-scope": "clear-filter", name: "x", size: "md", emphasis: "lower", "aria-label": "Clear filter text", tabindex: "-1", title: "Clear filter text", onMouseDown: this.handleMouseDownPreventBlur, onClick: this.clearFilterText })), h("nv-iconbutton", { "data-scope": "toggle-dropdown", name: this.open ? 'chevron-top' : 'chevron-down', size: "md", emphasis: "lower", "aria-label": this.open ? 'Hide dropdown' : 'Show dropdown', title: this.open ? 'Hide dropdown' : 'Show dropdown', onMouseDown: this.handleMouseDownPreventBlur, onClick: this.togglePopoverOptions })), h("slot", { name: "after-input" })), h("div", { id: `${this.inputId}-listbox`, slot: "content", style: this.maxHeight ? { maxHeight: this.maxHeight } : {}, onMouseDown: this.handleMouseDownPreventBlur }, this.shouldShowToggleAllOptionsButton() && (h("div", { class: "select-all-container" }, h("div", { class: "select-all-header" }, this.isSelectAllSectionVisible && (h("nv-fieldcheckbox", { checked: this.getSelectAllCheckboxStateOptions() === 'checked', indeterminate: this.getSelectAllCheckboxStateOptions() ===
450
473
  'indeterminate', label: this.getSelectAllCheckboxStateOptions() === 'unchecked'
451
474
  ? this.selectAllLabel
452
- : this.deselectAllLabel, onMouseDown: () => {
453
- this.preventBlurClose = true;
454
- }, onClick: this.handleSelectAllCheckboxOptionsClick }))))), h("ul", { role: "listbox", "aria-multiselectable": "true" }, this.options.map(option => (h("nv-fielddropdownitemcheck", { role: "option", label: option.label, description: option.description, value: option.value, checked: this.value.includes(option.value), disabled: option.disabled })))))), this.renderDescriptions()));
475
+ : this.deselectAllLabel, onMouseDown: this.handleMouseDownPreventBlur, onClick: this.handleSelectAllCheckboxOptionsClick }))))), h("ul", { role: "listbox", "aria-multiselectable": "true" }, this.options.map(option => (h("nv-fielddropdownitemcheck", { role: "option", label: option.label, description: option.description, value: option.value, checked: this.value.includes(option.value), disabled: option.disabled })))))), this.renderDescriptions()));
455
476
  };
456
477
  /**
457
478
  * Renders the component in slots mode
@@ -464,16 +485,10 @@ export class NvFieldmultiselect {
464
485
  width: '0',
465
486
  height: '0',
466
487
  pointerEvents: 'none',
467
- }, tabIndex: -1, "aria-hidden": "true", autoComplete: this.autocomplete, name: this.name, onFocus: this.handleInputFocusSlots }), h("p", { id: this.inputId, class: "non-filterable-text", "aria-label": this.label, onClick: this.handleInputContainerClickSlots, tabIndex: 0, onKeyDown: this.handleKeyDown, onFocus: this.handleInputFocusSlots, "aria-controls": `${this.inputId}-listbox`, "data-scope": "focusable", role: "button" }, h("span", null, this.placeholder)))), this.error && (h("nv-icon", { name: "alert-circle", class: "validation", size: "md" })), this.filterable && this.filterText.length > 0 && (h("nv-iconbutton", { name: "x", size: "md", emphasis: "lower", tabindex: "-1", onMouseDown: () => {
468
- this.preventBlurClose = true;
469
- }, onClick: this.clearFilterText, "aria-label": "Clear filter text" })), h("nv-iconbutton", { "data-scope": "toggle-dropdown", name: this.open ? 'chevron-top' : 'chevron-down', size: "md", emphasis: "lower", "aria-label": this.open ? 'Hide dropdown' : 'Show dropdown', title: this.open ? 'Hide dropdown' : 'Show dropdown', onMouseDown: () => {
470
- this.preventBlurClose = true;
471
- }, onClick: this.togglePopoverSlots })), h("slot", { name: "after-input" })), h("div", { id: `${this.inputId}-listbox`, slot: "content", style: this.maxHeight ? { maxHeight: this.maxHeight } : {} }, this.shouldShowToggleAllSlotButton() && (h("div", { class: "select-all-container" }, h("div", { class: "select-all-header" }, this.isSelectAllSectionVisible && (h("nv-fieldcheckbox", { checked: this.getSelectAllCheckboxStateSlots() === 'checked', indeterminate: this.getSelectAllCheckboxStateSlots() ===
488
+ }, tabIndex: -1, "aria-hidden": "true", autoComplete: this.autocomplete, name: this.name, onFocus: this.handleInputFocusSlots }), h("p", { id: this.inputId, class: "non-filterable-text", "aria-label": this.label, onClick: this.handleInputContainerClickSlots, tabIndex: 0, onKeyDown: this.handleKeyDown, onFocus: this.handleInputFocusSlots, "aria-controls": `${this.inputId}-listbox`, "data-scope": "focusable", role: "button" }, h("span", null, this.placeholder)))), this.error && (h("nv-icon", { name: "alert-circle", class: "validation", size: "md" })), this.filterable && this.filterText.length > 0 && (h("nv-iconbutton", { name: "x", size: "md", emphasis: "lower", tabindex: "-1", onMouseDown: this.handleMouseDownPreventBlur, onClick: this.clearFilterText, "aria-label": "Clear filter text" })), h("nv-iconbutton", { "data-scope": "toggle-dropdown", name: this.open ? 'chevron-top' : 'chevron-down', size: "md", emphasis: "lower", "aria-label": this.open ? 'Hide dropdown' : 'Show dropdown', title: this.open ? 'Hide dropdown' : 'Show dropdown', onMouseDown: this.handleMouseDownPreventBlur, onClick: this.togglePopoverSlots })), h("slot", { name: "after-input" })), h("div", { id: `${this.inputId}-listbox`, slot: "content", style: this.maxHeight ? { maxHeight: this.maxHeight } : {}, onMouseDown: this.handleMouseDownPreventBlur }, this.shouldShowToggleAllSlotButton() && (h("div", { class: "select-all-container" }, h("div", { class: "select-all-header" }, this.isSelectAllSectionVisible && (h("nv-fieldcheckbox", { checked: this.getSelectAllCheckboxStateSlots() === 'checked', indeterminate: this.getSelectAllCheckboxStateSlots() ===
472
489
  'indeterminate', label: this.getSelectAllCheckboxStateSlots() === 'unchecked'
473
490
  ? this.selectAllLabel
474
- : this.deselectAllLabel, onMouseDown: () => {
475
- this.preventBlurClose = true;
476
- }, onClick: this.handleSelectAllCheckboxSlotsClick }))))), h("slot", { name: "content" }))), this.renderDescriptions()));
491
+ : this.deselectAllLabel, onMouseDown: this.handleMouseDownPreventBlur, onClick: this.handleSelectAllCheckboxSlotsClick }))))), h("slot", { name: "content" }))), this.renderDescriptions()));
477
492
  };
478
493
  }
479
494
  //#endregion EVENTS
@@ -502,7 +517,12 @@ export class NvFieldmultiselect {
502
517
  this.reorderOptionsContent();
503
518
  }
504
519
  watchValueHandler() {
505
- console.info('[Watch:value] Value changed:', this.value);
520
+ console.info('[Watch:value] Value changed:', this.value, 'isBulkOperation:', this.isBulkOperation);
521
+ // Skip processing during bulk operations
522
+ if (this.isBulkOperation) {
523
+ console.info('[Watch:value] Skipping syncChildComponents and options update due to bulk operation');
524
+ return;
525
+ }
506
526
  // Synchronize child components when value changes programmatically
507
527
  if (this.el && this.el.isConnected) {
508
528
  this.syncChildComponents();
@@ -547,7 +567,9 @@ export class NvFieldmultiselect {
547
567
  * @param {CustomEvent} event - The event object containing the selected value and its checked state.
548
568
  */
549
569
  handleItemChecked(event) {
550
- if (this.disabled || this.readonly) {
570
+ if (this.disabled || this.readonly || this.isBulkOperation) {
571
+ // Skip processing itemChecked events during bulk operations
572
+ console.info('[Event:itemChecked] Skipped due to bulk operation or disabled/readonly', event.detail);
551
573
  return;
552
574
  }
553
575
  const { value, checked } = event.detail;
@@ -555,21 +577,23 @@ export class NvFieldmultiselect {
555
577
  if (value !== undefined && value !== null) {
556
578
  const newValue = [...this.value];
557
579
  const valueIndex = newValue.indexOf(value);
580
+ let hasChanged = false;
558
581
  if (checked && valueIndex === -1) {
559
582
  newValue.push(value);
583
+ hasChanged = true;
560
584
  }
561
585
  else if (!checked && valueIndex > -1) {
562
586
  newValue.splice(valueIndex, 1);
587
+ hasChanged = true;
563
588
  }
564
589
  console.info('[Event:itemChecked] newValue after update:', newValue);
565
- // Always update the state and emit the event when an item is checked/unchecked
566
- this.value = newValue;
567
- this.valueChanged.emit(this.value);
568
- // Update the checked state of all items to ensure consistency
569
- this.syncChildComponents();
590
+ if (hasChanged) {
591
+ this.value = newValue;
592
+ this.valueChanged.emit(this.value);
593
+ this.syncChildComponents();
594
+ }
570
595
  // Preserve the filter text in the input
571
596
  if (this.filterable && this.inputElement) {
572
- // Keep the current filter text in the input
573
597
  this.inputElement.value = this.filterText;
574
598
  }
575
599
  }
@@ -597,7 +621,11 @@ export class NvFieldmultiselect {
597
621
  */
598
622
  connectedCallback() {
599
623
  console.info('[Lifecycle] connectedCallback - value:', this.value);
600
- document.addEventListener('click', this.handleClickOutside.bind(this));
624
+ // Bind once and reuse the same reference for add/remove to avoid leaks
625
+ if (!this._boundHandleClickOutside) {
626
+ this._boundHandleClickOutside = this.handleClickOutside.bind(this);
627
+ }
628
+ document.addEventListener('click', this._boundHandleClickOutside);
601
629
  }
602
630
  /**
603
631
  * Set the mode state and handle options change.
@@ -655,7 +683,9 @@ export class NvFieldmultiselect {
655
683
  */
656
684
  disconnectedCallback() {
657
685
  console.info('[Lifecycle] disconnectedCallback - value:', this.value);
658
- document.removeEventListener('click', this.handleClickOutside.bind(this));
686
+ if (this._boundHandleClickOutside) {
687
+ document.removeEventListener('click', this._boundHandleClickOutside);
688
+ }
659
689
  }
660
690
  //#endregion LIFECYCLE
661
691
  /****************************************************************************/
@@ -1184,13 +1214,23 @@ export class NvFieldmultiselect {
1184
1214
  const itemValue = item.getAttribute('value') || item.getAttribute('label') || '';
1185
1215
  const shouldBeChecked = this.value.includes(itemValue);
1186
1216
  console.info('[syncChildComponents] itemValue:', itemValue, 'shouldBeChecked:', shouldBeChecked, 'item.checked(before):', item.checked);
1187
- if (shouldBeChecked) {
1188
- item.setAttribute('checked', '');
1189
- item.checked = true;
1190
- }
1191
- else {
1192
- item.removeAttribute('checked');
1193
- item.checked = false;
1217
+ // Only update if the checked state differs to avoid triggering unnecessary events
1218
+ if (item.checked !== shouldBeChecked) {
1219
+ // Set attribute and property, but avoid triggering itemChecked during bulk
1220
+ if (this.isBulkOperation) {
1221
+ // Directly update the DOM attribute to avoid triggering the setter
1222
+ if (shouldBeChecked) {
1223
+ item.setAttribute('checked', '');
1224
+ }
1225
+ else {
1226
+ item.removeAttribute('checked');
1227
+ }
1228
+ // Update internal state without emitting events (assumes nv-fielddropdownitemcheck respects this)
1229
+ item.checked = shouldBeChecked;
1230
+ }
1231
+ else {
1232
+ item.checked = shouldBeChecked;
1233
+ }
1194
1234
  }
1195
1235
  console.info('[syncChildComponents] itemValue:', itemValue, 'item.checked(after):', item.checked);
1196
1236
  });