@nordhealth/components 5.0.0 → 5.0.2

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 (132) hide show
  1. package/custom-elements.json +26062 -25769
  2. package/lib/AsideDrawer.js +2 -2
  3. package/lib/AsideDrawer.js.map +1 -1
  4. package/lib/AsideTrigger.js +2 -2
  5. package/lib/AsideTrigger.js.map +1 -1
  6. package/lib/Autocomplete.js +1 -1
  7. package/lib/Autocomplete.js.map +1 -1
  8. package/lib/Button.js +2 -2
  9. package/lib/Button.js.map +1 -1
  10. package/lib/Calendar.js +1 -1
  11. package/lib/Combobox.js +1 -1
  12. package/lib/Combobox.js.map +1 -1
  13. package/lib/ComboboxBase.js +1 -1
  14. package/lib/ComboboxBase.js.map +1 -1
  15. package/lib/CommandMenu.js +1 -1
  16. package/lib/CommandMenu.js.map +1 -1
  17. package/lib/DatePicker.js +1 -1
  18. package/lib/DatePicker.js.map +1 -1
  19. package/lib/DateRangePicker.js +1 -1
  20. package/lib/DateRangePicker.js.map +1 -1
  21. package/lib/Dropdown.js +1 -1
  22. package/lib/Dropdown.js.map +1 -1
  23. package/lib/DropdownSubmenu.js +1 -1
  24. package/lib/FilterAddButton.js +1 -1
  25. package/lib/FilterAddButton.js.map +1 -1
  26. package/lib/FilterDateRange.js +1 -1
  27. package/lib/FilterDateRange.js.map +1 -1
  28. package/lib/FilterDropdown.js +1 -1
  29. package/lib/FilterDropdown.js.map +1 -1
  30. package/lib/FilterField.js +1 -1
  31. package/lib/FilterField.js.map +1 -1
  32. package/lib/FilterInput.js +1 -1
  33. package/lib/FilterInput.js.map +1 -1
  34. package/lib/FilterResetButton.js +1 -1
  35. package/lib/FilterResetButton.js.map +1 -1
  36. package/lib/Header.js +1 -1
  37. package/lib/Header.js.map +1 -1
  38. package/lib/IconManager.js +1 -1
  39. package/lib/Input.js +1 -1
  40. package/lib/Item.js +1 -1
  41. package/lib/Item.js.map +1 -1
  42. package/lib/Layout.js +1 -1
  43. package/lib/Layout.js.map +1 -1
  44. package/lib/LocalizeController.js +1 -1
  45. package/lib/LocalizeController.js.map +1 -1
  46. package/lib/Message.js +1 -1
  47. package/lib/Message.js.map +1 -1
  48. package/lib/Modal.js +1 -1
  49. package/lib/Modal.js.map +1 -1
  50. package/lib/NavGroup.js +1 -1
  51. package/lib/NavGroup.js.map +1 -1
  52. package/lib/NavItem.js +1 -1
  53. package/lib/NavItem.js.map +1 -1
  54. package/lib/NavToggle-ROsuaJkW.js +2 -0
  55. package/lib/{NavToggle-BY83xpx0.js.map → NavToggle-ROsuaJkW.js.map} +1 -1
  56. package/lib/NavToggle.js +1 -1
  57. package/lib/Navigation.js +1 -1
  58. package/lib/Navigation.js.map +1 -1
  59. package/lib/Notification.js +1 -1
  60. package/lib/Notification.js.map +1 -1
  61. package/lib/NumberField.js +1 -1
  62. package/lib/NumberField.js.map +1 -1
  63. package/lib/OtpField.js +1 -1
  64. package/lib/OtpField.js.map +1 -1
  65. package/lib/Outline.js +1 -1
  66. package/lib/Outline.js.map +1 -1
  67. package/lib/Pagination.js +1 -1
  68. package/lib/Pagination.js.map +1 -1
  69. package/lib/Popout-B6Hirj3y.js +2 -0
  70. package/lib/{Popout-CFtFoCaA.js.map → Popout-B6Hirj3y.js.map} +1 -1
  71. package/lib/Popout.js +1 -1
  72. package/lib/Range.js +1 -1
  73. package/lib/SegmentedControlItem.js +1 -1
  74. package/lib/Tag.js +1 -1
  75. package/lib/Tag.js.map +1 -1
  76. package/lib/TextField-BYSciLeB.js +2 -0
  77. package/lib/TextField-BYSciLeB.js.map +1 -0
  78. package/lib/Textarea.js +1 -1
  79. package/lib/Textarea.js.map +1 -1
  80. package/lib/TimePicker.js +1 -1
  81. package/lib/TimePicker.js.map +1 -1
  82. package/lib/bundle.js +13 -13
  83. package/lib/bundle.js.map +1 -1
  84. package/lib/en-us.js +1 -1
  85. package/lib/en-us.js.map +1 -1
  86. package/lib/fi-fi.js +1 -1
  87. package/lib/fi-fi.js.map +1 -1
  88. package/lib/index.js +1 -1
  89. package/lib/localization13.js +1 -1
  90. package/lib/localization13.js.map +1 -1
  91. package/lib/localization14.js +1 -1
  92. package/lib/localization14.js.map +1 -1
  93. package/lib/localization15.js +1 -1
  94. package/lib/localization15.js.map +1 -1
  95. package/lib/localization16.js +1 -1
  96. package/lib/localization16.js.map +1 -1
  97. package/lib/localization17.js +1 -1
  98. package/lib/localization17.js.map +1 -1
  99. package/lib/localization18.js +1 -1
  100. package/lib/localization18.js.map +1 -1
  101. package/lib/localization19.js +1 -1
  102. package/lib/localization19.js.map +1 -1
  103. package/lib/localization20.js +1 -1
  104. package/lib/localization20.js.map +1 -1
  105. package/lib/localization21.js +1 -1
  106. package/lib/localization21.js.map +1 -1
  107. package/lib/localization22.js +1 -1
  108. package/lib/localization22.js.map +1 -1
  109. package/lib/localization23.js +1 -1
  110. package/lib/localization23.js.map +1 -1
  111. package/lib/localization24.js +2 -0
  112. package/lib/localization24.js.map +1 -0
  113. package/lib/nav-context.js +2 -0
  114. package/lib/nav-context.js.map +1 -0
  115. package/lib/src/aside-trigger/AsideTrigger.d.ts +28 -2
  116. package/lib/src/button/Button.d.ts +7 -0
  117. package/lib/src/dropdown/Dropdown.d.ts +3 -0
  118. package/lib/src/layout/Layout.d.ts +12 -0
  119. package/lib/src/layout/localization.d.ts +5 -0
  120. package/lib/src/localization/en-us.d.ts +4 -0
  121. package/lib/src/localization/translation.d.ts +4 -0
  122. package/lib/src/nav-group/NavGroup.d.ts +1 -0
  123. package/lib/src/nav-group/nav-context.d.ts +11 -0
  124. package/lib/src/nav-item/NavItem.d.ts +45 -0
  125. package/lib/src/navigation/Navigation.d.ts +18 -0
  126. package/lib/translation.js +1 -1
  127. package/lib/translation.js.map +1 -1
  128. package/package.json +8 -8
  129. package/lib/NavToggle-BY83xpx0.js +0 -2
  130. package/lib/Popout-CFtFoCaA.js +0 -2
  131. package/lib/TextField-CSKvieoG.js +0 -2
  132. package/lib/TextField-CSKvieoG.js.map +0 -1
package/lib/OtpField.js CHANGED
@@ -1,2 +1,2 @@
1
- import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{css as e,nothing as i,html as o,LitElement as n}from"lit";import{property as l,customElement as s}from"lit/decorators.js";import{ifDefined as r}from"lit/directives/if-defined.js";import{F as a}from"./FormDataController-OUt5L5uC.js";import{S as d}from"./StateAttributesController-BIh96sXZ.js";import{o as h}from"./observe-D0n0zOfU.js";import{N as u}from"./events-Bv6wNHwJ.js";import{i as c}from"./light-dom-styles-DXsbiKU9.js";import{D as p}from"./DraftComponentMixin-4qug5Rky.js";import{F as v}from"./FieldControlMixin-BXNZJXu9.js";import{I as f}from"./InputMixin-LetXsCyv.js";import{S as g}from"./SizeMixin-CU9cLbLC.js";import{LocalizeController as m}from"./LocalizeController.js";import{OtpFieldCompleteEvent as b,OtpFieldInvalidEvent as y}from"./OtpFieldEvents.js";import"./context-consumer-BJVUulGf.js";import"./context-request-event-CCRlXoeR.js";import"./field-context.js";import"./create-context-CJ69ntlY.js";import"./SlotController-Z6eG7LSZ.js";import"./EventController-BBOmvfLa.js";import"./VisuallyHidden.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";const z=e`nord-otp-field,nord-otp-field *,nord-otp-field :after,nord-otp-field :before{box-sizing:border-box}nord-otp-field{--n-otp-field-gap:var(--n-space-s);--n-otp-field-background:var(--n-color-surface);--n-otp-field-border-color:var(--n-color-border-strong);--n-otp-field-border-radius:var(--n-border-radius-s);--_n-otp-field-cell-size:var(--n-otp-field-cell-size,var(--n-space-xl));--_n-otp-field-min-content-block-size:calc(var(--n-line-height-form) + var(--n-space-s)/1.6*2 + 2px);--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-m));display:block}nord-otp-field .n-otp-field{align-items:center;display:flex;gap:var(--n-otp-field-gap)}nord-otp-field .n-cell{appearance:none;background:var(--n-otp-field-background);block-size:var(--_n-otp-field-cell-size);border:1px solid var(--n-otp-field-border-color);border-radius:var(--n-otp-field-border-radius);color:var(--n-color-text);flex-shrink:0;font-family:var(--n-font-family);font-feature-settings:var(--n-font-features);font-size:var(--_n-otp-field-font-size);inline-size:var(--_n-otp-field-cell-size);line-height:var(--n-line-height-form);margin:0;padding:0;text-align:center;transition:border var(--n-transition-quickly),box-shadow var(--n-transition-quickly),background var(--n-transition-quickly)}nord-otp-field .n-cell::placeholder{color:var(--n-color-text-weakest);opacity:1}nord-otp-field .n-cell:focus::placeholder{color:#0000}nord-otp-field .n-cell:hover{border-color:var(--n-color-border-hover)}nord-otp-field .n-cell:focus{border-color:var(--n-color-accent);box-shadow:0 0 0 1px var(--n-color-accent);outline:none}nord-otp-field[invalid] .n-cell{border-color:var(--n-color-border-danger)}nord-otp-field[invalid] .n-cell:focus{border-color:var(--n-color-status-danger);box-shadow:0 0 0 1px var(--n-color-status-danger)}nord-otp-field[disabled] .n-cell{background:var(--n-color-active);border-color:var(--n-color-active);color:var(--n-color-text-weakest);cursor:not-allowed}nord-otp-field[readonly] .n-cell{cursor:default}nord-otp-field .n-separator{background:var(--n-color-border-strong);block-size:1px;flex-shrink:0;inline-size:var(--n-space-s)}nord-otp-field .n-hidden-input{block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;clip:rect(0,0,0,0);border:0;white-space:nowrap}nord-otp-field[size=s]{--_n-otp-field-cell-size:var(--n-otp-field-cell-size,calc(var(--n-space-l) + var(--n-space-xs)));--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-s))}nord-otp-field[size=l]{--_n-otp-field-cell-size:max(var(--n-otp-field-cell-size,calc(var(--n-space-xxl) - var(--n-space-l))),var(--_n-otp-field-min-content-block-size));--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-l))}`,x={numeric:{slotPattern:"\\d{1}",rootPattern:t=>`\\d{${t}}`,regexp:/\D/g,inputMode:"numeric"},alphanumeric:{slotPattern:"[a-zA-Z0-9]{1}",rootPattern:t=>`[a-zA-Z0-9]{${t}}`,regexp:/[^a-z0-9]/gi,inputMode:"text"}};function $(t,e){return t.replace(e.regexp,"")}function j(t,e,i){const o=function(t){return(null!=t?t:"").replace(/\s/g,"")}(t);let n=$(o,i),l=o.length>n.length;if(i.normalizeValue){const t=i.normalizeValue(n);l||(l=n.length>t.length),n=$(t,i),l||(l=t.length>n.length)}const s=e<0?0:e,r=Array.from(n);return[r.slice(0,s).join(""),l||r.length>s]}function k(t,e,i){return j(t,e,i)[0]}function I(t,e,i,o,n){const l=k(i,o,n);return k(`${t.slice(0,e)}${l}${t.slice(e+l.length)}`,o,n)}function w(t,e){return e<0||e>=t.length?t:`${t.slice(0,e)}${t.slice(e+1)}`}let A=1,M=class extends(p(g(v(f(n))))){constructor(){super(...arguments),this.otpId="nord-otp-field-"+A++,this.localize=new m(this),this.formData=new a(this,{value:()=>this.value||void 0}),this.stateAttributes=new d(this,(()=>({invalid:this.invalid})),{trackFocus:!0}),this.pendingFocus=null,this.pendingComplete=null,this.focused=!1,this.focusedIndex=0,this.length=6,this.type="numeric",this.readonly=!1,this.mask=!1,this.invalid=!1,this.autocomplete="one-time-code",this.groupSize=0,this._value="",this.lastReason="input-change"}get ownInvalid(){return this.invalid||super.ownInvalid}get complete(){return this.length>0&&this._value.length===this.length}get value(){return this._value}set value(t){const e=this._value,i=k(t,this.length,this.config);i!==e&&(this._value=i,this.requestUpdate("value",e))}get config(){var t;return{...null!==(t=x[this.type])&&void 0!==t?t:x.numeric,normalizeValue:this.normalizeValue}}get hasValidLength(){return Number.isInteger(this.length)&&this.length>0}get activeIndex(){const t=Math.max(this.length-1,0);return this.focused?Math.min(Math.max(this.focusedIndex,0),t):Math.min(this.value.length,t)}connectedCallback(){var t;super.connectedCallback(),c(this,z),this.inputId=this.cellId(0),null!==(t=this.ariaObserver)&&void 0!==t||(this.ariaObserver=new MutationObserver((()=>this.requestUpdate()))),this.ariaObserver.observe(this,{attributes:!0,attributeFilter:["aria-label","aria-labelledby","aria-describedby"]})}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this.ariaObserver)||void 0===t||t.disconnect(),this.ariaObserver=void 0}createRenderRoot(){return this}renormalize(){const t=k(this._value,this.length,this.config);t!==this._value&&(this._value=t,this.requestUpdate())}flushPending(){if(null!=this.pendingComplete){const t=this.pendingComplete;this.pendingComplete=null,t===this.value&&this.dispatchEvent(new b(t))}if(null!=this.pendingFocus){const t=this.pendingFocus;this.pendingFocus=null,t.value===this.value&&this.focusInput(t.index)}}get cells(){return Array.from(this.querySelectorAll("input.n-cell"))}focusInput(t){const e=this.cells,i=e[Math.min(Math.max(t,0),Math.max(e.length-1,0))];null==i||i.focus(),null==i||i.select()}queueFocusInput(t,e){this.pendingFocus={index:t,value:e}}focus(t){var e;null===(e=this.cells[this.activeIndex])||void 0===e||e.focus(t)}setValue(t){const e=k(t,this.length,this.config),i=this.value.length===this.length,o=e.length===this.length&&(!i||"input-paste"===this.lastReason);return e===this.value?(o&&(this.pendingComplete=e,this.requestUpdate()),null):(this.value=e,this.dispatchEvent(new u("input")),this.dispatchEvent(new u("change")),this.pendingComplete=o?e:null,e)}reportInvalid(t){this.dispatchEvent(new y(t))}handleMousedown(t,e){t.defaultPrevented||this.disabled||(t.preventDefault(),this.focusInput(e))}handleInput(t,e){var i,o;if(t.stopPropagation(),this.disabled||this.readonly)return;const n=t.target,l=n.value,[s,r]=j(l,this.length,this.config);if(r&&(this.lastReason="input-change",this.reportInvalid(l)),""===s){const t=null!==(i=this.value[e])&&void 0!==i?i:"";return void(""===l?(this.lastReason="input-clear",this.setValue(w(this.value,e))):(n.value=t,n.select()))}this.lastReason="input-change";const a=I(this.value,e,s,this.length,this.config),d=this.setValue(a);null!=d?this.queueFocusInput(Math.min(e+s.length,this.length-1),d):(n.value=null!==(o=this.value[e])&&void 0!==o?o:"",n.select())}handleKeydown(t,e){var i;if(this.disabled)return;const o=Math.max(this.length-1,0),n=Math.min(this.value.length,o),l=(t.ctrlKey||t.metaKey)&&!t.altKey,s="rtl"===this.resolveDirection(),r=s?"ArrowRight":"ArrowLeft",a=s?"ArrowLeft":"ArrowRight";if(t.key===r)return this.stopEvent(t),void this.focusInput(l?0:Math.max(0,e-1));if(t.key===a)return this.stopEvent(t),void this.focusInput(l?n:Math.min(o,e+1));if("Home"===t.key||"ArrowUp"===t.key)return this.stopEvent(t),void this.focusInput(0);if("End"===t.key||"ArrowDown"===t.key)return this.stopEvent(t),void this.focusInput(n);if(this.readonly)return;if("Backspace"===t.key&&l)return this.stopEvent(t),this.lastReason="keyboard",void(null!=this.setValue("")&&this.queueFocusInput(0,""));if("Delete"===t.key){this.stopEvent(t),this.lastReason="keyboard";const i=w(this.value,e),o=this.setValue(i);return void(null!=o&&this.queueFocusInput(e,o))}const d=null!==(i=this.value[e])&&void 0!==i?i:"",h=t.currentTarget,u=0===h.selectionStart&&h.selectionEnd===h.value.length;if(1===t.key.length&&u&&d===t.key)return this.stopEvent(t),void(e<this.length-1&&this.focusInput(e+1));if("Backspace"===t.key){this.stopEvent(t),this.lastReason="keyboard";const i=Math.max(0,e-1),o=""===d?i:e,n=this.setValue(w(this.value,o));null!=n&&this.queueFocusInput(i,n)}}handlePaste(t,e){var i,o;if(this.disabled||this.readonly)return;let n="";try{n=null!==(o=null===(i=t.clipboardData)||void 0===i?void 0:i.getData("text/plain"))&&void 0!==o?o:""}catch(t){return}t.preventDefault();const[l,s]=j(n,this.length,this.config);if(this.lastReason="input-paste",s&&this.reportInvalid(n),""===l)return;const r=I(this.value,e,l,this.length,this.config),a=this.setValue(r);null!=a&&this.queueFocusInput(Math.min(e+l.length,this.length-1),a)}handleFocus(t,e){if(this.disabled)return;if(e>this.value.length)return void this.focusInput(Math.min(this.value.length,this.length-1));this.focusedIndex=e,this.focused=!0,this.requestUpdate();t.currentTarget.select()}handleBlur(t){t.relatedTarget instanceof Node&&this.contains(t.relatedTarget)||(this.focused=!1,this.requestUpdate())}handleHiddenFocus(){this.focusInput(0)}handleHiddenInput(t){if(t.stopPropagation(),this.disabled||this.readonly)return;const e=t.target,[i,o]=j(e.value,this.length,this.config);this.lastReason="input-change",o&&this.reportInvalid(e.value);const n=this.setValue(i);null!=n&&""!==n&&this.queueFocusInput(n.length-1,n)}resolveDirection(){var t,e;return"rtl"===(null!==(e=null===(t=this.closest("[dir]"))||void 0===t?void 0:t.getAttribute("dir"))&&void 0!==e?e:"undefined"!=typeof document?document.documentElement.getAttribute("dir"):null)?"rtl":"ltr"}stopEvent(t){t.preventDefault(),t.stopPropagation()}cellId(t){var e;return`${null!==(e=this.getAttribute("id"))&&void 0!==e?e:this.otpId}-${t+1}`}render(){if(!this.hasValidLength)return i;const t=this.config,e=this.value,n=this.activeIndex,l=`${this.otpId}-group`,s=this.controlAriaLabel,a=this.controlAriaLabelledby,d=this.controlAriaDescribedby,h=[];for(let i=0;i<this.length;i++)h.push(this.renderCell(i,e,t,n,s,a)),this.groupSize>0&&(i+1)%this.groupSize==0&&i<this.length-1&&h.push(o`<span class="n-separator" aria-hidden="true"></span>`);return o`${this.renderLabel()}<div class="n-otp-field" id="${l}" role="group" aria-label="${r(s)}" aria-labelledby="${r(a)}" aria-describedby="${r(d)}">${h}</div><input class="n-hidden-input" type="text" aria-hidden="true" tabindex="-1" .value="${e}" autocomplete="${this.autocomplete}" inputmode="${t.inputMode}" minlength="${this.length}" maxlength="${this.length}" pattern="${t.rootPattern(this.length)}" ?disabled="${this.effectiveDisabled}" ?readonly="${this.readonly}" ?required="${this.required}" aria-invalid="${r(!this.effectiveDisabled&&this.effectiveInvalid?"true":void 0)}" @focus="${this.handleHiddenFocus}" @input="${this.handleHiddenInput}"> ${this.renderError()} ${this.isHintBelow?this.renderHint():i}`}renderCell(t,e,i,n,l,s){var a;const d=null!==(a=e[t])&&void 0!==a?a:"",h=""!==d,u=0===t?void 0:this.localize.term("characterLabel",t+1,this.length),c=0===t?s:void 0,p=0===t?l:void 0;return o`<input class="n-cell" id="${this.cellId(t)}" .value="${d}" type="${this.mask?"password":"text"}" inputmode="${i.inputMode}" autocomplete="${0===t?this.autocomplete:"off"}" autocorrect="off" spellcheck="false" enterkeyhint="${t===this.length-1?"done":"next"}" maxlength="${r(0===t?this.length:void 0)}" pattern="${i.slotPattern}" placeholder="${r(this.placeholder)}" tabindex="${n===t?0:-1}" ?disabled="${this.effectiveDisabled}" ?readonly="${this.readonly}" aria-label="${r(null!=u?u:p)}" aria-labelledby="${r(null==u?c:void 0)}" aria-invalid="${r(!this.effectiveDisabled&&this.effectiveInvalid?"true":void 0)}" data-filled="${r(h?"":void 0)}" @mousedown="${e=>this.handleMousedown(e,t)}" @input="${e=>this.handleInput(e,t)}" @keydown="${e=>this.handleKeydown(e,t)}" @paste="${e=>this.handlePaste(e,t)}" @focus="${e=>this.handleFocus(e,t)}" @blur="${t=>this.handleBlur(t)}">`}updated(t){super.updated(t),this.toggleAttribute("complete",this.complete),this.toggleAttribute("data-complete",this.complete),this.toggleAttribute("data-filled",this.value.length>0),this.toggleAttribute("data-disabled",this.disabled),this.toggleAttribute("data-readonly",this.readonly),this.toggleAttribute("data-required",this.required),this.flushPending()}};t([l({reflect:!0,type:Number})],M.prototype,"length",void 0),t([l({reflect:!0})],M.prototype,"type",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"readonly",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"mask",void 0),t([l({reflect:!0})],M.prototype,"placeholder",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"invalid",void 0),t([l()],M.prototype,"autocomplete",void 0),t([l({reflect:!0,type:Number,attribute:"group-size"})],M.prototype,"groupSize",void 0),t([l()],M.prototype,"value",null),t([l({attribute:!1})],M.prototype,"normalizeValue",void 0),t([h("length"),h("type")],M.prototype,"renormalize",null),M=t([s("nord-otp-field")],M);var F=M;export{b as OtpFieldCompleteEvent,y as OtpFieldInvalidEvent,F as default};
1
+ import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{css as e,nothing as i,html as o,LitElement as n}from"lit";import{property as l,customElement as s}from"lit/decorators.js";import{ifDefined as r}from"lit/directives/if-defined.js";import{F as a}from"./FormDataController-OUt5L5uC.js";import{S as d}from"./StateAttributesController-BIh96sXZ.js";import{o as h}from"./observe-D0n0zOfU.js";import{N as u}from"./events-Bv6wNHwJ.js";import{i as c}from"./light-dom-styles-DXsbiKU9.js";import{D as p}from"./DraftComponentMixin-4qug5Rky.js";import{F as v}from"./FieldControlMixin-BXNZJXu9.js";import{I as f}from"./InputMixin-LetXsCyv.js";import{S as g}from"./SizeMixin-CU9cLbLC.js";import{LocalizeController as m}from"./LocalizeController.js";import{OtpFieldCompleteEvent as b,OtpFieldInvalidEvent as y}from"./OtpFieldEvents.js";import"./context-consumer-BJVUulGf.js";import"./context-request-event-CCRlXoeR.js";import"./field-context.js";import"./create-context-CJ69ntlY.js";import"./SlotController-Z6eG7LSZ.js";import"./EventController-BBOmvfLa.js";import"./VisuallyHidden.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";const z=e`nord-otp-field,nord-otp-field *,nord-otp-field :after,nord-otp-field :before{box-sizing:border-box}nord-otp-field{--n-otp-field-gap:var(--n-space-s);--n-otp-field-background:var(--n-color-surface);--n-otp-field-border-color:var(--n-color-border-strong);--n-otp-field-border-radius:var(--n-border-radius-s);--_n-otp-field-cell-size:var(--n-otp-field-cell-size,var(--n-space-xl));--_n-otp-field-min-content-block-size:calc(var(--n-line-height-form) + var(--n-space-s)/1.6*2 + 2px);--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-m));display:block}nord-otp-field .n-otp-field{align-items:center;display:flex;gap:var(--n-otp-field-gap)}nord-otp-field .n-cell{appearance:none;background:var(--n-otp-field-background);block-size:var(--_n-otp-field-cell-size);border:1px solid var(--n-otp-field-border-color);border-radius:var(--n-otp-field-border-radius);color:var(--n-color-text);flex-shrink:0;font-family:var(--n-font-family);font-feature-settings:var(--n-font-features);font-size:var(--_n-otp-field-font-size);inline-size:var(--_n-otp-field-cell-size);line-height:var(--n-line-height-form);margin:0;padding:0;text-align:center;transition:border var(--n-transition-quickly),box-shadow var(--n-transition-quickly),background var(--n-transition-quickly)}nord-otp-field .n-cell::placeholder{color:var(--n-color-text-weakest);opacity:1}nord-otp-field .n-cell:focus::placeholder{color:#0000}nord-otp-field .n-cell:hover{border-color:var(--n-color-border-hover)}nord-otp-field .n-cell:focus{border-color:var(--n-color-accent);box-shadow:0 0 0 1px var(--n-color-accent);outline:none}nord-otp-field[invalid] .n-cell{border-color:var(--n-color-border-danger)}nord-otp-field[invalid] .n-cell:focus{border-color:var(--n-color-status-danger);box-shadow:0 0 0 1px var(--n-color-status-danger)}nord-otp-field[disabled] .n-cell{background:var(--n-color-active);border-color:var(--n-color-active);color:var(--n-color-text-weakest);cursor:not-allowed}nord-otp-field[readonly] .n-cell{cursor:default}nord-otp-field .n-separator{background:var(--n-color-border-strong);block-size:1px;flex-shrink:0;inline-size:var(--n-space-s)}nord-otp-field .n-hidden-input{block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;clip:rect(0,0,0,0);border:0;white-space:nowrap}nord-otp-field[size=s]{--_n-otp-field-cell-size:var(--n-otp-field-cell-size,calc(var(--n-space-l) + var(--n-space-xs)));--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-s))}nord-otp-field[size=l]{--_n-otp-field-cell-size:max(var(--n-otp-field-cell-size,calc(var(--n-space-xxl) - var(--n-space-l))),var(--_n-otp-field-min-content-block-size));--_n-otp-field-font-size:var(--n-otp-field-font-size,var(--n-font-size-l))}`,x={numeric:{slotPattern:"\\d{1}",rootPattern:t=>`\\d{${t}}`,regexp:/\D/g,inputMode:"numeric"},alphanumeric:{slotPattern:"[a-zA-Z0-9]{1}",rootPattern:t=>`[a-zA-Z0-9]{${t}}`,regexp:/[^a-z0-9]/gi,inputMode:"text"}};function $(t,e){return t.replace(e.regexp,"")}function j(t,e,i){const o=function(t){return(null!=t?t:"").replace(/\s/g,"")}(t);let n=$(o,i),l=o.length>n.length;if(i.normalizeValue){const t=i.normalizeValue(n);l||(l=n.length>t.length),n=$(t,i),l||(l=t.length>n.length)}const s=e<0?0:e,r=Array.from(n);return[r.slice(0,s).join(""),l||r.length>s]}function k(t,e,i){return j(t,e,i)[0]}function I(t,e,i,o,n){const l=k(i,o,n);return k(`${t.slice(0,e)}${l}${t.slice(e+l.length)}`,o,n)}function w(t,e){return e<0||e>=t.length?t:`${t.slice(0,e)}${t.slice(e+1)}`}let A=1,M=class extends(p(g(v(f(n))))){constructor(){super(...arguments),this.otpId="nord-otp-field-"+A++,this.localize=new m(this),this.formData=new a(this,{value:()=>this.value||void 0}),this.stateAttributes=new d(this,(()=>({invalid:this.invalid})),{trackFocus:!0}),this.pendingFocus=null,this.pendingComplete=null,this.focused=!1,this.focusedIndex=0,this.length=6,this.type="numeric",this.readonly=!1,this.mask=!1,this.invalid=!1,this.autocomplete="one-time-code",this.groupSize=0,this._value="",this.lastReason="input-change"}get ownInvalid(){return this.invalid||super.ownInvalid}get complete(){return this.length>0&&this._value.length===this.length}get value(){return this._value}set value(t){const e=this._value,i=k(t,this.length,this.config);i!==e&&(this._value=i,this.requestUpdate("value",e))}get config(){var t;return{...null!==(t=x[this.type])&&void 0!==t?t:x.numeric,normalizeValue:this.normalizeValue}}get hasValidLength(){return Number.isInteger(this.length)&&this.length>0}get activeIndex(){const t=Math.max(this.length-1,0);return this.focused?Math.min(Math.max(this.focusedIndex,0),t):Math.min(this.value.length,t)}connectedCallback(){var t;super.connectedCallback(),c(this,z),this.inputId=this.cellId(0),null!==(t=this.ariaObserver)&&void 0!==t||(this.ariaObserver=new MutationObserver((()=>this.requestUpdate()))),this.ariaObserver.observe(this,{attributes:!0,attributeFilter:["aria-label","aria-labelledby","aria-describedby"]})}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this.ariaObserver)||void 0===t||t.disconnect(),this.ariaObserver=void 0}createRenderRoot(){return this}renormalize(){const t=k(this._value,this.length,this.config);t!==this._value&&(this._value=t,this.requestUpdate())}flushPending(){if(null!=this.pendingComplete){const t=this.pendingComplete;this.pendingComplete=null,t===this.value&&this.dispatchEvent(new b(t))}if(null!=this.pendingFocus){const t=this.pendingFocus;this.pendingFocus=null,t.value===this.value&&this.focusInput(t.index)}}get cells(){return Array.from(this.querySelectorAll("input.n-cell"))}focusInput(t){const e=this.cells,i=e[Math.min(Math.max(t,0),Math.max(e.length-1,0))];null==i||i.focus(),null==i||i.select()}queueFocusInput(t,e){this.pendingFocus={index:t,value:e}}focus(t){var e;null===(e=this.cells[this.activeIndex])||void 0===e||e.focus(t)}setValue(t){const e=k(t,this.length,this.config),i=this.value.length===this.length,o=e.length===this.length&&(!i||"input-paste"===this.lastReason);return e===this.value?(o&&(this.pendingComplete=e,this.requestUpdate()),null):(this.value=e,this.dispatchEvent(new u("input")),this.dispatchEvent(new u("change")),this.pendingComplete=o?e:null,e)}reportInvalid(t){this.dispatchEvent(new y(t))}handleMousedown(t,e){t.defaultPrevented||this.disabled||(t.preventDefault(),this.focusInput(e))}handleInput(t,e){var i,o;if(t.stopPropagation(),this.disabled||this.readonly)return;const n=t.target,l=n.value,[s,r]=j(l,this.length,this.config);if(r&&(this.lastReason="input-change",this.reportInvalid(l)),""===s){const t=null!==(i=this.value[e])&&void 0!==i?i:"";return void(""===l?(this.lastReason="input-clear",this.setValue(w(this.value,e))):(n.value=t,n.select()))}this.lastReason="input-change";const a=I(this.value,e,s,this.length,this.config),d=this.setValue(a);null!=d?this.queueFocusInput(Math.min(e+s.length,this.length-1),d):(n.value=null!==(o=this.value[e])&&void 0!==o?o:"",n.select())}handleKeydown(t,e){var i;if(this.disabled)return;const o=Math.max(this.length-1,0),n=Math.min(this.value.length,o),l=(t.ctrlKey||t.metaKey)&&!t.altKey,s="rtl"===this.resolveDirection(),r=s?"ArrowRight":"ArrowLeft",a=s?"ArrowLeft":"ArrowRight";if(t.key===r)return this.stopEvent(t),void this.focusInput(l?0:Math.max(0,e-1));if(t.key===a)return this.stopEvent(t),void this.focusInput(l?n:Math.min(o,e+1));if("Home"===t.key||"ArrowUp"===t.key)return this.stopEvent(t),void this.focusInput(0);if("End"===t.key||"ArrowDown"===t.key)return this.stopEvent(t),void this.focusInput(n);if(this.readonly)return;if("Backspace"===t.key&&l)return this.stopEvent(t),this.lastReason="keyboard",void(null!=this.setValue("")&&this.queueFocusInput(0,""));if("Delete"===t.key){this.stopEvent(t),this.lastReason="keyboard";const i=w(this.value,e),o=this.setValue(i);return void(null!=o&&this.queueFocusInput(e,o))}const d=null!==(i=this.value[e])&&void 0!==i?i:"",h=t.currentTarget,u=0===h.selectionStart&&h.selectionEnd===h.value.length;if(1===t.key.length&&u&&d===t.key)return this.stopEvent(t),void(e<this.length-1&&this.focusInput(e+1));if("Backspace"===t.key){this.stopEvent(t),this.lastReason="keyboard";const i=Math.max(0,e-1),o=""===d?i:e,n=this.setValue(w(this.value,o));null!=n&&this.queueFocusInput(i,n)}}handlePaste(t,e){var i,o;if(this.disabled||this.readonly)return;let n="";try{n=null!==(o=null===(i=t.clipboardData)||void 0===i?void 0:i.getData("text/plain"))&&void 0!==o?o:""}catch(t){return}t.preventDefault();const[l,s]=j(n,this.length,this.config);if(this.lastReason="input-paste",s&&this.reportInvalid(n),""===l)return;const r=I(this.value,e,l,this.length,this.config),a=this.setValue(r);null!=a&&this.queueFocusInput(Math.min(e+l.length,this.length-1),a)}handleFocus(t,e){if(this.disabled)return;if(e>this.value.length)return void this.focusInput(Math.min(this.value.length,this.length-1));this.focusedIndex=e,this.focused=!0,this.requestUpdate();t.currentTarget.select()}handleBlur(t){t.relatedTarget instanceof Node&&this.contains(t.relatedTarget)||(this.focused=!1,this.requestUpdate())}handleHiddenFocus(){this.focusInput(0)}handleHiddenInput(t){if(t.stopPropagation(),this.disabled||this.readonly)return;const e=t.target,[i,o]=j(e.value,this.length,this.config);this.lastReason="input-change",o&&this.reportInvalid(e.value);const n=this.setValue(i);null!=n&&""!==n&&this.queueFocusInput(n.length-1,n)}resolveDirection(){var t,e;return"rtl"===(null!==(e=null===(t=this.closest("[dir]"))||void 0===t?void 0:t.getAttribute("dir"))&&void 0!==e?e:"undefined"!=typeof document?document.documentElement.getAttribute("dir"):null)?"rtl":"ltr"}stopEvent(t){t.preventDefault(),t.stopPropagation()}cellId(t){var e;return`${null!==(e=this.getAttribute("id"))&&void 0!==e?e:this.otpId}-${t+1}`}render(){if(!this.hasValidLength)return i;const t=this.config,e=this.value,n=this.activeIndex,l=`${this.otpId}-group`,s=this.controlAriaLabel,a=this.controlAriaLabelledby,d=this.controlAriaDescribedby,h=[];for(let i=0;i<this.length;i++)h.push(this.renderCell(i,e,t,n,s,a)),this.groupSize>0&&(i+1)%this.groupSize==0&&i<this.length-1&&h.push(o`<span class="n-separator" aria-hidden="true"></span>`);return o`${this.renderLabel()}<div class="n-otp-field" id="${l}" role="group" aria-label="${r(s)}" aria-labelledby="${r(a)}" aria-describedby="${r(d)}">${h}</div><input class="n-hidden-input" type="text" aria-hidden="true" tabindex="-1" .value="${e}" autocomplete="${this.autocomplete}" inputmode="${t.inputMode}" minlength="${this.length}" maxlength="${this.length}" pattern="${t.rootPattern(this.length)}" ?disabled="${this.effectiveDisabled}" ?readonly="${this.readonly}" ?required="${this.required}" aria-invalid="${r(!this.effectiveDisabled&&this.effectiveInvalid?"true":void 0)}" @focus="${this.handleHiddenFocus}" @input="${this.handleHiddenInput}"> ${this.renderError()} ${this.isHintBelow?this.renderHint():i}`}renderCell(t,e,i,n,l,s){var a;const d=null!==(a=e[t])&&void 0!==a?a:"",h=""!==d,u=0===t?void 0:this.localize.term("characterLabel",t+1,this.length),c=0===t?s:void 0,p=0===t?l:void 0;return o`<input class="n-cell" id="${this.cellId(t)}" .value="${d}" type="${this.mask?"password":"text"}" inputmode="${i.inputMode}" autocomplete="${0===t?this.autocomplete:"off"}" autocorrect="off" spellcheck="false" enterkeyhint="${t===this.length-1?"done":"next"}" maxlength="${r(0===t?this.length:void 0)}" pattern="${i.slotPattern}" placeholder="${r(this.placeholder)}" tabindex="${n===t?0:-1}" ?disabled="${this.effectiveDisabled}" ?readonly="${this.readonly}" aria-label="${r(null!=u?u:p)}" aria-labelledby="${r(null==u?c:void 0)}" aria-invalid="${r(!this.effectiveDisabled&&this.effectiveInvalid?"true":void 0)}" data-filled="${r(h?"":void 0)}" @mousedown="${e=>this.handleMousedown(e,t)}" @input="${e=>this.handleInput(e,t)}" @keydown="${e=>this.handleKeydown(e,t)}" @paste="${e=>this.handlePaste(e,t)}" @focus="${e=>this.handleFocus(e,t)}" @blur="${t=>this.handleBlur(t)}">`}updated(t){super.updated(t),this.toggleAttribute("complete",this.complete),this.toggleAttribute("data-complete",this.complete),this.toggleAttribute("data-filled",this.value.length>0),this.toggleAttribute("data-disabled",this.disabled),this.toggleAttribute("data-readonly",this.readonly),this.toggleAttribute("data-required",this.required),this.flushPending()}};t([l({reflect:!0,type:Number})],M.prototype,"length",void 0),t([l({reflect:!0})],M.prototype,"type",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"readonly",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"mask",void 0),t([l({reflect:!0})],M.prototype,"placeholder",void 0),t([l({reflect:!0,type:Boolean})],M.prototype,"invalid",void 0),t([l()],M.prototype,"autocomplete",void 0),t([l({reflect:!0,type:Number,attribute:"group-size"})],M.prototype,"groupSize",void 0),t([l()],M.prototype,"value",null),t([l({attribute:!1})],M.prototype,"normalizeValue",void 0),t([h("length"),h("type")],M.prototype,"renormalize",null),M=t([s("nord-otp-field")],M);var F=M;export{b as OtpFieldCompleteEvent,y as OtpFieldInvalidEvent,F as default};
2
2
  //# sourceMappingURL=OtpField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OtpField.js","sources":["../src/otp-field/OtpField.ts"],"sourcesContent":["import type { PropertyValues } from 'lit'\nimport { html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { FormDataController } from '../common/controllers/FormDataController.js'\nimport { StateAttributesController } from '../common/controllers/StateAttributesController.js'\nimport { observe } from '../common/decorators/observe.js'\nimport { NordEvent } from '../common/events.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport { FieldControlMixin } from '../common/mixins/FieldControlMixin.js'\nimport { InputMixin } from '../common/mixins/InputMixin.js'\nimport { SizeMixin } from '../common/mixins/SizeMixin.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './OtpField.css'\nimport { OtpFieldCompleteEvent, OtpFieldInvalidEvent } from './OtpFieldEvents.js'\n\nexport { OtpFieldCompleteEvent, OtpFieldInvalidEvent } from './OtpFieldEvents.js'\n\n/** The character sets the field accepts, mirroring Base UI's `validationType`. */\nexport type OtpFieldType = 'numeric' | 'alphanumeric'\n\ninterface OtpValidationConfig {\n /** Pattern for a single cell input, e.g. `'\\\\d{1}'`. */\n slotPattern: string\n /** Builds the full-value pattern for the hidden input, e.g. `'\\\\d{6}'`. */\n rootPattern: (length: number) => string\n /** Strips characters not allowed by this type. */\n regexp: RegExp\n /** Virtual-keyboard hint for cells and the hidden input. */\n inputMode: 'numeric' | 'text'\n /** Optional consumer normalization (mirrors Base UI's `normalizeValue`). */\n normalizeValue?: (value: string) => string\n}\n\n// Kept as a table (rather than inline branches) so adding Base UI's `alpha` /\n// `none` types later is a one-line change.\nconst OTP_VALIDATION_CONFIG: Record<OtpFieldType, OtpValidationConfig> = {\n numeric: {\n slotPattern: '\\\\d{1}',\n rootPattern: length => `\\\\d{${length}}`,\n regexp: /\\D/g,\n inputMode: 'numeric',\n },\n alphanumeric: {\n slotPattern: '[a-zA-Z0-9]{1}',\n rootPattern: length => `[a-zA-Z0-9]{${length}}`,\n regexp: /[^a-z0-9]/gi,\n inputMode: 'text',\n },\n}\n\n/** Strips all whitespace from a raw OTP string. */\nfunction stripWhitespace(value: string | null | undefined): string {\n return (value ?? '').replace(/\\s/g, '')\n}\n\n/** Removes characters not permitted by the type's regexp. */\nfunction applyValidation(value: string, config: OtpValidationConfig): string {\n return value.replace(config.regexp, '')\n}\n\n/**\n * Normalizes user-entered OTP text: strips whitespace, filters by `type`, then\n * clamps to `length` by Unicode code point so multi-byte characters never split\n * across a cell. Returns the normalized value plus whether any character was\n * rejected (so the caller can fire `value-invalid`).\n */\nfunction normalizeWithDetails(\n value: string | null | undefined,\n length: number,\n config: OtpValidationConfig,\n): readonly [value: string, didRejectCharacters: boolean] {\n const stripped = stripWhitespace(value)\n let normalized = applyValidation(stripped, config)\n let didReject = stripped.length > normalized.length\n\n // Optional consumer normalization (e.g. uppercasing), mirroring Base UI's\n // `normalizeValue`: runs after type filtering, then the result is filtered\n // again so a normalizer can't introduce characters the type disallows.\n if (config.normalizeValue) {\n const custom = config.normalizeValue(normalized)\n didReject ||= normalized.length > custom.length\n normalized = applyValidation(custom, config)\n didReject ||= custom.length > normalized.length\n }\n\n // Slice by code points so multi-byte characters do not split across slots.\n const maxLength = length < 0 ? 0 : length\n const characters = Array.from(normalized)\n\n return [\n characters.slice(0, maxLength).join(''),\n didReject || characters.length > maxLength,\n ]\n}\n\n/** Convenience wrapper returning only the normalized value. */\nfunction normalize(value: string | null | undefined, length: number, config: OtpValidationConfig): string {\n return normalizeWithDetails(value, length, config)[0]\n}\n\n/**\n * Replaces characters starting at `index`, then re-normalizes so paste and\n * multi-character edits stay contiguous and length-bounded.\n */\nfunction replaceValue(\n current: string,\n index: number,\n next: string,\n length: number,\n config: OtpValidationConfig,\n): string {\n const normalized = normalize(next, length, config)\n const prefix = current.slice(0, index)\n const suffix = current.slice(index + normalized.length)\n\n return normalize(`${prefix}${normalized}${suffix}`, length, config)\n}\n\n/** Splices a single character out of the value at `index`. */\nfunction removeCharacter(current: string, index: number): string {\n if (index < 0 || index >= current.length) {\n return current\n }\n\n return `${current.slice(0, index)}${current.slice(index + 1)}`\n}\n\n/** Per-instance counter so light-DOM ids stay unique when the host has no `id`. */\nlet otpFieldCount = 1\n\n/**\n * OTP Field is a segmented one-time-code input: it renders `length` individual\n * character cells plus a visually-hidden input that holds the full value, enabling\n * SMS / keychain autofill and native `pattern`/`required` validation. Typing fills\n * and auto-advances, Backspace clears and moves back, the arrow keys navigate, and\n * pasting a code distributes its characters across the cells.\n *\n * OTP Field is a control only — it has no built-in label, hint or error. Compose\n * it inside a [Field](/components/field/) with a [Field Label](/components/field-label/)\n * (connected with `for`) to give it an accessible name, helper text and an error\n * message, exactly like a native input.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {NordEvent} input - Dispatched whenever the OTP value changes through user interaction (typing, Backspace/Delete, paste, autofill).\n * @fires {NordEvent} change - Dispatched alongside `input` when the committed value changes via user interaction.\n * @fires {OtpFieldCompleteEvent} complete - Dispatched after the value updates when every cell becomes filled.\n * @fires {OtpFieldInvalidEvent} value-invalid - Dispatched when typed or pasted text contained characters rejected by `type`.\n *\n * @localization characterLabel - Per-cell accessible label, given the 1-based cell position and total cell count.\n *\n * @attr {boolean} data-invalid - Present while the field is invalid (mirrors the \\`invalid\\` property). Style hook for the whole control.\n * @attr {boolean} data-focused - Present while any cell has focus. Style hook for focus-within treatments.\n *\n * @cssprop [--n-otp-field-gap=var(--n-space-s)] - Gap between cells (and between groups when `group-size` is used).\n * @cssprop [--n-otp-field-cell-size=var(--n-space-xl)] - Controls the block-size and inline-size of each square cell. When unset, size maps to the shared control block sizes.\n * @cssprop [--n-otp-field-background=var(--n-color-surface)] - Cell background.\n * @cssprop [--n-otp-field-border-color=var(--n-color-border-strong)] - Cell border color (resting).\n * @cssprop [--n-otp-field-border-radius=var(--n-border-radius-s)] - Cell corner radius.\n * @cssprop [--n-otp-field-font-size=var(--n-font-size-m)] - Cell character font size.\n */\n@customElement('nord-otp-field')\nexport default class OtpField extends DraftComponentMixin(SizeMixin(FieldControlMixin(InputMixin(LitElement)))) {\n /** Stable, unique id base for light-DOM ARIA wiring of this instance. */\n private otpId = `nord-otp-field-${otpFieldCount++}`\n\n private localize = new LocalizeController<'nord-otp-field'>(this)\n\n private formData = new FormDataController(this, { value: () => this.value || undefined })\n\n /** Reflects `invalid` to `data-invalid` and focus-within to `data-focused`. */\n private stateAttributes = new StateAttributesController(\n this,\n () => ({ invalid: this.invalid }),\n { trackFocus: true },\n )\n\n /** Re-renders when the host's forwarded ARIA labelling attributes change. */\n private ariaObserver?: MutationObserver\n\n /** Index + value to focus once the async value update has applied. */\n private pendingFocus: { index: number, value: string } | null = null\n\n /** Value to fire `complete` for once the async value update has applied. */\n private pendingComplete: string | null = null\n\n /** Whether any cell currently holds focus (drives roving tabindex + data-focused). */\n private focused = false\n\n /** The cell index that currently has (or last had) focus. */\n private focusedIndex = 0\n\n /**\n * The number of OTP cells. Must be a positive integer.\n */\n @property({ reflect: true, type: Number }) length = 6\n\n /**\n * Controls the allowed characters, `inputmode` and `pattern`. `numeric` accepts\n * digits; `alphanumeric` accepts letters and digits.\n */\n @property({ reflect: true }) type: OtpFieldType = 'numeric'\n\n /**\n * Prevents the user from changing the value while keeping navigation and focus.\n */\n @property({ reflect: true, type: Boolean }) readonly = false\n\n /**\n * Obscures each cell (renders `type=\"password\"`) for use on shared screens.\n */\n @property({ reflect: true, type: Boolean }) mask = false\n\n /**\n * Placeholder character or string shown in every empty cell.\n */\n @property({ reflect: true }) placeholder?: string\n\n /**\n * Marks the field invalid, applying error styling and `aria-invalid` to every\n * cell and the hidden input. Pair with a `nord-field-error` in the Field.\n */\n @property({ reflect: true, type: Boolean }) invalid = false\n\n // The control's own invalid state for the field context: its `invalid` prop or\n // a built-in `error` (when used standalone).\n protected override get ownInvalid() {\n return this.invalid || super.ownInvalid\n }\n\n /**\n * The autocomplete token applied to the first cell and the hidden input (all\n * other cells get `autocomplete=\"off\"`). Defaults to `one-time-code` to enable\n * SMS / keychain OTP autofill.\n */\n @property() autocomplete = 'one-time-code'\n\n /**\n * Renders a decorative separator after every N cells (for example, `3` shows\n * `123-456`). `0` disables grouping. The separator is `aria-hidden` and does\n * not affect the value or navigation.\n */\n @property({ reflect: true, type: Number, attribute: 'group-size' }) groupSize = 0\n\n /**\n * Whether every cell is filled (`value.length === length`). Read-only and\n * derived from `value`; reflected as the `complete` attribute so consumers can\n * style the completed state.\n */\n get complete(): boolean {\n return this.length > 0 && this._value.length === this.length\n }\n\n /** Backing store for the normalized value. */\n private _value = ''\n\n /**\n * The OTP value, for example `'123456'`. Whitespace is stripped, characters are\n * filtered by `type`, and the result is clamped to `length`. Set programmatically\n * to prefill.\n */\n @property()\n // @ts-expect-error - intentionally re-declares the inherited `value` property as a normalizing accessor\n get value(): string {\n return this._value\n }\n\n set value(next: string) {\n const old = this._value\n const normalized = normalize(next, this.length, this.config)\n\n if (normalized === old) {\n return\n }\n\n this._value = normalized\n this.requestUpdate('value', old)\n }\n\n /**\n * Function that normalizes the value after whitespace and `type` filtering —\n * e.g. `el.normalizeValue = v => v.toUpperCase()`. It runs whenever the field\n * normalizes a value (initial, programmatic, and user edits), inside the\n * component's own pipeline, so live normalization never fights the per-cell\n * focus handling. The result is filtered by `type` again, then clamped to\n * `length`; it should be idempotent since the same value may be normalized\n * more than once. Characters rejected while normalizing are reported through\n * `value-invalid`. Mirrors Base UI's `normalizeValue`.\n */\n @property({ attribute: false }) normalizeValue?: (value: string) => string\n\n /** The validation config for the current `type`. */\n private get config(): OtpValidationConfig {\n return {\n ...(OTP_VALIDATION_CONFIG[this.type] ?? OTP_VALIDATION_CONFIG.numeric),\n normalizeValue: this.normalizeValue,\n }\n }\n\n /** Whether `length` is a usable positive integer. */\n private get hasValidLength(): boolean {\n return Number.isInteger(this.length) && this.length > 0\n }\n\n /** The index of the cell that is currently tabbable (roving tabindex). */\n private get activeIndex(): number {\n const last = Math.max(this.length - 1, 0)\n\n return this.focused\n ? Math.min(Math.max(this.focusedIndex, 0), last)\n : Math.min(this.value.length, last)\n }\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n\n // The built-in `<label for>` (from FieldControlMixin) focuses the first cell.\n this.inputId = this.cellId(0)\n\n // An external label (e.g. nord-field-label) names the control by setting\n // `aria-labelledby`/`aria-label` on the host; forward it to the first cell.\n this.ariaObserver ??= new MutationObserver(() => this.requestUpdate())\n this.ariaObserver.observe(this, {\n attributes: true,\n attributeFilter: ['aria-label', 'aria-labelledby', 'aria-describedby'],\n })\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.ariaObserver?.disconnect()\n this.ariaObserver = undefined\n }\n\n // Render in the light DOM so the control participates in the document tree\n // (form labelling, Tailwind), like the other new Nord components.\n protected createRenderRoot() {\n return this\n }\n\n /** Re-normalize the value when `length` or `type` changes (e.g. clamps it). */\n @observe('length')\n @observe('type')\n protected renormalize() {\n const normalized = normalize(this._value, this.length, this.config)\n\n if (normalized !== this._value) {\n this._value = normalized\n this.requestUpdate()\n }\n }\n\n /**\n * Flush queued focus/complete once the value update has actually applied.\n * Runs from `updated()` (after every render) rather than a value observer so\n * it also fires for a re-paste that completes an already-complete value (the\n * value text is unchanged, so a value observer would not run).\n */\n private flushPending() {\n if (this.pendingComplete != null) {\n const value = this.pendingComplete\n this.pendingComplete = null\n\n if (value === this.value) {\n this.dispatchEvent(new OtpFieldCompleteEvent(value))\n }\n }\n\n if (this.pendingFocus != null) {\n const pending = this.pendingFocus\n this.pendingFocus = null\n\n if (pending.value === this.value) {\n this.focusInput(pending.index)\n }\n }\n }\n\n /** Live list of the rendered cell inputs, in DOM order. */\n private get cells(): HTMLInputElement[] {\n return Array.from(this.querySelectorAll<HTMLInputElement>('input.n-cell'))\n }\n\n /** Focus a cell by index (clamped), then select its content. */\n private focusInput(index: number) {\n const cells = this.cells\n const target = cells[Math.min(Math.max(index, 0), Math.max(cells.length - 1, 0))]\n target?.focus()\n target?.select()\n }\n\n /** Queue a focus to run once the value update applies (Lit renders async). */\n private queueFocusInput(index: number, value: string) {\n this.pendingFocus = { index, value }\n }\n\n /** Focus the field by moving focus into its active cell. */\n focus(options?: FocusOptions) {\n this.cells[this.activeIndex]?.focus(options)\n }\n\n /**\n * Commit a new value, firing `input` + `change` (and queuing `complete` when\n * the field becomes filled). Returns the committed value, or `null` if nothing\n * changed.\n */\n private setValue(next: string): string | null {\n const normalized = normalize(next, this.length, this.config)\n const wasComplete = this.value.length === this.length\n\n // A completing change, OR a complete value (re-)committed via paste, signals\n // completion — even when the value text is unchanged.\n const completes = normalized.length === this.length && (!wasComplete || this.lastReason === 'input-paste')\n\n if (normalized === this.value) {\n if (completes) {\n this.pendingComplete = normalized\n // Value is unchanged so the value observer won't fire — flush manually.\n this.requestUpdate()\n }\n return null\n }\n\n this.value = normalized\n\n // Recommended order on a completing edit: 'input', 'change', then 'complete'\n // (queued and flushed after render, so the value is already committed).\n this.dispatchEvent(new NordEvent('input'))\n this.dispatchEvent(new NordEvent('change'))\n\n this.pendingComplete = completes ? normalized : null\n\n return normalized\n }\n\n /** The reason for the in-flight `setValue`, used to detect re-paste completion. */\n private lastReason: 'input-change' | 'input-clear' | 'input-paste' | 'keyboard' = 'input-change'\n\n /** Report rejected characters to consumers via `value-invalid`. */\n private reportInvalid(raw: string) {\n this.dispatchEvent(new OtpFieldInvalidEvent(raw))\n }\n\n /**\n * Re-select a cell on mousedown so clicking an already-focused filled cell\n * re-selects its character (typing then replaces it) instead of dropping a\n * caret. Mirrors Base UI's OTPFieldInput onMouseDown.\n */\n private handleMousedown(e: MouseEvent, index: number) {\n if (e.defaultPrevented || this.disabled) {\n return\n }\n\n e.preventDefault()\n this.focusInput(index)\n }\n\n private handleInput(e: Event, index: number) {\n // Stop the native input event at the boundary so consumers only ever see the\n // canonical NordEvent('input') dispatched from `setValue` (no double event).\n e.stopPropagation()\n\n if (this.disabled || this.readonly) {\n return\n }\n\n const cell = e.target as HTMLInputElement\n const raw = cell.value\n const [digits, didReject] = normalizeWithDetails(raw, this.length, this.config)\n\n if (didReject) {\n this.lastReason = 'input-change'\n this.reportInvalid(raw)\n }\n\n if (digits === '') {\n const slotValue = this.value[index] ?? ''\n if (raw === '') {\n // The user deleted the cell's character.\n this.lastReason = 'input-clear'\n this.setValue(removeCharacter(this.value, index))\n }\n else {\n // An invalid character was typed (e.g. a letter in a numeric field) —\n // revert the cell to its committed value (empty for an empty cell, the\n // existing digit for a filled one) so the rejected character never\n // lingers visibly in the field.\n cell.value = slotValue\n cell.select()\n }\n return\n }\n\n this.lastReason = 'input-change'\n const next = replaceValue(this.value, index, digits, this.length, this.config)\n const committed = this.setValue(next)\n\n if (committed != null) {\n this.queueFocusInput(Math.min(index + digits.length, this.length - 1), committed)\n }\n else {\n // The edit didn't change the value — e.g. characters typed past a full\n // field, which clamp to a no-op. Base UI's inputs are controlled, so React\n // snaps the cell back to its committed character; the light-DOM cells here\n // aren't, so reset it explicitly to stop the extra keystroke lingering.\n cell.value = this.value[index] ?? ''\n cell.select()\n }\n }\n\n private handleKeydown(e: KeyboardEvent, index: number) {\n // In disabled mode bail WITHOUT preventing default so vertical arrow keys\n // bubble (matches Base UI 'leaves vertical arrow navigation unhandled').\n if (this.disabled) {\n return\n }\n\n const firstIndex = 0\n const lastIndex = Math.max(this.length - 1, firstIndex)\n const endTargetIndex = Math.min(this.value.length, lastIndex)\n const hasBoundaryModifier = (e.ctrlKey || e.metaKey) && !e.altKey\n const isRtl = this.resolveDirection() === 'rtl'\n const previousKey = isRtl ? 'ArrowRight' : 'ArrowLeft'\n const nextKey = isRtl ? 'ArrowLeft' : 'ArrowRight'\n\n // --- Navigation (works in readonly too) ---\n if (e.key === previousKey) {\n this.stopEvent(e)\n this.focusInput(hasBoundaryModifier ? firstIndex : Math.max(firstIndex, index - 1))\n return\n }\n\n if (e.key === nextKey) {\n this.stopEvent(e)\n this.focusInput(hasBoundaryModifier ? endTargetIndex : Math.min(lastIndex, index + 1))\n return\n }\n\n if (e.key === 'Home' || e.key === 'ArrowUp') {\n this.stopEvent(e)\n this.focusInput(firstIndex)\n return\n }\n\n if (e.key === 'End' || e.key === 'ArrowDown') {\n this.stopEvent(e)\n this.focusInput(endTargetIndex)\n return\n }\n\n // --- Value-changing keys (blocked in readonly) ---\n if (this.readonly) {\n return\n }\n\n if (e.key === 'Backspace' && hasBoundaryModifier) {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n if (this.setValue('') != null) {\n this.queueFocusInput(firstIndex, '')\n }\n return\n }\n\n if (e.key === 'Delete') {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n const next = removeCharacter(this.value, index)\n const committed = this.setValue(next)\n if (committed != null) {\n this.queueFocusInput(index, committed)\n }\n return\n }\n\n const slotValue = this.value[index] ?? ''\n const cell = e.currentTarget as HTMLInputElement\n const fullSelection = cell.selectionStart === 0 && cell.selectionEnd === cell.value.length\n\n // Typing the same character into a fully-selected filled cell would be a\n // no-op change; advance instead so the user isn't stuck.\n if (e.key.length === 1 && fullSelection && slotValue === e.key) {\n this.stopEvent(e)\n if (index < this.length - 1) {\n this.focusInput(index + 1)\n }\n return\n }\n\n if (e.key === 'Backspace') {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n const targetIndex = Math.max(firstIndex, index - 1)\n const deleteIndex = slotValue === '' ? targetIndex : index\n const committed = this.setValue(removeCharacter(this.value, deleteIndex))\n if (committed != null) {\n this.queueFocusInput(targetIndex, committed)\n }\n }\n }\n\n private handlePaste(e: ClipboardEvent, index: number) {\n if (this.disabled || this.readonly) {\n return\n }\n\n let raw = ''\n try {\n raw = e.clipboardData?.getData('text/plain') ?? ''\n }\n catch {\n if (process.env.NODE_ENV === 'development') {\n console.warn('NORD: nord-otp-field could not read clipboard text during paste.')\n }\n return\n }\n\n e.preventDefault()\n\n const [digits, didReject] = normalizeWithDetails(raw, this.length, this.config)\n\n this.lastReason = 'input-paste'\n if (didReject) {\n this.reportInvalid(raw)\n }\n\n if (digits === '') {\n return\n }\n\n const next = replaceValue(this.value, index, digits, this.length, this.config)\n const committed = this.setValue(next)\n\n if (committed != null) {\n this.queueFocusInput(Math.min(index + digits.length, this.length - 1), committed)\n }\n }\n\n private handleFocus(e: FocusEvent, index: number) {\n if (this.disabled) {\n return\n }\n\n // Focusing a cell beyond the first empty slot redirects to the first empty one.\n if (index > this.value.length) {\n this.focusInput(Math.min(this.value.length, this.length - 1))\n return\n }\n\n this.focusedIndex = index\n this.focused = true\n this.requestUpdate()\n\n const cell = e.currentTarget as HTMLInputElement\n cell.select()\n }\n\n private handleBlur(e: FocusEvent) {\n // Ignore focus moving between cells within this field.\n if (e.relatedTarget instanceof Node && this.contains(e.relatedTarget)) {\n return\n }\n\n this.focused = false\n this.requestUpdate()\n }\n\n /** The browser focuses the hidden input during autofill — redirect to cell 0. */\n private handleHiddenFocus() {\n this.focusInput(0)\n }\n\n /** SMS autofill writes the whole code into the hidden input. */\n private handleHiddenInput(e: Event) {\n e.stopPropagation()\n\n if (this.disabled || this.readonly) {\n return\n }\n\n const input = e.target as HTMLInputElement\n const [digits, didReject] = normalizeWithDetails(input.value, this.length, this.config)\n\n this.lastReason = 'input-change'\n if (didReject) {\n this.reportInvalid(input.value)\n }\n\n const committed = this.setValue(digits)\n\n if (committed != null && committed !== '') {\n this.queueFocusInput(committed.length - 1, committed)\n }\n }\n\n /** Resolve the effective text direction from the host or document. */\n private resolveDirection(): 'ltr' | 'rtl' {\n const dir = this.closest('[dir]')?.getAttribute('dir')\n ?? (typeof document !== 'undefined' ? document.documentElement.getAttribute('dir') : null)\n return dir === 'rtl' ? 'rtl' : 'ltr'\n }\n\n /** preventDefault + stopPropagation, like Base UI's `stopEvent`. */\n private stopEvent(e: Event) {\n e.preventDefault()\n e.stopPropagation()\n }\n\n /** The id for a given cell — derived so cell ids stay unique and never collide with the host id. */\n private cellId(index: number): string {\n const base = this.getAttribute('id') ?? this.otpId\n return `${base}-${index + 1}`\n }\n\n render() {\n if (!this.hasValidLength) {\n return nothing\n }\n\n const config = this.config\n const value = this.value\n const activeIndex = this.activeIndex\n const groupId = `${this.otpId}-group`\n\n // Naming/description resolved by the FieldControlMixin getters (field context\n // in a field, built-in label/hint/error standalone, or host aria-* fallback).\n // Cell 0 inherits the shared label and the group is named by it.\n const ariaLabel = this.controlAriaLabel\n const ariaLabelledby = this.controlAriaLabelledby\n const ariaDescribedby = this.controlAriaDescribedby\n\n const cells = []\n for (let i = 0; i < this.length; i++) {\n cells.push(this.renderCell(i, value, config, activeIndex, ariaLabel, ariaLabelledby))\n\n // Decorative separators chunk the code, e.g. 123-456.\n if (this.groupSize > 0 && (i + 1) % this.groupSize === 0 && i < this.length - 1) {\n cells.push(html`<span class=\"n-separator\" aria-hidden=\"true\"></span>`)\n }\n }\n\n return html`\n ${this.renderLabel()}\n <div\n class=\"n-otp-field\"\n id=${groupId}\n role=\"group\"\n aria-label=${ifDefined(ariaLabel)}\n aria-labelledby=${ifDefined(ariaLabelledby)}\n aria-describedby=${ifDefined(ariaDescribedby)}\n >\n ${cells}\n </div>\n <input\n class=\"n-hidden-input\"\n type=\"text\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n .value=${value}\n autocomplete=${this.autocomplete}\n inputmode=${config.inputMode}\n minlength=${this.length}\n maxlength=${this.length}\n pattern=${config.rootPattern(this.length)}\n ?disabled=${this.effectiveDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${ifDefined(!this.effectiveDisabled && this.effectiveInvalid ? 'true' : undefined)}\n @focus=${this.handleHiddenFocus}\n @input=${this.handleHiddenInput}\n />\n ${this.renderError()}\n ${this.isHintBelow ? this.renderHint() : nothing}\n `\n }\n\n private renderCell(\n index: number,\n value: string,\n config: OtpValidationConfig,\n activeIndex: number,\n ariaLabel: string | undefined,\n ariaLabelledby: string | undefined,\n ) {\n const slotValue = value[index] ?? ''\n const filled = slotValue !== ''\n\n // Cell 0 inherits the shared field label; later cells get a per-cell label so\n // AT announces which slot is focused.\n const cellAriaLabel = index === 0 ? undefined : this.localize.term('characterLabel', index + 1, this.length)\n const cellAriaLabelledby = index === 0 ? ariaLabelledby : undefined\n const cellAriaLabelInherited = index === 0 ? ariaLabel : undefined\n\n return html`\n <input\n class=\"n-cell\"\n id=${this.cellId(index)}\n .value=${slotValue}\n type=${this.mask ? 'password' : 'text'}\n inputmode=${config.inputMode}\n autocomplete=${index === 0 ? this.autocomplete : 'off'}\n autocorrect=\"off\"\n spellcheck=\"false\"\n enterkeyhint=${index === this.length - 1 ? 'done' : 'next'}\n maxlength=${ifDefined(index === 0 ? this.length : undefined)}\n pattern=${config.slotPattern}\n placeholder=${ifDefined(this.placeholder)}\n tabindex=${activeIndex === index ? 0 : -1}\n ?disabled=${this.effectiveDisabled}\n ?readonly=${this.readonly}\n aria-label=${ifDefined(cellAriaLabel ?? cellAriaLabelInherited)}\n aria-labelledby=${ifDefined(cellAriaLabel == null ? cellAriaLabelledby : undefined)}\n aria-invalid=${ifDefined(!this.effectiveDisabled && this.effectiveInvalid ? 'true' : undefined)}\n data-filled=${ifDefined(filled ? '' : undefined)}\n @mousedown=${(e: MouseEvent) => this.handleMousedown(e, index)}\n @input=${(e: Event) => this.handleInput(e, index)}\n @keydown=${(e: KeyboardEvent) => this.handleKeydown(e, index)}\n @paste=${(e: ClipboardEvent) => this.handlePaste(e, index)}\n @focus=${(e: FocusEvent) => this.handleFocus(e, index)}\n @blur=${(e: FocusEvent) => this.handleBlur(e)}\n />\n `\n }\n\n /** Mirror state to host data-* attributes and flush queued focus/complete. */\n protected updated(changed: PropertyValues) {\n super.updated(changed)\n this.toggleAttribute('complete', this.complete)\n this.toggleAttribute('data-complete', this.complete)\n this.toggleAttribute('data-filled', this.value.length > 0)\n this.toggleAttribute('data-disabled', this.disabled)\n this.toggleAttribute('data-readonly', this.readonly)\n this.toggleAttribute('data-required', this.required)\n // `data-invalid` and `data-focused` are managed by `stateAttributes`.\n\n this.flushPending()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-otp-field': OtpField\n }\n}\n"],"names":["OTP_VALIDATION_CONFIG","numeric","slotPattern","rootPattern","length","regexp","inputMode","alphanumeric","applyValidation","value","config","replace","normalizeWithDetails","stripped","stripWhitespace","normalized","didReject","normalizeValue","custom","maxLength","characters","Array","from","slice","join","normalize","replaceValue","current","index","next","removeCharacter","otpFieldCount","OtpField","DraftComponentMixin","SizeMixin","FieldControlMixin","InputMixin","LitElement","constructor","this","otpId","localize","LocalizeController","formData","FormDataController","undefined","stateAttributes","StateAttributesController","invalid","trackFocus","pendingFocus","pendingComplete","focused","focusedIndex","type","readonly","mask","autocomplete","groupSize","_value","lastReason","ownInvalid","super","complete","old","requestUpdate","_a","hasValidLength","Number","isInteger","activeIndex","last","Math","max","min","connectedCallback","injectLightDomStyles","style","inputId","cellId","ariaObserver","MutationObserver","observe","attributes","attributeFilter","disconnectedCallback","disconnect","createRenderRoot","renormalize","flushPending","dispatchEvent","OtpFieldCompleteEvent","pending","focusInput","cells","querySelectorAll","target","focus","select","queueFocusInput","options","setValue","wasComplete","completes","NordEvent","reportInvalid","raw","OtpFieldInvalidEvent","handleMousedown","e","defaultPrevented","disabled","preventDefault","handleInput","stopPropagation","cell","digits","slotValue","committed","_b","handleKeydown","lastIndex","endTargetIndex","hasBoundaryModifier","ctrlKey","metaKey","altKey","isRtl","resolveDirection","previousKey","nextKey","key","stopEvent","currentTarget","fullSelection","selectionStart","selectionEnd","targetIndex","deleteIndex","handlePaste","clipboardData","getData","_c","handleFocus","handleBlur","relatedTarget","Node","contains","handleHiddenFocus","handleHiddenInput","input","closest","getAttribute","document","documentElement","render","nothing","groupId","ariaLabel","controlAriaLabel","ariaLabelledby","controlAriaLabelledby","ariaDescribedby","controlAriaDescribedby","i","push","renderCell","html","renderLabel","ifDefined","effectiveDisabled","required","effectiveInvalid","renderError","isHintBelow","renderHint","filled","cellAriaLabel","term","cellAriaLabelledby","cellAriaLabelInherited","placeholder","updated","changed","toggleAttribute","__decorate","property","reflect","prototype","Boolean","attribute","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"OtpField.js","sources":["../src/otp-field/OtpField.ts"],"sourcesContent":["import type { PropertyValues } from 'lit'\nimport { html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { FormDataController } from '../common/controllers/FormDataController.js'\nimport { StateAttributesController } from '../common/controllers/StateAttributesController.js'\nimport { observe } from '../common/decorators/observe.js'\nimport { NordEvent } from '../common/events.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport { FieldControlMixin } from '../common/mixins/FieldControlMixin.js'\nimport { InputMixin } from '../common/mixins/InputMixin.js'\nimport { SizeMixin } from '../common/mixins/SizeMixin.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './OtpField.css'\nimport { OtpFieldCompleteEvent, OtpFieldInvalidEvent } from './OtpFieldEvents.js'\n\nexport { OtpFieldCompleteEvent, OtpFieldInvalidEvent } from './OtpFieldEvents.js'\n\n/** The character sets the field accepts, mirroring Base UI's `validationType`. */\nexport type OtpFieldType = 'numeric' | 'alphanumeric'\n\ninterface OtpValidationConfig {\n /** Pattern for a single cell input, e.g. `'\\\\d{1}'`. */\n slotPattern: string\n /** Builds the full-value pattern for the hidden input, e.g. `'\\\\d{6}'`. */\n rootPattern: (length: number) => string\n /** Strips characters not allowed by this type. */\n regexp: RegExp\n /** Virtual-keyboard hint for cells and the hidden input. */\n inputMode: 'numeric' | 'text'\n /** Optional consumer normalization (mirrors Base UI's `normalizeValue`). */\n normalizeValue?: (value: string) => string\n}\n\n// Kept as a table (rather than inline branches) so adding Base UI's `alpha` /\n// `none` types later is a one-line change.\nconst OTP_VALIDATION_CONFIG: Record<OtpFieldType, OtpValidationConfig> = {\n numeric: {\n slotPattern: '\\\\d{1}',\n rootPattern: length => `\\\\d{${length}}`,\n regexp: /\\D/g,\n inputMode: 'numeric',\n },\n alphanumeric: {\n slotPattern: '[a-zA-Z0-9]{1}',\n rootPattern: length => `[a-zA-Z0-9]{${length}}`,\n regexp: /[^a-z0-9]/gi,\n inputMode: 'text',\n },\n}\n\n/** Strips all whitespace from a raw OTP string. */\nfunction stripWhitespace(value: string | null | undefined): string {\n return (value ?? '').replace(/\\s/g, '')\n}\n\n/** Removes characters not permitted by the type's regexp. */\nfunction applyValidation(value: string, config: OtpValidationConfig): string {\n return value.replace(config.regexp, '')\n}\n\n/**\n * Normalizes user-entered OTP text: strips whitespace, filters by `type`, then\n * clamps to `length` by Unicode code point so multi-byte characters never split\n * across a cell. Returns the normalized value plus whether any character was\n * rejected (so the caller can fire `value-invalid`).\n */\nfunction normalizeWithDetails(\n value: string | null | undefined,\n length: number,\n config: OtpValidationConfig,\n): readonly [value: string, didRejectCharacters: boolean] {\n const stripped = stripWhitespace(value)\n let normalized = applyValidation(stripped, config)\n let didReject = stripped.length > normalized.length\n\n // Optional consumer normalization (e.g. uppercasing), mirroring Base UI's\n // `normalizeValue`: runs after type filtering, then the result is filtered\n // again so a normalizer can't introduce characters the type disallows.\n if (config.normalizeValue) {\n const custom = config.normalizeValue(normalized)\n didReject ||= normalized.length > custom.length\n normalized = applyValidation(custom, config)\n didReject ||= custom.length > normalized.length\n }\n\n // Slice by code points so multi-byte characters do not split across slots.\n const maxLength = length < 0 ? 0 : length\n const characters = Array.from(normalized)\n\n return [\n characters.slice(0, maxLength).join(''),\n didReject || characters.length > maxLength,\n ]\n}\n\n/** Convenience wrapper returning only the normalized value. */\nfunction normalize(value: string | null | undefined, length: number, config: OtpValidationConfig): string {\n return normalizeWithDetails(value, length, config)[0]\n}\n\n/**\n * Replaces characters starting at `index`, then re-normalizes so paste and\n * multi-character edits stay contiguous and length-bounded.\n */\nfunction replaceValue(\n current: string,\n index: number,\n next: string,\n length: number,\n config: OtpValidationConfig,\n): string {\n const normalized = normalize(next, length, config)\n const prefix = current.slice(0, index)\n const suffix = current.slice(index + normalized.length)\n\n return normalize(`${prefix}${normalized}${suffix}`, length, config)\n}\n\n/** Splices a single character out of the value at `index`. */\nfunction removeCharacter(current: string, index: number): string {\n if (index < 0 || index >= current.length) {\n return current\n }\n\n return `${current.slice(0, index)}${current.slice(index + 1)}`\n}\n\n/** Per-instance counter so light-DOM ids stay unique when the host has no `id`. */\nlet otpFieldCount = 1\n\n/**\n * OTP Field is a segmented one-time-code input: it renders `length` individual\n * character cells plus a visually-hidden input that holds the full value, enabling\n * SMS / keychain autofill and native `pattern`/`required` validation. Typing fills\n * and auto-advances, Backspace clears and moves back, the arrow keys navigate, and\n * pasting a code distributes its characters across the cells.\n *\n * OTP Field is a control only — it has no built-in label, hint or error. Compose\n * it inside a [Field](/components/field/) with a [Field Label](/components/field-label/)\n * (connected with `for`) to give it an accessible name, helper text and an error\n * message, exactly like a native input.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {NordEvent} input - Dispatched whenever the OTP value changes through user interaction (typing, Backspace/Delete, paste, autofill).\n * @fires {NordEvent} change - Dispatched alongside `input` when the committed value changes via user interaction.\n * @fires {OtpFieldCompleteEvent} complete - Dispatched after the value updates when every cell becomes filled.\n * @fires {OtpFieldInvalidEvent} value-invalid - Dispatched when typed or pasted text contained characters rejected by `type`.\n *\n * @localization characterLabel - Per-cell accessible label, given the 1-based cell position and total cell count.\n *\n * @attr {boolean} data-invalid - Present while the field is invalid (mirrors the \\`invalid\\` property). Style hook for the whole control.\n * @attr {boolean} data-focused - Present while any cell has focus. Style hook for focus-within treatments.\n *\n * @cssprop [--n-otp-field-gap=var(--n-space-s)] - Gap between cells (and between groups when `group-size` is used).\n * @cssprop [--n-otp-field-cell-size=var(--n-space-xl)] - Controls the block-size and inline-size of each square cell. When unset, size maps to the shared control block sizes.\n * @cssprop [--n-otp-field-background=var(--n-color-surface)] - Cell background.\n * @cssprop [--n-otp-field-border-color=var(--n-color-border-strong)] - Cell border color (resting).\n * @cssprop [--n-otp-field-border-radius=var(--n-border-radius-s)] - Cell corner radius.\n * @cssprop [--n-otp-field-font-size=var(--n-font-size-m)] - Cell character font size.\n */\n@customElement('nord-otp-field')\nexport default class OtpField extends DraftComponentMixin(SizeMixin(FieldControlMixin(InputMixin(LitElement)))) {\n /** Stable, unique id base for light-DOM ARIA wiring of this instance. */\n private otpId = `nord-otp-field-${otpFieldCount++}`\n\n private localize = new LocalizeController<'nord-otp-field'>(this)\n\n private formData = new FormDataController(this, { value: () => this.value || undefined })\n\n /** Reflects `invalid` to `data-invalid` and focus-within to `data-focused`. */\n private stateAttributes = new StateAttributesController(\n this,\n () => ({ invalid: this.invalid }),\n { trackFocus: true },\n )\n\n /** Re-renders when the host's forwarded ARIA labelling attributes change. */\n private ariaObserver?: MutationObserver\n\n /** Index + value to focus once the async value update has applied. */\n private pendingFocus: { index: number, value: string } | null = null\n\n /** Value to fire `complete` for once the async value update has applied. */\n private pendingComplete: string | null = null\n\n /** Whether any cell currently holds focus (drives roving tabindex + data-focused). */\n private focused = false\n\n /** The cell index that currently has (or last had) focus. */\n private focusedIndex = 0\n\n /**\n * The number of OTP cells. Must be a positive integer.\n */\n @property({ reflect: true, type: Number }) length = 6\n\n /**\n * Controls the allowed characters, `inputmode` and `pattern`. `numeric` accepts\n * digits; `alphanumeric` accepts letters and digits.\n */\n @property({ reflect: true }) type: OtpFieldType = 'numeric'\n\n /**\n * Prevents the user from changing the value while keeping navigation and focus.\n */\n @property({ reflect: true, type: Boolean }) readonly = false\n\n /**\n * Obscures each cell (renders `type=\"password\"`) for use on shared screens.\n */\n @property({ reflect: true, type: Boolean }) mask = false\n\n /**\n * Placeholder character or string shown in every empty cell.\n */\n @property({ reflect: true }) placeholder?: string\n\n /**\n * Marks the field invalid, applying error styling and `aria-invalid` to every\n * cell and the hidden input. Pair with a `nord-field-error` in the Field.\n */\n @property({ reflect: true, type: Boolean }) invalid = false\n\n // The control's own invalid state for the field context: its `invalid` prop or\n // a built-in `error` (when used standalone).\n protected override get ownInvalid() {\n return this.invalid || super.ownInvalid\n }\n\n /**\n * The autocomplete token applied to the first cell and the hidden input (all\n * other cells get `autocomplete=\"off\"`). Defaults to `one-time-code` to enable\n * SMS / keychain OTP autofill.\n */\n @property() autocomplete = 'one-time-code'\n\n /**\n * Renders a decorative separator after every N cells (for example, `3` shows\n * `123-456`). `0` disables grouping. The separator is `aria-hidden` and does\n * not affect the value or navigation.\n */\n @property({ reflect: true, type: Number, attribute: 'group-size' }) groupSize = 0\n\n /**\n * Whether every cell is filled (`value.length === length`). Read-only and\n * derived from `value`; reflected as the `complete` attribute so consumers can\n * style the completed state.\n */\n get complete(): boolean {\n return this.length > 0 && this._value.length === this.length\n }\n\n /** Backing store for the normalized value. */\n private _value = ''\n\n /**\n * The OTP value, for example `'123456'`. Whitespace is stripped, characters are\n * filtered by `type`, and the result is clamped to `length`. Set programmatically\n * to prefill.\n */\n @property()\n // @ts-expect-error - intentionally re-declares the inherited `value` property as a normalizing accessor\n get value(): string {\n return this._value\n }\n\n set value(next: string) {\n const old = this._value\n const normalized = normalize(next, this.length, this.config)\n\n if (normalized === old) {\n return\n }\n\n this._value = normalized\n this.requestUpdate('value', old)\n }\n\n /**\n * Function that normalizes the value after whitespace and `type` filtering —\n * e.g. `el.normalizeValue = v => v.toUpperCase()`. It runs whenever the field\n * normalizes a value (initial, programmatic, and user edits), inside the\n * component's own pipeline, so live normalization never fights the per-cell\n * focus handling. The result is filtered by `type` again, then clamped to\n * `length`; it should be idempotent since the same value may be normalized\n * more than once. Characters rejected while normalizing are reported through\n * `value-invalid`. Mirrors Base UI's `normalizeValue`.\n */\n @property({ attribute: false }) normalizeValue?: (value: string) => string\n\n /** The validation config for the current `type`. */\n private get config(): OtpValidationConfig {\n return {\n ...(OTP_VALIDATION_CONFIG[this.type] ?? OTP_VALIDATION_CONFIG.numeric),\n normalizeValue: this.normalizeValue,\n }\n }\n\n /** Whether `length` is a usable positive integer. */\n private get hasValidLength(): boolean {\n return Number.isInteger(this.length) && this.length > 0\n }\n\n /** The index of the cell that is currently tabbable (roving tabindex). */\n private get activeIndex(): number {\n const last = Math.max(this.length - 1, 0)\n\n return this.focused\n ? Math.min(Math.max(this.focusedIndex, 0), last)\n : Math.min(this.value.length, last)\n }\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n\n // The built-in `<label for>` (from FieldControlMixin) focuses the first cell.\n this.inputId = this.cellId(0)\n\n // An external label (e.g. nord-field-label) names the control by setting\n // `aria-labelledby`/`aria-label` on the host; forward it to the first cell.\n this.ariaObserver ??= new MutationObserver(() => this.requestUpdate())\n this.ariaObserver.observe(this, {\n attributes: true,\n attributeFilter: ['aria-label', 'aria-labelledby', 'aria-describedby'],\n })\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.ariaObserver?.disconnect()\n this.ariaObserver = undefined\n }\n\n // Render in the light DOM so the control participates in the document tree\n // (form labelling, Tailwind), like the other new Nord components.\n protected createRenderRoot() {\n return this\n }\n\n /** Re-normalize the value when `length` or `type` changes (e.g. clamps it). */\n @observe('length')\n @observe('type')\n protected renormalize() {\n const normalized = normalize(this._value, this.length, this.config)\n\n if (normalized !== this._value) {\n this._value = normalized\n this.requestUpdate()\n }\n }\n\n /**\n * Flush queued focus/complete once the value update has actually applied.\n * Runs from `updated()` (after every render) rather than a value observer so\n * it also fires for a re-paste that completes an already-complete value (the\n * value text is unchanged, so a value observer would not run).\n */\n private flushPending() {\n if (this.pendingComplete != null) {\n const value = this.pendingComplete\n this.pendingComplete = null\n\n if (value === this.value) {\n this.dispatchEvent(new OtpFieldCompleteEvent(value))\n }\n }\n\n if (this.pendingFocus != null) {\n const pending = this.pendingFocus\n this.pendingFocus = null\n\n if (pending.value === this.value) {\n this.focusInput(pending.index)\n }\n }\n }\n\n /** Live list of the rendered cell inputs, in DOM order. */\n private get cells(): HTMLInputElement[] {\n return Array.from(this.querySelectorAll<HTMLInputElement>('input.n-cell'))\n }\n\n /** Focus a cell by index (clamped), then select its content. */\n private focusInput(index: number) {\n const cells = this.cells\n const target = cells[Math.min(Math.max(index, 0), Math.max(cells.length - 1, 0))]\n target?.focus()\n target?.select()\n }\n\n /** Queue a focus to run once the value update applies (Lit renders async). */\n private queueFocusInput(index: number, value: string) {\n this.pendingFocus = { index, value }\n }\n\n /** Focus the field by moving focus into its active cell. */\n focus(options?: FocusOptions) {\n this.cells[this.activeIndex]?.focus(options)\n }\n\n /**\n * Commit a new value, firing `input` + `change` (and queuing `complete` when\n * the field becomes filled). Returns the committed value, or `null` if nothing\n * changed.\n */\n private setValue(next: string): string | null {\n const normalized = normalize(next, this.length, this.config)\n const wasComplete = this.value.length === this.length\n\n // A completing change, OR a complete value (re-)committed via paste, signals\n // completion — even when the value text is unchanged.\n const completes = normalized.length === this.length && (!wasComplete || this.lastReason === 'input-paste')\n\n if (normalized === this.value) {\n if (completes) {\n this.pendingComplete = normalized\n // Value is unchanged so the value observer won't fire — flush manually.\n this.requestUpdate()\n }\n return null\n }\n\n this.value = normalized\n\n // Recommended order on a completing edit: 'input', 'change', then 'complete'\n // (queued and flushed after render, so the value is already committed).\n this.dispatchEvent(new NordEvent('input'))\n this.dispatchEvent(new NordEvent('change'))\n\n this.pendingComplete = completes ? normalized : null\n\n return normalized\n }\n\n /** The reason for the in-flight `setValue`, used to detect re-paste completion. */\n private lastReason: 'input-change' | 'input-clear' | 'input-paste' | 'keyboard' = 'input-change'\n\n /** Report rejected characters to consumers via `value-invalid`. */\n private reportInvalid(raw: string) {\n this.dispatchEvent(new OtpFieldInvalidEvent(raw))\n }\n\n /**\n * Re-select a cell on mousedown so clicking an already-focused filled cell\n * re-selects its character (typing then replaces it) instead of dropping a\n * caret. Mirrors Base UI's OTPFieldInput onMouseDown.\n */\n private handleMousedown(e: MouseEvent, index: number) {\n if (e.defaultPrevented || this.disabled) {\n return\n }\n\n e.preventDefault()\n this.focusInput(index)\n }\n\n private handleInput(e: Event, index: number) {\n // Stop the native input event at the boundary so consumers only ever see the\n // canonical NordEvent('input') dispatched from `setValue` (no double event).\n e.stopPropagation()\n\n if (this.disabled || this.readonly) {\n return\n }\n\n const cell = e.target as HTMLInputElement\n const raw = cell.value\n const [digits, didReject] = normalizeWithDetails(raw, this.length, this.config)\n\n if (didReject) {\n this.lastReason = 'input-change'\n this.reportInvalid(raw)\n }\n\n if (digits === '') {\n const slotValue = this.value[index] ?? ''\n if (raw === '') {\n // The user deleted the cell's character.\n this.lastReason = 'input-clear'\n this.setValue(removeCharacter(this.value, index))\n }\n else {\n // An invalid character was typed (e.g. a letter in a numeric field) —\n // revert the cell to its committed value (empty for an empty cell, the\n // existing digit for a filled one) so the rejected character never\n // lingers visibly in the field.\n cell.value = slotValue\n cell.select()\n }\n return\n }\n\n this.lastReason = 'input-change'\n const next = replaceValue(this.value, index, digits, this.length, this.config)\n const committed = this.setValue(next)\n\n if (committed != null) {\n this.queueFocusInput(Math.min(index + digits.length, this.length - 1), committed)\n }\n else {\n // The edit didn't change the value — e.g. characters typed past a full\n // field, which clamp to a no-op. Base UI's inputs are controlled, so React\n // snaps the cell back to its committed character; the light-DOM cells here\n // aren't, so reset it explicitly to stop the extra keystroke lingering.\n cell.value = this.value[index] ?? ''\n cell.select()\n }\n }\n\n private handleKeydown(e: KeyboardEvent, index: number) {\n // In disabled mode bail WITHOUT preventing default so vertical arrow keys\n // bubble (matches Base UI 'leaves vertical arrow navigation unhandled').\n if (this.disabled) {\n return\n }\n\n const firstIndex = 0\n const lastIndex = Math.max(this.length - 1, firstIndex)\n const endTargetIndex = Math.min(this.value.length, lastIndex)\n const hasBoundaryModifier = (e.ctrlKey || e.metaKey) && !e.altKey\n const isRtl = this.resolveDirection() === 'rtl'\n const previousKey = isRtl ? 'ArrowRight' : 'ArrowLeft'\n const nextKey = isRtl ? 'ArrowLeft' : 'ArrowRight'\n\n // --- Navigation (works in readonly too) ---\n if (e.key === previousKey) {\n this.stopEvent(e)\n this.focusInput(hasBoundaryModifier ? firstIndex : Math.max(firstIndex, index - 1))\n return\n }\n\n if (e.key === nextKey) {\n this.stopEvent(e)\n this.focusInput(hasBoundaryModifier ? endTargetIndex : Math.min(lastIndex, index + 1))\n return\n }\n\n if (e.key === 'Home' || e.key === 'ArrowUp') {\n this.stopEvent(e)\n this.focusInput(firstIndex)\n return\n }\n\n if (e.key === 'End' || e.key === 'ArrowDown') {\n this.stopEvent(e)\n this.focusInput(endTargetIndex)\n return\n }\n\n // --- Value-changing keys (blocked in readonly) ---\n if (this.readonly) {\n return\n }\n\n if (e.key === 'Backspace' && hasBoundaryModifier) {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n if (this.setValue('') != null) {\n this.queueFocusInput(firstIndex, '')\n }\n return\n }\n\n if (e.key === 'Delete') {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n const next = removeCharacter(this.value, index)\n const committed = this.setValue(next)\n if (committed != null) {\n this.queueFocusInput(index, committed)\n }\n return\n }\n\n const slotValue = this.value[index] ?? ''\n const cell = e.currentTarget as HTMLInputElement\n const fullSelection = cell.selectionStart === 0 && cell.selectionEnd === cell.value.length\n\n // Typing the same character into a fully-selected filled cell would be a\n // no-op change; advance instead so the user isn't stuck.\n if (e.key.length === 1 && fullSelection && slotValue === e.key) {\n this.stopEvent(e)\n if (index < this.length - 1) {\n this.focusInput(index + 1)\n }\n return\n }\n\n if (e.key === 'Backspace') {\n this.stopEvent(e)\n this.lastReason = 'keyboard'\n const targetIndex = Math.max(firstIndex, index - 1)\n const deleteIndex = slotValue === '' ? targetIndex : index\n const committed = this.setValue(removeCharacter(this.value, deleteIndex))\n if (committed != null) {\n this.queueFocusInput(targetIndex, committed)\n }\n }\n }\n\n private handlePaste(e: ClipboardEvent, index: number) {\n if (this.disabled || this.readonly) {\n return\n }\n\n let raw = ''\n try {\n raw = e.clipboardData?.getData('text/plain') ?? ''\n }\n catch {\n if (process.env.NODE_ENV === 'development') {\n console.warn('NORD: nord-otp-field could not read clipboard text during paste.')\n }\n return\n }\n\n e.preventDefault()\n\n const [digits, didReject] = normalizeWithDetails(raw, this.length, this.config)\n\n this.lastReason = 'input-paste'\n if (didReject) {\n this.reportInvalid(raw)\n }\n\n if (digits === '') {\n return\n }\n\n const next = replaceValue(this.value, index, digits, this.length, this.config)\n const committed = this.setValue(next)\n\n if (committed != null) {\n this.queueFocusInput(Math.min(index + digits.length, this.length - 1), committed)\n }\n }\n\n private handleFocus(e: FocusEvent, index: number) {\n if (this.disabled) {\n return\n }\n\n // Focusing a cell beyond the first empty slot redirects to the first empty one.\n if (index > this.value.length) {\n this.focusInput(Math.min(this.value.length, this.length - 1))\n return\n }\n\n this.focusedIndex = index\n this.focused = true\n this.requestUpdate()\n\n const cell = e.currentTarget as HTMLInputElement\n cell.select()\n }\n\n private handleBlur(e: FocusEvent) {\n // Ignore focus moving between cells within this field.\n if (e.relatedTarget instanceof Node && this.contains(e.relatedTarget)) {\n return\n }\n\n this.focused = false\n this.requestUpdate()\n }\n\n /** The browser focuses the hidden input during autofill — redirect to cell 0. */\n private handleHiddenFocus() {\n this.focusInput(0)\n }\n\n /** SMS autofill writes the whole code into the hidden input. */\n private handleHiddenInput(e: Event) {\n e.stopPropagation()\n\n if (this.disabled || this.readonly) {\n return\n }\n\n const input = e.target as HTMLInputElement\n const [digits, didReject] = normalizeWithDetails(input.value, this.length, this.config)\n\n this.lastReason = 'input-change'\n if (didReject) {\n this.reportInvalid(input.value)\n }\n\n const committed = this.setValue(digits)\n\n if (committed != null && committed !== '') {\n this.queueFocusInput(committed.length - 1, committed)\n }\n }\n\n /** Resolve the effective text direction from the host or document. */\n private resolveDirection(): 'ltr' | 'rtl' {\n const dir = this.closest('[dir]')?.getAttribute('dir')\n ?? (typeof document !== 'undefined' ? document.documentElement.getAttribute('dir') : null)\n return dir === 'rtl' ? 'rtl' : 'ltr'\n }\n\n /** preventDefault + stopPropagation, like Base UI's `stopEvent`. */\n private stopEvent(e: Event) {\n e.preventDefault()\n e.stopPropagation()\n }\n\n /** The id for a given cell — derived so cell ids stay unique and never collide with the host id. */\n private cellId(index: number): string {\n const base = this.getAttribute('id') ?? this.otpId\n return `${base}-${index + 1}`\n }\n\n render() {\n if (!this.hasValidLength) {\n return nothing\n }\n\n const config = this.config\n const value = this.value\n const activeIndex = this.activeIndex\n const groupId = `${this.otpId}-group`\n\n // Naming/description resolved by the FieldControlMixin getters (field context\n // in a field, built-in label/hint/error standalone, or host aria-* fallback).\n // Cell 0 inherits the shared label and the group is named by it.\n const ariaLabel = this.controlAriaLabel\n const ariaLabelledby = this.controlAriaLabelledby\n const ariaDescribedby = this.controlAriaDescribedby\n\n const cells = []\n for (let i = 0; i < this.length; i++) {\n cells.push(this.renderCell(i, value, config, activeIndex, ariaLabel, ariaLabelledby))\n\n // Decorative separators chunk the code, e.g. 123-456.\n if (this.groupSize > 0 && (i + 1) % this.groupSize === 0 && i < this.length - 1) {\n cells.push(html`<span class=\"n-separator\" aria-hidden=\"true\"></span>`)\n }\n }\n\n return html`\n ${this.renderLabel()}\n <div\n class=\"n-otp-field\"\n id=${groupId}\n role=\"group\"\n aria-label=${ifDefined(ariaLabel)}\n aria-labelledby=${ifDefined(ariaLabelledby)}\n aria-describedby=${ifDefined(ariaDescribedby)}\n >\n ${cells}\n </div>\n <input\n class=\"n-hidden-input\"\n type=\"text\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n .value=${value}\n autocomplete=${this.autocomplete}\n inputmode=${config.inputMode}\n minlength=${this.length}\n maxlength=${this.length}\n pattern=${config.rootPattern(this.length)}\n ?disabled=${this.effectiveDisabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${ifDefined(!this.effectiveDisabled && this.effectiveInvalid ? 'true' : undefined)}\n @focus=${this.handleHiddenFocus}\n @input=${this.handleHiddenInput}\n />\n ${this.renderError()}\n ${this.isHintBelow ? this.renderHint() : nothing}\n `\n }\n\n private renderCell(\n index: number,\n value: string,\n config: OtpValidationConfig,\n activeIndex: number,\n ariaLabel: string | undefined,\n ariaLabelledby: string | undefined,\n ) {\n const slotValue = value[index] ?? ''\n const filled = slotValue !== ''\n\n // Cell 0 inherits the shared field label; later cells get a per-cell label so\n // AT announces which slot is focused.\n const cellAriaLabel = index === 0 ? undefined : this.localize.term('characterLabel', index + 1, this.length)\n const cellAriaLabelledby = index === 0 ? ariaLabelledby : undefined\n const cellAriaLabelInherited = index === 0 ? ariaLabel : undefined\n\n return html`\n <input\n class=\"n-cell\"\n id=${this.cellId(index)}\n .value=${slotValue}\n type=${this.mask ? 'password' : 'text'}\n inputmode=${config.inputMode}\n autocomplete=${index === 0 ? this.autocomplete : 'off'}\n autocorrect=\"off\"\n spellcheck=\"false\"\n enterkeyhint=${index === this.length - 1 ? 'done' : 'next'}\n maxlength=${ifDefined(index === 0 ? this.length : undefined)}\n pattern=${config.slotPattern}\n placeholder=${ifDefined(this.placeholder)}\n tabindex=${activeIndex === index ? 0 : -1}\n ?disabled=${this.effectiveDisabled}\n ?readonly=${this.readonly}\n aria-label=${ifDefined(cellAriaLabel ?? cellAriaLabelInherited)}\n aria-labelledby=${ifDefined(cellAriaLabel == null ? cellAriaLabelledby : undefined)}\n aria-invalid=${ifDefined(!this.effectiveDisabled && this.effectiveInvalid ? 'true' : undefined)}\n data-filled=${ifDefined(filled ? '' : undefined)}\n @mousedown=${(e: MouseEvent) => this.handleMousedown(e, index)}\n @input=${(e: Event) => this.handleInput(e, index)}\n @keydown=${(e: KeyboardEvent) => this.handleKeydown(e, index)}\n @paste=${(e: ClipboardEvent) => this.handlePaste(e, index)}\n @focus=${(e: FocusEvent) => this.handleFocus(e, index)}\n @blur=${(e: FocusEvent) => this.handleBlur(e)}\n />\n `\n }\n\n /** Mirror state to host data-* attributes and flush queued focus/complete. */\n protected updated(changed: PropertyValues) {\n super.updated(changed)\n this.toggleAttribute('complete', this.complete)\n this.toggleAttribute('data-complete', this.complete)\n this.toggleAttribute('data-filled', this.value.length > 0)\n this.toggleAttribute('data-disabled', this.disabled)\n this.toggleAttribute('data-readonly', this.readonly)\n this.toggleAttribute('data-required', this.required)\n // `data-invalid` and `data-focused` are managed by `stateAttributes`.\n\n this.flushPending()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-otp-field': OtpField\n }\n}\n"],"names":["OTP_VALIDATION_CONFIG","numeric","slotPattern","rootPattern","length","regexp","inputMode","alphanumeric","applyValidation","value","config","replace","normalizeWithDetails","stripped","stripWhitespace","normalized","didReject","normalizeValue","custom","maxLength","characters","Array","from","slice","join","normalize","replaceValue","current","index","next","removeCharacter","otpFieldCount","OtpField","DraftComponentMixin","SizeMixin","FieldControlMixin","InputMixin","LitElement","constructor","this","otpId","localize","LocalizeController","formData","FormDataController","undefined","stateAttributes","StateAttributesController","invalid","trackFocus","pendingFocus","pendingComplete","focused","focusedIndex","type","readonly","mask","autocomplete","groupSize","_value","lastReason","ownInvalid","super","complete","old","requestUpdate","_a","hasValidLength","Number","isInteger","activeIndex","last","Math","max","min","connectedCallback","injectLightDomStyles","style","inputId","cellId","ariaObserver","MutationObserver","observe","attributes","attributeFilter","disconnectedCallback","disconnect","createRenderRoot","renormalize","flushPending","dispatchEvent","OtpFieldCompleteEvent","pending","focusInput","cells","querySelectorAll","target","focus","select","queueFocusInput","options","setValue","wasComplete","completes","NordEvent","reportInvalid","raw","OtpFieldInvalidEvent","handleMousedown","e","defaultPrevented","disabled","preventDefault","handleInput","stopPropagation","cell","digits","slotValue","committed","_b","handleKeydown","lastIndex","endTargetIndex","hasBoundaryModifier","ctrlKey","metaKey","altKey","isRtl","resolveDirection","previousKey","nextKey","key","stopEvent","currentTarget","fullSelection","selectionStart","selectionEnd","targetIndex","deleteIndex","handlePaste","clipboardData","getData","_c","handleFocus","handleBlur","relatedTarget","Node","contains","handleHiddenFocus","handleHiddenInput","input","closest","getAttribute","document","documentElement","render","nothing","groupId","ariaLabel","controlAriaLabel","ariaLabelledby","controlAriaLabelledby","ariaDescribedby","controlAriaDescribedby","i","push","renderCell","html","renderLabel","ifDefined","effectiveDisabled","required","effectiveInvalid","renderError","isHintBelow","renderHint","filled","cellAriaLabel","term","cellAriaLabelledby","cellAriaLabelInherited","placeholder","updated","changed","toggleAttribute","__decorate","property","reflect","prototype","Boolean","attribute","customElement"],"mappings":"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"}
package/lib/Outline.js CHANGED
@@ -1,2 +1,2 @@
1
- import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{css as t,isServer as i,nothing as n,html as o,LitElement as r}from"lit";import{property as s,state as a,query as l,customElement as c}from"lit/decorators.js";import{S as d}from"./SlotController-Z6eG7LSZ.js";import{c as h}from"./cond-CI1KbneT.js";import{N as u}from"./events-Bv6wNHwJ.js";import{D as v}from"./DraftComponentMixin-4qug5Rky.js";import{s as p}from"./Component-BJ5O5n8k.js";import{LocalizeController as m}from"./LocalizeController.js";import"./OutlineItem.js";import"./EventController-BBOmvfLa.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";const f=t`:host{--n-outline-indicator-color:var(--n-color-accent);--n-outline-track-color:var(--n-color-border);--n-outline-indicator-width:2px;--n-outline-indent:var(--n-space-m);--n-outline-header-color:var(--n-color-text-weaker);--n-outline-header-font-size:var(--n-font-size-s);--n-outline-item-padding-block:var(--n-space-s);display:block}:host([density=compact]){--n-outline-indent:var(--n-space-s);--n-outline-item-padding-block:var(--n-space-xs)}.n-outline{position:relative}.n-outline-header{color:var(--n-outline-header-color);font-size:var(--n-outline-header-font-size);font-weight:var(--n-font-weight-active);line-height:var(--n-line-height-tight);margin-block-end:var(--n-space-s);padding-inline-start:calc(var(--n-outline-indicator-width) + var(--n-space-s))}:host([density=compact]) .n-outline-header{margin-block-end:var(--n-space-xs)}.n-outline-list{padding-inline-start:calc(var(--n-outline-indicator-width) + var(--n-space-s));position:relative}.n-outline-track{background:var(--n-outline-track-color);inset-block:0}.n-outline-indicator,.n-outline-track{border-radius:var(--n-border-radius-pill);inline-size:var(--n-outline-indicator-width);inset-inline-start:0;position:absolute}.n-outline-indicator{background:var(--n-outline-indicator-color);block-size:0;inset-block-start:0;opacity:0;transition:transform .2s ease-in-out,block-size .2s ease-in-out,opacity .2s ease-in-out;will-change:transform,block-size}.n-outline-indicator.is-visible{opacity:1}@media (prefers-reduced-motion:reduce){.n-outline-indicator{transition:opacity .2s ease-in-out}}.n-outline-item.is-generated{border-radius:var(--n-border-radius-s);color:var(--n-color-text-weak);cursor:pointer;display:block;font-family:inherit;font-size:var(--n-font-size-s);line-height:var(--n-line-height-tight);overflow:hidden;padding-block:var(--n-outline-item-padding-block);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-outline-indent);text-decoration:none;text-overflow:ellipsis;transition:color .1s ease-in-out;white-space:nowrap}.n-outline-item.is-generated[level="2"]{padding-inline-start:calc(var(--n-outline-indent)*2)}.n-outline-item.is-generated[level="3"]{padding-inline-start:calc(var(--n-outline-indent)*3)}.n-outline-item.is-generated[level="4"]{padding-inline-start:calc(var(--n-outline-indent)*4)}.n-outline-item.is-generated:hover{color:var(--n-color-text)}.n-outline-item.is-generated:focus-visible{box-shadow:0 0 0 2px var(--n-color-accent);outline:none}.n-outline-item.is-generated[aria-current=location]{color:var(--n-color-text-link);font-weight:var(--n-font-weight-active)}`;class b extends u{constructor(e){super("change"),Object.defineProperty(this,"activeId",{value:e,enumerable:!0,writable:!1})}}let g=class extends(v(r)){constructor(){super(...arguments),this.localize=new m(this),this.headerSlot=new d(this,"header"),this.density="default",this.headingSelector="h1,h2,h3,h4",this.hideHeader=!1,this.scanned=[],this.controlled=!1,this.intersecting=new Set,this.handleIntersect=e=>{for(const t of e){const e=t.target.id;t.isIntersecting?this.intersecting.add(e):this.intersecting.delete(e)}const t=this.entries.map((e=>e.id)).find((e=>this.intersecting.has(e)));t&&t!==this.active&&this.setActive(t)},this.handleClick=e=>{if(e.defaultPrevented||0!==e.button||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;const t=e.composedPath().find((e=>e instanceof HTMLAnchorElement)),i=null==t?void 0:t.getAttribute("href");if(!(null==i?void 0:i.startsWith("#")))return;const n=i.slice(1),o=document.getElementById(n);if(!o)return;e.preventDefault();const r="undefined"!=typeof matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches;o.scrollIntoView({behavior:r?"auto":"smooth",block:"start"}),"undefined"!=typeof history&&history.replaceState(null,"",`#${n}`),this.setActive(n)},this.handleSlotChange=()=>{this.refresh()}}connectedCallback(){super.connectedCallback(),this.hasAttribute("role")||this.setAttribute("role","navigation"),this.hasAttribute("aria-label")||this.hasAttribute("aria-labelledby")||this.setAttribute("aria-label",this.localize.term("label")),this.addEventListener("click",this.handleClick)}disconnectedCallback(){var e,t,i;super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),null===(e=this.observer)||void 0===e||e.disconnect(),null===(t=this.resizeObserver)||void 0===t||t.disconnect(),null===(i=this.mutationObserver)||void 0===i||i.disconnect()}firstUpdated(){i||(this.controlled=null!=this.active&&""!==this.active,this.scanContent(),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver((()=>this.updateIndicator())),this.resizeObserver.observe(this)),this.mutationObserver=new MutationObserver((()=>this.refresh())),this.mutationObserver.observe(this,{childList:!0}),this.refresh())}updated(e){e.has("active")&&(this.applyActiveToItems(),this.updateIndicator()),(e.has("for")||e.has("headingSelector"))&&(this.scanContent(),this.refresh()),e.has("scrollContainer")&&this.observeTargets(),e.has("scanned")&&this.refresh()}refresh(){this.observeTargets(),this.applyActiveToItems(),this.updateIndicator()}get entries(){if(this.for){return[...this.renderRoot.querySelectorAll("a.n-outline-item")].map((e=>{var t;return{id:null!==(t=e.dataset.id)&&void 0!==t?t:"",element:e,setActive:()=>{}}}))}return[...this.querySelectorAll("nord-outline-item")].map((e=>{var t;return{id:(null!==(t=e.getAttribute("href"))&&void 0!==t?t:"").replace(/^#/,""),element:e,setActive:t=>{e.active=t}}}))}scanContent(){var e;if(i||!this.for)return void(this.scanned=[]);const t=null!==(e=document.getElementById(this.for))&&void 0!==e?e:document.querySelector(this.for);if(!t)return void(this.scanned=[]);const n=[...t.querySelectorAll(this.headingSelector)];this.scanned=n.map((e=>{var t,i,n;e.id||(e.id=(null!==(t=e.textContent)&&void 0!==t?t:"").trim().toLowerCase().replace(/[^\w\s-]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-"));const o=Number(e.tagName.slice(1))||1;return{id:e.id,text:null!==(n=null===(i=e.textContent)||void 0===i?void 0:i.trim())&&void 0!==n?n:"",level:Math.min(Math.max(o,1),4)}}))}observeTargets(){var e,t,n,o;if(null===(e=this.observer)||void 0===e||e.disconnect(),this.intersecting.clear(),this.controlled||i||"undefined"==typeof IntersectionObserver)return;const r=this.scrollContainer?document.querySelector(this.scrollContainer):null,s=this.for?null!==(t=document.getElementById(this.for))&&void 0!==t?t:document.querySelector(this.for):this,a=null!==(n=null!=r?r:null==s?void 0:s.closest("nord-scroll-area"))&&void 0!==n?n:null;let l=null;if(a)if("nord-scroll-area"===a.localName){const e=null===(o=a.shadowRoot)||void 0===o?void 0:o.querySelector('[part~="viewport"]');if(!e)return void customElements.whenDefined("nord-scroll-area").then((()=>{this.isConnected&&this.observeTargets()}));l=e}else l=a;this.observer=new IntersectionObserver(this.handleIntersect,{root:l,rootMargin:"0px 0px -66% 0px",threshold:0});for(const e of this.entries){const t=e.id?document.getElementById(e.id):null;t&&this.observer.observe(t)}}setActive(e){this.active=e,this.dispatchEvent(new b(e))}applyActiveToItems(){for(const e of this.entries)e.setActive(e.id===this.active)}updateIndicator(){const e=this.indicatorEl,t=this.containerEl;if(!e||!t)return;const i=this.entries.find((e=>e.id===this.active));if(!i)return void e.classList.remove("is-visible");const n=t.getBoundingClientRect(),o=i.element.getBoundingClientRect();e.style.transform=`translateY(${o.top-n.top}px)`,e.style.blockSize=`${o.height}px`,e.classList.add("is-visible")}renderHeader(){return this.hideHeader?n:this.headerSlot.hasContent?o`<div class="n-outline-header" part="header"><slot name="header"></slot></div>`:o`<div class="n-outline-header" part="header" aria-hidden="true">${this.localize.term("label")}</div>`}render(){return o`<div class="n-outline" part="base">${this.renderHeader()}<div class="n-outline-list" part="list"><span class="n-outline-track" aria-hidden="true"></span> <span class="n-outline-indicator" aria-hidden="true"></span> ${this.for?this.scanned.map((e=>o`<a class="n-outline-item is-generated" data-id="${e.id}" href="#${e.id}" level="${e.level}" aria-current="${h(this.active===e.id,"location")}">${e.text}</a>`)):o`<slot @slotchange="${this.handleSlotChange}"></slot>`}</div></div>`}};g.styles=[p,f],e([s({reflect:!0})],g.prototype,"active",void 0),e([s({reflect:!0})],g.prototype,"density",void 0),e([s({reflect:!0})],g.prototype,"for",void 0),e([s({attribute:"heading-selector"})],g.prototype,"headingSelector",void 0),e([s({attribute:"scroll-container"})],g.prototype,"scrollContainer",void 0),e([s({type:Boolean,reflect:!0,attribute:"hide-header"})],g.prototype,"hideHeader",void 0),e([a()],g.prototype,"scanned",void 0),e([l(".n-outline-list")],g.prototype,"containerEl",void 0),e([l(".n-outline-indicator")],g.prototype,"indicatorEl",void 0),g=e([c("nord-outline")],g);var y=g;export{b as NordOutlineChangeEvent,y as default};
1
+ import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{css as t,isServer as i,nothing as n,html as o,LitElement as r}from"lit";import{property as s,state as a,query as l,customElement as c}from"lit/decorators.js";import{S as d}from"./SlotController-Z6eG7LSZ.js";import{c as h}from"./cond-CI1KbneT.js";import{N as u}from"./events-Bv6wNHwJ.js";import{D as v}from"./DraftComponentMixin-4qug5Rky.js";import{s as p}from"./Component-BJ5O5n8k.js";import{LocalizeController as m}from"./LocalizeController.js";import"./OutlineItem.js";import"./EventController-BBOmvfLa.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";const f=t`:host{--n-outline-indicator-color:var(--n-color-accent);--n-outline-track-color:var(--n-color-border);--n-outline-indicator-width:2px;--n-outline-indent:var(--n-space-m);--n-outline-header-color:var(--n-color-text-weaker);--n-outline-header-font-size:var(--n-font-size-s);--n-outline-item-padding-block:var(--n-space-s);display:block}:host([density=compact]){--n-outline-indent:var(--n-space-s);--n-outline-item-padding-block:var(--n-space-xs)}.n-outline{position:relative}.n-outline-header{color:var(--n-outline-header-color);font-size:var(--n-outline-header-font-size);font-weight:var(--n-font-weight-active);line-height:var(--n-line-height-tight);margin-block-end:var(--n-space-s);padding-inline-start:calc(var(--n-outline-indicator-width) + var(--n-space-s))}:host([density=compact]) .n-outline-header{margin-block-end:var(--n-space-xs)}.n-outline-list{padding-inline-start:calc(var(--n-outline-indicator-width) + var(--n-space-s));position:relative}.n-outline-track{background:var(--n-outline-track-color);inset-block:0}.n-outline-indicator,.n-outline-track{border-radius:var(--n-border-radius-pill);inline-size:var(--n-outline-indicator-width);inset-inline-start:0;position:absolute}.n-outline-indicator{background:var(--n-outline-indicator-color);block-size:0;inset-block-start:0;opacity:0;transition:transform .2s ease-in-out,block-size .2s ease-in-out,opacity .2s ease-in-out;will-change:transform,block-size}.n-outline-indicator.is-visible{opacity:1}@media (prefers-reduced-motion:reduce){.n-outline-indicator{transition:opacity .2s ease-in-out}}.n-outline-item.is-generated{border-radius:var(--n-border-radius-s);color:var(--n-color-text-weak);cursor:pointer;display:block;font-family:inherit;font-size:var(--n-font-size-s);line-height:var(--n-line-height-tight);overflow:hidden;padding-block:var(--n-outline-item-padding-block);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-outline-indent);text-decoration:none;text-overflow:ellipsis;transition:color .1s ease-in-out;white-space:nowrap}.n-outline-item.is-generated[level="2"]{padding-inline-start:calc(var(--n-outline-indent)*2)}.n-outline-item.is-generated[level="3"]{padding-inline-start:calc(var(--n-outline-indent)*3)}.n-outline-item.is-generated[level="4"]{padding-inline-start:calc(var(--n-outline-indent)*4)}.n-outline-item.is-generated:hover{color:var(--n-color-text)}.n-outline-item.is-generated:focus-visible{box-shadow:0 0 0 2px var(--n-color-accent);outline:none}.n-outline-item.is-generated[aria-current=location]{color:var(--n-color-text-link);font-weight:var(--n-font-weight-active)}`;class b extends u{constructor(e){super("change"),Object.defineProperty(this,"activeId",{value:e,enumerable:!0,writable:!1})}}let g=class extends(v(r)){constructor(){super(...arguments),this.localize=new m(this),this.headerSlot=new d(this,"header"),this.density="default",this.headingSelector="h1,h2,h3,h4",this.hideHeader=!1,this.scanned=[],this.controlled=!1,this.intersecting=new Set,this.handleIntersect=e=>{for(const t of e){const e=t.target.id;t.isIntersecting?this.intersecting.add(e):this.intersecting.delete(e)}const t=this.entries.map((e=>e.id)).find((e=>this.intersecting.has(e)));t&&t!==this.active&&this.setActive(t)},this.handleClick=e=>{if(e.defaultPrevented||0!==e.button||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;const t=e.composedPath().find((e=>e instanceof HTMLAnchorElement)),i=null==t?void 0:t.getAttribute("href");if(!(null==i?void 0:i.startsWith("#")))return;const n=i.slice(1),o=document.getElementById(n);if(!o)return;e.preventDefault();const r="undefined"!=typeof matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches;o.scrollIntoView({behavior:r?"auto":"smooth",block:"start"}),"undefined"!=typeof history&&history.replaceState(null,"",`#${n}`),this.setActive(n)},this.handleSlotChange=()=>{this.refresh()}}connectedCallback(){super.connectedCallback(),this.hasAttribute("role")||this.setAttribute("role","navigation"),this.hasAttribute("aria-label")||this.hasAttribute("aria-labelledby")||this.setAttribute("aria-label",this.localize.term("label")),this.addEventListener("click",this.handleClick)}disconnectedCallback(){var e,t,i;super.disconnectedCallback(),this.removeEventListener("click",this.handleClick),null===(e=this.observer)||void 0===e||e.disconnect(),null===(t=this.resizeObserver)||void 0===t||t.disconnect(),null===(i=this.mutationObserver)||void 0===i||i.disconnect()}firstUpdated(){i||(this.controlled=null!=this.active&&""!==this.active,this.scanContent(),"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver((()=>this.updateIndicator())),this.resizeObserver.observe(this)),this.mutationObserver=new MutationObserver((()=>this.refresh())),this.mutationObserver.observe(this,{childList:!0}),this.refresh())}updated(e){e.has("active")&&(this.applyActiveToItems(),this.updateIndicator()),(e.has("for")||e.has("headingSelector"))&&(this.scanContent(),this.refresh()),e.has("scrollContainer")&&this.observeTargets(),e.has("scanned")&&this.refresh()}refresh(){this.observeTargets(),this.applyActiveToItems(),this.updateIndicator()}get entries(){if(this.for){return[...this.renderRoot.querySelectorAll("a.n-outline-item")].map((e=>{var t;return{id:null!==(t=e.dataset.id)&&void 0!==t?t:"",element:e,setActive:()=>{}}}))}return[...this.querySelectorAll("nord-outline-item")].map((e=>{var t;return{id:(null!==(t=e.getAttribute("href"))&&void 0!==t?t:"").replace(/^#/,""),element:e,setActive:t=>{e.active=t}}}))}scanContent(){var e;if(i||!this.for)return void(this.scanned=[]);const t=null!==(e=document.getElementById(this.for))&&void 0!==e?e:document.querySelector(this.for);if(!t)return void(this.scanned=[]);const n=[...t.querySelectorAll(this.headingSelector)];this.scanned=n.map((e=>{var t,i,n;e.id||(e.id=(null!==(t=e.textContent)&&void 0!==t?t:"").trim().toLowerCase().replace(/[^\w\s-]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-"));const o=Number(e.tagName.slice(1))||1;return{id:e.id,text:null!==(n=null===(i=e.textContent)||void 0===i?void 0:i.trim())&&void 0!==n?n:"",level:Math.min(Math.max(o,1),4)}}))}observeTargets(){var e,t,n,o;if(null===(e=this.observer)||void 0===e||e.disconnect(),this.intersecting.clear(),this.controlled||i||"undefined"==typeof IntersectionObserver)return;const r=this.scrollContainer?document.querySelector(this.scrollContainer):null,s=this.for?null!==(t=document.getElementById(this.for))&&void 0!==t?t:document.querySelector(this.for):this,a=null!==(n=null!=r?r:null==s?void 0:s.closest("nord-scroll-area"))&&void 0!==n?n:null;let l=null;if(a)if("nord-scroll-area"===a.localName){const e=null===(o=a.shadowRoot)||void 0===o?void 0:o.querySelector('[part~="viewport"]');if(!e)return void customElements.whenDefined("nord-scroll-area").then((()=>{this.isConnected&&this.observeTargets()}));l=e}else l=a;this.observer=new IntersectionObserver(this.handleIntersect,{root:l,rootMargin:"0px 0px -66% 0px",threshold:0});for(const e of this.entries){const t=e.id?document.getElementById(e.id):null;t&&this.observer.observe(t)}}setActive(e){this.active=e,this.dispatchEvent(new b(e))}applyActiveToItems(){for(const e of this.entries)e.setActive(e.id===this.active)}updateIndicator(){const e=this.indicatorEl,t=this.containerEl;if(!e||!t)return;const i=this.entries.find((e=>e.id===this.active));if(!i)return void e.classList.remove("is-visible");const n=t.getBoundingClientRect(),o=i.element.getBoundingClientRect();e.style.transform=`translateY(${o.top-n.top}px)`,e.style.blockSize=`${o.height}px`,e.classList.add("is-visible")}renderHeader(){return this.hideHeader?n:this.headerSlot.hasContent?o`<div class="n-outline-header" part="header"><slot name="header"></slot></div>`:o`<div class="n-outline-header" part="header" aria-hidden="true">${this.localize.term("label")}</div>`}render(){return o`<div class="n-outline" part="base">${this.renderHeader()}<div class="n-outline-list" part="list"><span class="n-outline-track" aria-hidden="true"></span> <span class="n-outline-indicator" aria-hidden="true"></span> ${this.for?this.scanned.map((e=>o`<a class="n-outline-item is-generated" data-id="${e.id}" href="#${e.id}" level="${e.level}" aria-current="${h(this.active===e.id,"location")}">${e.text}</a>`)):o`<slot @slotchange="${this.handleSlotChange}"></slot>`}</div></div>`}};g.styles=[p,f],e([s({reflect:!0})],g.prototype,"active",void 0),e([s({reflect:!0})],g.prototype,"density",void 0),e([s({reflect:!0})],g.prototype,"for",void 0),e([s({attribute:"heading-selector"})],g.prototype,"headingSelector",void 0),e([s({attribute:"scroll-container"})],g.prototype,"scrollContainer",void 0),e([s({type:Boolean,reflect:!0,attribute:"hide-header"})],g.prototype,"hideHeader",void 0),e([a()],g.prototype,"scanned",void 0),e([l(".n-outline-list")],g.prototype,"containerEl",void 0),e([l(".n-outline-indicator")],g.prototype,"indicatorEl",void 0),g=e([c("nord-outline")],g);var y=g;export{b as NordOutlineChangeEvent,y as default};
2
2
  //# sourceMappingURL=Outline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Outline.js","sources":["../src/outline/Outline.ts"],"sourcesContent":["import type OutlineItem from './OutlineItem.js'\nimport { html, isServer, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { SlotController } from '../common/controllers/SlotController.js'\nimport { cond } from '../common/directives/cond.js'\nimport { NordEvent } from '../common/events.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport componentStyle from '../common/styles/Component.css'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './Outline.css'\n\nimport './OutlineItem.js'\n\n/**\n * Event dispatched when the active section of an Outline changes, either via the\n * built-in scroll-spy, a click on one of its items, or a programmatic change.\n * The event's `activeId` is the id of the newly active heading.\n */\nexport class NordOutlineChangeEvent extends NordEvent {\n declare activeId: string\n\n constructor(activeId: string) {\n super('change')\n Object.defineProperty(this, 'activeId', {\n value: activeId,\n enumerable: true,\n writable: false,\n })\n }\n}\n\ninterface ScannedHeading {\n id: string\n text: string\n level: number\n}\n\ninterface OutlineEntry {\n id: string\n element: HTMLElement\n setActive: (active: boolean) => void\n}\n\nfunction slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n}\n\n/**\n * Outline is an in-page table of contents that lists a page's headings and\n * highlights the section currently in view as you scroll.\n *\n * Provide [Outline Item](/components/outline-item/) children, or point `for` at\n * a container to build the list from its headings.\n *\n * @status draft\n * @category navigation\n *\n * @slot - The default slot for [Outline Item](/components/outline-item/) children.\n * @slot header - Custom header content shown above the list. Overrides the default localized \"On this page\" heading. Set `hide-header` to remove the header entirely.\n *\n * @fires {NordOutlineChangeEvent} change - Dispatched when the active section changes. Includes an `activeId` property.\n *\n * @localization label - Accessible label for the outline navigation landmark, and the default header text.\n *\n * @cssprop [--n-outline-indicator-color=var(--n-color-accent)] - Color of the sliding active indicator.\n * @cssprop [--n-outline-track-color=var(--n-color-border)] - Color of the static track behind the indicator.\n * @cssprop [--n-outline-indicator-width=2px] - Thickness of the track and indicator.\n * @cssprop [--n-outline-indent=var(--n-space-m)] - Indentation step applied per heading level.\n * @cssprop [--n-outline-header-color=var(--n-color-text-weaker)] - Color of the default header text.\n * @cssprop [--n-outline-header-font-size=var(--n-font-size-s)] - Font size of the default header text.\n */\n@customElement('nord-outline')\nexport default class Outline extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n protected localize = new LocalizeController<'nord-outline'>(this)\n\n private headerSlot = new SlotController(this, 'header')\n\n /**\n * The id of the active heading. Setting this puts the Outline in controlled\n * mode and disables the built-in scroll-spy, so your own logic owns the\n * highlight (mirrors providing `activeId` in other libraries).\n */\n @property({ reflect: true }) active?: string\n\n /**\n * Tightens spacing for dense sidebars where vertical space is at a premium.\n */\n @property({ reflect: true }) density: 'default' | 'compact' = 'default'\n\n /**\n * DOM-scan mode: the id (or any CSS selector) of the content container whose\n * headings should populate the outline. When set, slotted children are\n * ignored and items are generated from the matched headings.\n */\n @property({ reflect: true }) for?: string\n\n /**\n * The selector used to find headings when `for` is set.\n */\n @property({ attribute: 'heading-selector' }) headingSelector = 'h1,h2,h3,h4'\n\n /**\n * CSS selector for the element that scrolls the content, used as the\n * scroll-spy `IntersectionObserver` root. Point this at your scroll container\n * when the page scrolls inside an element rather than the window — otherwise\n * the observer watches the window and never sees the headings move. If the\n * selector resolves to a `nord-scroll-area`, its scroll viewport is used.\n *\n * When unset, the nearest ancestor `nord-scroll-area` of the scanned content\n * is detected automatically, falling back to the window.\n */\n @property({ attribute: 'scroll-container' }) scrollContainer?: string\n\n /**\n * Hides the header. By default Outline shows a localized \"On this page\"\n * heading (or the `header` slot's content) above the list.\n */\n @property({ type: Boolean, reflect: true, attribute: 'hide-header' }) hideHeader = false\n\n @state() private scanned: ScannedHeading[] = []\n\n @query('.n-outline-list') private containerEl?: HTMLElement\n @query('.n-outline-indicator') private indicatorEl?: HTMLElement\n\n private controlled = false\n private observer?: IntersectionObserver\n private resizeObserver?: ResizeObserver\n private mutationObserver?: MutationObserver\n private readonly intersecting = new Set<string>()\n\n connectedCallback() {\n super.connectedCallback()\n\n // Expose a navigation landmark with an accessible name, without clobbering\n // any semantics the consumer has already provided.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'navigation')\n }\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n this.setAttribute('aria-label', this.localize.term('label'))\n }\n\n this.addEventListener('click', this.handleClick)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('click', this.handleClick)\n this.observer?.disconnect()\n this.resizeObserver?.disconnect()\n this.mutationObserver?.disconnect()\n }\n\n protected firstUpdated() {\n if (isServer) {\n return\n }\n\n // Controlled mode is decided once, by whether the consumer supplied a\n // non-empty `active`. An empty value leaves scroll-spy in charge.\n this.controlled = this.active != null && this.active !== ''\n\n this.scanContent()\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.updateIndicator())\n this.resizeObserver.observe(this)\n }\n\n // Watch for slotted items being added/removed (e.g. via v-for / *ngFor).\n this.mutationObserver = new MutationObserver(() => this.refresh())\n this.mutationObserver.observe(this, { childList: true })\n\n this.refresh()\n }\n\n protected updated(changed: Map<string, unknown>) {\n if (changed.has('active')) {\n this.applyActiveToItems()\n this.updateIndicator()\n }\n if (changed.has('for') || changed.has('headingSelector')) {\n this.scanContent()\n this.refresh()\n }\n if (changed.has('scrollContainer')) {\n this.observeTargets()\n }\n if (changed.has('scanned')) {\n this.refresh()\n }\n }\n\n /** Re-derive entries, restart scroll-spy and reposition the indicator. */\n private refresh() {\n this.observeTargets()\n this.applyActiveToItems()\n this.updateIndicator()\n }\n\n /** The ordered list of items, normalised across slotted and scan modes. */\n private get entries(): OutlineEntry[] {\n if (this.for) {\n const anchors = [...this.renderRoot.querySelectorAll<HTMLAnchorElement>('a.n-outline-item')]\n return anchors.map(anchor => ({\n id: anchor.dataset.id ?? '',\n element: anchor,\n // Generated anchors get their active styling from `aria-current` in render().\n setActive: () => {},\n }))\n }\n\n const items = [...this.querySelectorAll<OutlineItem>('nord-outline-item')]\n return items.map(item => ({\n id: (item.getAttribute('href') ?? '').replace(/^#/, ''),\n element: item,\n setActive: (active: boolean) => {\n item.active = active\n },\n }))\n }\n\n private scanContent() {\n if (isServer || !this.for) {\n this.scanned = []\n return\n }\n\n const root = document.getElementById(this.for) ?? document.querySelector(this.for)\n if (!root) {\n this.scanned = []\n return\n }\n\n const headings = [...root.querySelectorAll<HTMLElement>(this.headingSelector)]\n this.scanned = headings.map((heading) => {\n if (!heading.id) {\n heading.id = slugify(heading.textContent ?? '')\n }\n const level = Number(heading.tagName.slice(1)) || 1\n return {\n id: heading.id,\n text: heading.textContent?.trim() ?? '',\n level: Math.min(Math.max(level, 1), 4),\n }\n })\n }\n\n private observeTargets() {\n this.observer?.disconnect()\n this.intersecting.clear()\n\n if (this.controlled || isServer || typeof IntersectionObserver === 'undefined') {\n return\n }\n\n // Resolve the scroll container to observe within. An explicit\n // `scroll-container` selector wins; otherwise auto-detect the nearest\n // ancestor `nord-scroll-area` of the scanned content. A `nord-scroll-area`\n // is resolved down to its scroll viewport (the element that actually\n // scrolls). When nothing resolves, `root` stays null — the observer then\n // watches the document viewport (body/html), the original behaviour.\n const explicit = this.scrollContainer ? document.querySelector(this.scrollContainer) : null\n const contentRoot = this.for\n ? (document.getElementById(this.for) ?? document.querySelector(this.for))\n : this\n const container = explicit ?? contentRoot?.closest('nord-scroll-area') ?? null\n\n let root: Element | null = null\n if (container) {\n if (container.localName === 'nord-scroll-area') {\n const viewport = container.shadowRoot?.querySelector('[part~=\"viewport\"]')\n if (!viewport) {\n // The scroll-area hasn't upgraded yet; re-run once it has so we\n // observe the real scroller rather than falling back to the window.\n customElements.whenDefined('nord-scroll-area').then(() => {\n if (this.isConnected) {\n this.observeTargets()\n }\n })\n return\n }\n root = viewport\n }\n else {\n root = container\n }\n }\n\n // A heading becomes active as it nears the top of the container. The lower\n // bound keeps the section active while the reader is within it.\n this.observer = new IntersectionObserver(this.handleIntersect, {\n root,\n rootMargin: '0px 0px -66% 0px',\n threshold: 0,\n })\n\n for (const entry of this.entries) {\n const target = entry.id ? document.getElementById(entry.id) : null\n if (target) {\n this.observer.observe(target)\n }\n }\n }\n\n private handleIntersect = (entries: IntersectionObserverEntry[]) => {\n for (const entry of entries) {\n const id = entry.target.id\n if (entry.isIntersecting) {\n this.intersecting.add(id)\n }\n else {\n this.intersecting.delete(id)\n }\n }\n\n // Pick the first heading in document order that's currently in view.\n const next = this.entries.map(e => e.id).find(id => this.intersecting.has(id))\n if (next && next !== this.active) {\n this.setActive(next)\n }\n }\n\n private setActive(id: string) {\n this.active = id\n this.dispatchEvent(new NordOutlineChangeEvent(id))\n }\n\n private applyActiveToItems() {\n for (const entry of this.entries) {\n entry.setActive(entry.id === this.active)\n }\n }\n\n private updateIndicator() {\n const indicator = this.indicatorEl\n const container = this.containerEl\n if (!indicator || !container) {\n return\n }\n\n const active = this.entries.find(entry => entry.id === this.active)\n if (!active) {\n indicator.classList.remove('is-visible')\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = active.element.getBoundingClientRect()\n indicator.style.transform = `translateY(${itemRect.top - containerRect.top}px)`\n indicator.style.blockSize = `${itemRect.height}px`\n indicator.classList.add('is-visible')\n }\n\n private handleClick = (event: MouseEvent) => {\n // Honour modifier-clicks (open in new tab, etc.) — let the browser handle them.\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n\n const anchor = event.composedPath().find((node): node is HTMLAnchorElement => node instanceof HTMLAnchorElement)\n const href = anchor?.getAttribute('href')\n if (!href?.startsWith('#')) {\n return\n }\n\n const id = href.slice(1)\n const target = document.getElementById(id)\n if (!target) {\n return\n }\n\n event.preventDefault()\n const reduceMotion = typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches\n target.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' })\n\n if (typeof history !== 'undefined') {\n history.replaceState(null, '', `#${id}`)\n }\n\n // Update immediately for responsiveness, even in controlled mode the click\n // is an explicit user intent so we reflect it and notify.\n this.setActive(id)\n }\n\n private handleSlotChange = () => {\n this.refresh()\n }\n\n private renderHeader() {\n if (this.hideHeader) {\n return nothing\n }\n // A custom header (slot) keeps its own semantics. The default text header is\n // hidden from assistive tech because the host's aria-label already names the\n // navigation landmark with the same term, avoiding a duplicate announcement.\n if (this.headerSlot.hasContent) {\n return html`<div class=\"n-outline-header\" part=\"header\"><slot name=\"header\"></slot></div>`\n }\n return html`<div class=\"n-outline-header\" part=\"header\" aria-hidden=\"true\">${this.localize.term('label')}</div>`\n }\n\n render() {\n return html`\n <div class=\"n-outline\" part=\"base\">\n ${this.renderHeader()}\n <div class=\"n-outline-list\" part=\"list\">\n <span class=\"n-outline-track\" aria-hidden=\"true\"></span>\n <span class=\"n-outline-indicator\" aria-hidden=\"true\"></span>\n ${this.for\n ? this.scanned.map(\n heading => html`\n <a\n class=\"n-outline-item is-generated\"\n data-id=${heading.id}\n href=\"#${heading.id}\"\n level=${heading.level}\n aria-current=${cond(this.active === heading.id, 'location')}\n >${heading.text}</a\n >\n `,\n )\n : html`<slot @slotchange=${this.handleSlotChange}></slot>`}\n </div>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-outline': Outline\n }\n}\n"],"names":["NordOutlineChangeEvent","NordEvent","constructor","activeId","super","Object","defineProperty","this","value","enumerable","writable","Outline","DraftComponentMixin","LitElement","localize","LocalizeController","headerSlot","SlotController","density","headingSelector","hideHeader","scanned","controlled","intersecting","Set","handleIntersect","entries","entry","id","target","isIntersecting","add","delete","next","map","e","find","has","active","setActive","handleClick","event","defaultPrevented","button","metaKey","ctrlKey","shiftKey","altKey","anchor","composedPath","node","HTMLAnchorElement","href","getAttribute","startsWith","slice","document","getElementById","preventDefault","reduceMotion","matchMedia","matches","scrollIntoView","behavior","block","history","replaceState","handleSlotChange","refresh","connectedCallback","hasAttribute","setAttribute","term","addEventListener","disconnectedCallback","removeEventListener","_a","observer","disconnect","_b","resizeObserver","_c","mutationObserver","firstUpdated","isServer","scanContent","ResizeObserver","updateIndicator","observe","MutationObserver","childList","updated","changed","applyActiveToItems","observeTargets","for","renderRoot","querySelectorAll","dataset","element","item","replace","root","querySelector","headings","heading","textContent","trim","toLowerCase","level","Number","tagName","text","Math","min","max","clear","IntersectionObserver","explicit","scrollContainer","contentRoot","container","closest","localName","viewport","_d","shadowRoot","customElements","whenDefined","then","isConnected","rootMargin","threshold","dispatchEvent","indicator","indicatorEl","containerEl","classList","remove","containerRect","getBoundingClientRect","itemRect","style","transform","top","blockSize","height","renderHeader","nothing","hasContent","html","render","cond","styles","componentStyle","__decorate","property","reflect","prototype","attribute","type","Boolean","state","query","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"Outline.js","sources":["../src/outline/Outline.ts"],"sourcesContent":["import type OutlineItem from './OutlineItem.js'\nimport { html, isServer, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { SlotController } from '../common/controllers/SlotController.js'\nimport { cond } from '../common/directives/cond.js'\nimport { NordEvent } from '../common/events.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport componentStyle from '../common/styles/Component.css'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './Outline.css'\n\nimport './OutlineItem.js'\n\n/**\n * Event dispatched when the active section of an Outline changes, either via the\n * built-in scroll-spy, a click on one of its items, or a programmatic change.\n * The event's `activeId` is the id of the newly active heading.\n */\nexport class NordOutlineChangeEvent extends NordEvent {\n declare activeId: string\n\n constructor(activeId: string) {\n super('change')\n Object.defineProperty(this, 'activeId', {\n value: activeId,\n enumerable: true,\n writable: false,\n })\n }\n}\n\ninterface ScannedHeading {\n id: string\n text: string\n level: number\n}\n\ninterface OutlineEntry {\n id: string\n element: HTMLElement\n setActive: (active: boolean) => void\n}\n\nfunction slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n}\n\n/**\n * Outline is an in-page table of contents that lists a page's headings and\n * highlights the section currently in view as you scroll.\n *\n * Provide [Outline Item](/components/outline-item/) children, or point `for` at\n * a container to build the list from its headings.\n *\n * @status draft\n * @category navigation\n *\n * @slot - The default slot for [Outline Item](/components/outline-item/) children.\n * @slot header - Custom header content shown above the list. Overrides the default localized \"On this page\" heading. Set `hide-header` to remove the header entirely.\n *\n * @fires {NordOutlineChangeEvent} change - Dispatched when the active section changes. Includes an `activeId` property.\n *\n * @localization label - Accessible label for the outline navigation landmark, and the default header text.\n *\n * @cssprop [--n-outline-indicator-color=var(--n-color-accent)] - Color of the sliding active indicator.\n * @cssprop [--n-outline-track-color=var(--n-color-border)] - Color of the static track behind the indicator.\n * @cssprop [--n-outline-indicator-width=2px] - Thickness of the track and indicator.\n * @cssprop [--n-outline-indent=var(--n-space-m)] - Indentation step applied per heading level.\n * @cssprop [--n-outline-header-color=var(--n-color-text-weaker)] - Color of the default header text.\n * @cssprop [--n-outline-header-font-size=var(--n-font-size-s)] - Font size of the default header text.\n */\n@customElement('nord-outline')\nexport default class Outline extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n protected localize = new LocalizeController<'nord-outline'>(this)\n\n private headerSlot = new SlotController(this, 'header')\n\n /**\n * The id of the active heading. Setting this puts the Outline in controlled\n * mode and disables the built-in scroll-spy, so your own logic owns the\n * highlight (mirrors providing `activeId` in other libraries).\n */\n @property({ reflect: true }) active?: string\n\n /**\n * Tightens spacing for dense sidebars where vertical space is at a premium.\n */\n @property({ reflect: true }) density: 'default' | 'compact' = 'default'\n\n /**\n * DOM-scan mode: the id (or any CSS selector) of the content container whose\n * headings should populate the outline. When set, slotted children are\n * ignored and items are generated from the matched headings.\n */\n @property({ reflect: true }) for?: string\n\n /**\n * The selector used to find headings when `for` is set.\n */\n @property({ attribute: 'heading-selector' }) headingSelector = 'h1,h2,h3,h4'\n\n /**\n * CSS selector for the element that scrolls the content, used as the\n * scroll-spy `IntersectionObserver` root. Point this at your scroll container\n * when the page scrolls inside an element rather than the window — otherwise\n * the observer watches the window and never sees the headings move. If the\n * selector resolves to a `nord-scroll-area`, its scroll viewport is used.\n *\n * When unset, the nearest ancestor `nord-scroll-area` of the scanned content\n * is detected automatically, falling back to the window.\n */\n @property({ attribute: 'scroll-container' }) scrollContainer?: string\n\n /**\n * Hides the header. By default Outline shows a localized \"On this page\"\n * heading (or the `header` slot's content) above the list.\n */\n @property({ type: Boolean, reflect: true, attribute: 'hide-header' }) hideHeader = false\n\n @state() private scanned: ScannedHeading[] = []\n\n @query('.n-outline-list') private containerEl?: HTMLElement\n @query('.n-outline-indicator') private indicatorEl?: HTMLElement\n\n private controlled = false\n private observer?: IntersectionObserver\n private resizeObserver?: ResizeObserver\n private mutationObserver?: MutationObserver\n private readonly intersecting = new Set<string>()\n\n connectedCallback() {\n super.connectedCallback()\n\n // Expose a navigation landmark with an accessible name, without clobbering\n // any semantics the consumer has already provided.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'navigation')\n }\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n this.setAttribute('aria-label', this.localize.term('label'))\n }\n\n this.addEventListener('click', this.handleClick)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('click', this.handleClick)\n this.observer?.disconnect()\n this.resizeObserver?.disconnect()\n this.mutationObserver?.disconnect()\n }\n\n protected firstUpdated() {\n if (isServer) {\n return\n }\n\n // Controlled mode is decided once, by whether the consumer supplied a\n // non-empty `active`. An empty value leaves scroll-spy in charge.\n this.controlled = this.active != null && this.active !== ''\n\n this.scanContent()\n\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.updateIndicator())\n this.resizeObserver.observe(this)\n }\n\n // Watch for slotted items being added/removed (e.g. via v-for / *ngFor).\n this.mutationObserver = new MutationObserver(() => this.refresh())\n this.mutationObserver.observe(this, { childList: true })\n\n this.refresh()\n }\n\n protected updated(changed: Map<string, unknown>) {\n if (changed.has('active')) {\n this.applyActiveToItems()\n this.updateIndicator()\n }\n if (changed.has('for') || changed.has('headingSelector')) {\n this.scanContent()\n this.refresh()\n }\n if (changed.has('scrollContainer')) {\n this.observeTargets()\n }\n if (changed.has('scanned')) {\n this.refresh()\n }\n }\n\n /** Re-derive entries, restart scroll-spy and reposition the indicator. */\n private refresh() {\n this.observeTargets()\n this.applyActiveToItems()\n this.updateIndicator()\n }\n\n /** The ordered list of items, normalised across slotted and scan modes. */\n private get entries(): OutlineEntry[] {\n if (this.for) {\n const anchors = [...this.renderRoot.querySelectorAll<HTMLAnchorElement>('a.n-outline-item')]\n return anchors.map(anchor => ({\n id: anchor.dataset.id ?? '',\n element: anchor,\n // Generated anchors get their active styling from `aria-current` in render().\n setActive: () => {},\n }))\n }\n\n const items = [...this.querySelectorAll<OutlineItem>('nord-outline-item')]\n return items.map(item => ({\n id: (item.getAttribute('href') ?? '').replace(/^#/, ''),\n element: item,\n setActive: (active: boolean) => {\n item.active = active\n },\n }))\n }\n\n private scanContent() {\n if (isServer || !this.for) {\n this.scanned = []\n return\n }\n\n const root = document.getElementById(this.for) ?? document.querySelector(this.for)\n if (!root) {\n this.scanned = []\n return\n }\n\n const headings = [...root.querySelectorAll<HTMLElement>(this.headingSelector)]\n this.scanned = headings.map((heading) => {\n if (!heading.id) {\n heading.id = slugify(heading.textContent ?? '')\n }\n const level = Number(heading.tagName.slice(1)) || 1\n return {\n id: heading.id,\n text: heading.textContent?.trim() ?? '',\n level: Math.min(Math.max(level, 1), 4),\n }\n })\n }\n\n private observeTargets() {\n this.observer?.disconnect()\n this.intersecting.clear()\n\n if (this.controlled || isServer || typeof IntersectionObserver === 'undefined') {\n return\n }\n\n // Resolve the scroll container to observe within. An explicit\n // `scroll-container` selector wins; otherwise auto-detect the nearest\n // ancestor `nord-scroll-area` of the scanned content. A `nord-scroll-area`\n // is resolved down to its scroll viewport (the element that actually\n // scrolls). When nothing resolves, `root` stays null — the observer then\n // watches the document viewport (body/html), the original behaviour.\n const explicit = this.scrollContainer ? document.querySelector(this.scrollContainer) : null\n const contentRoot = this.for\n ? (document.getElementById(this.for) ?? document.querySelector(this.for))\n : this\n const container = explicit ?? contentRoot?.closest('nord-scroll-area') ?? null\n\n let root: Element | null = null\n if (container) {\n if (container.localName === 'nord-scroll-area') {\n const viewport = container.shadowRoot?.querySelector('[part~=\"viewport\"]')\n if (!viewport) {\n // The scroll-area hasn't upgraded yet; re-run once it has so we\n // observe the real scroller rather than falling back to the window.\n customElements.whenDefined('nord-scroll-area').then(() => {\n if (this.isConnected) {\n this.observeTargets()\n }\n })\n return\n }\n root = viewport\n }\n else {\n root = container\n }\n }\n\n // A heading becomes active as it nears the top of the container. The lower\n // bound keeps the section active while the reader is within it.\n this.observer = new IntersectionObserver(this.handleIntersect, {\n root,\n rootMargin: '0px 0px -66% 0px',\n threshold: 0,\n })\n\n for (const entry of this.entries) {\n const target = entry.id ? document.getElementById(entry.id) : null\n if (target) {\n this.observer.observe(target)\n }\n }\n }\n\n private handleIntersect = (entries: IntersectionObserverEntry[]) => {\n for (const entry of entries) {\n const id = entry.target.id\n if (entry.isIntersecting) {\n this.intersecting.add(id)\n }\n else {\n this.intersecting.delete(id)\n }\n }\n\n // Pick the first heading in document order that's currently in view.\n const next = this.entries.map(e => e.id).find(id => this.intersecting.has(id))\n if (next && next !== this.active) {\n this.setActive(next)\n }\n }\n\n private setActive(id: string) {\n this.active = id\n this.dispatchEvent(new NordOutlineChangeEvent(id))\n }\n\n private applyActiveToItems() {\n for (const entry of this.entries) {\n entry.setActive(entry.id === this.active)\n }\n }\n\n private updateIndicator() {\n const indicator = this.indicatorEl\n const container = this.containerEl\n if (!indicator || !container) {\n return\n }\n\n const active = this.entries.find(entry => entry.id === this.active)\n if (!active) {\n indicator.classList.remove('is-visible')\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const itemRect = active.element.getBoundingClientRect()\n indicator.style.transform = `translateY(${itemRect.top - containerRect.top}px)`\n indicator.style.blockSize = `${itemRect.height}px`\n indicator.classList.add('is-visible')\n }\n\n private handleClick = (event: MouseEvent) => {\n // Honour modifier-clicks (open in new tab, etc.) — let the browser handle them.\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n\n const anchor = event.composedPath().find((node): node is HTMLAnchorElement => node instanceof HTMLAnchorElement)\n const href = anchor?.getAttribute('href')\n if (!href?.startsWith('#')) {\n return\n }\n\n const id = href.slice(1)\n const target = document.getElementById(id)\n if (!target) {\n return\n }\n\n event.preventDefault()\n const reduceMotion = typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches\n target.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' })\n\n if (typeof history !== 'undefined') {\n history.replaceState(null, '', `#${id}`)\n }\n\n // Update immediately for responsiveness, even in controlled mode the click\n // is an explicit user intent so we reflect it and notify.\n this.setActive(id)\n }\n\n private handleSlotChange = () => {\n this.refresh()\n }\n\n private renderHeader() {\n if (this.hideHeader) {\n return nothing\n }\n // A custom header (slot) keeps its own semantics. The default text header is\n // hidden from assistive tech because the host's aria-label already names the\n // navigation landmark with the same term, avoiding a duplicate announcement.\n if (this.headerSlot.hasContent) {\n return html`<div class=\"n-outline-header\" part=\"header\"><slot name=\"header\"></slot></div>`\n }\n return html`<div class=\"n-outline-header\" part=\"header\" aria-hidden=\"true\">${this.localize.term('label')}</div>`\n }\n\n render() {\n return html`\n <div class=\"n-outline\" part=\"base\">\n ${this.renderHeader()}\n <div class=\"n-outline-list\" part=\"list\">\n <span class=\"n-outline-track\" aria-hidden=\"true\"></span>\n <span class=\"n-outline-indicator\" aria-hidden=\"true\"></span>\n ${this.for\n ? this.scanned.map(\n heading => html`\n <a\n class=\"n-outline-item is-generated\"\n data-id=${heading.id}\n href=\"#${heading.id}\"\n level=${heading.level}\n aria-current=${cond(this.active === heading.id, 'location')}\n >${heading.text}</a\n >\n `,\n )\n : html`<slot @slotchange=${this.handleSlotChange}></slot>`}\n </div>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-outline': Outline\n }\n}\n"],"names":["NordOutlineChangeEvent","NordEvent","constructor","activeId","super","Object","defineProperty","this","value","enumerable","writable","Outline","DraftComponentMixin","LitElement","localize","LocalizeController","headerSlot","SlotController","density","headingSelector","hideHeader","scanned","controlled","intersecting","Set","handleIntersect","entries","entry","id","target","isIntersecting","add","delete","next","map","e","find","has","active","setActive","handleClick","event","defaultPrevented","button","metaKey","ctrlKey","shiftKey","altKey","anchor","composedPath","node","HTMLAnchorElement","href","getAttribute","startsWith","slice","document","getElementById","preventDefault","reduceMotion","matchMedia","matches","scrollIntoView","behavior","block","history","replaceState","handleSlotChange","refresh","connectedCallback","hasAttribute","setAttribute","term","addEventListener","disconnectedCallback","removeEventListener","_a","observer","disconnect","_b","resizeObserver","_c","mutationObserver","firstUpdated","isServer","scanContent","ResizeObserver","updateIndicator","observe","MutationObserver","childList","updated","changed","applyActiveToItems","observeTargets","for","renderRoot","querySelectorAll","dataset","element","item","replace","root","querySelector","headings","heading","textContent","trim","toLowerCase","level","Number","tagName","text","Math","min","max","clear","IntersectionObserver","explicit","scrollContainer","contentRoot","container","closest","localName","viewport","_d","shadowRoot","customElements","whenDefined","then","isConnected","rootMargin","threshold","dispatchEvent","indicator","indicatorEl","containerEl","classList","remove","containerRect","getBoundingClientRect","itemRect","style","transform","top","blockSize","height","renderHeader","nothing","hasContent","html","render","cond","styles","componentStyle","__decorate","property","reflect","prototype","attribute","type","Boolean","state","query","customElement"],"mappings":"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"}
package/lib/Pagination.js CHANGED
@@ -1,2 +1,2 @@
1
- import{_ as i}from"./tslib.es6-CmLYFWVC.js";import{css as t,LitElement as o}from"lit";import{property as a,customElement as l}from"lit/decorators.js";import{i as r}from"./light-dom-styles-DXsbiKU9.js";import{D as s}from"./DraftComponentMixin-4qug5Rky.js";import{LocalizeController as n}from"./LocalizeController.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";const e=t`nord-pagination{display:flex;inline-size:100%;justify-content:center;margin-inline:auto}nord-pagination[loading]{opacity:.5;pointer-events:none}`;let p=class extends(s(o)){constructor(){super(...arguments),this.localize=new n(this),this.loading=!1}connectedCallback(){super.connectedCallback(),r(this,e),this.hasAttribute("role")||this.setAttribute("role","navigation"),this.hasAttribute("aria-label")||this.hasAttribute("aria-labelledby")||this.setAttribute("aria-label",this.localize.term("label"))}updated(){this.loading?this.setAttribute("aria-busy","true"):this.removeAttribute("aria-busy")}createRenderRoot(){return this}};i([a({reflect:!0,type:Boolean})],p.prototype,"loading",void 0),p=i([l("nord-pagination")],p);var c=p;export{c as default};
1
+ import{_ as i}from"./tslib.es6-CmLYFWVC.js";import{css as t,LitElement as o}from"lit";import{property as a,customElement as l}from"lit/decorators.js";import{i as r}from"./light-dom-styles-DXsbiKU9.js";import{D as s}from"./DraftComponentMixin-4qug5Rky.js";import{LocalizeController as n}from"./LocalizeController.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";const e=t`nord-pagination{display:flex;inline-size:100%;justify-content:center;margin-inline:auto}nord-pagination[loading]{opacity:.5;pointer-events:none}`;let p=class extends(s(o)){constructor(){super(...arguments),this.localize=new n(this),this.loading=!1}connectedCallback(){super.connectedCallback(),r(this,e),this.hasAttribute("role")||this.setAttribute("role","navigation"),this.hasAttribute("aria-label")||this.hasAttribute("aria-labelledby")||this.setAttribute("aria-label",this.localize.term("label"))}updated(){this.loading?this.setAttribute("aria-busy","true"):this.removeAttribute("aria-busy")}createRenderRoot(){return this}};i([a({reflect:!0,type:Boolean})],p.prototype,"loading",void 0),p=i([l("nord-pagination")],p);var c=p;export{c as default};
2
2
  //# sourceMappingURL=Pagination.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.js","sources":["../src/pagination/Pagination.ts"],"sourcesContent":["import { LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './Pagination.css'\n\n/**\n * Pagination is the navigation root for a paginated collection. It is\n * composition-first: it owns no page state, renders no controls, and emits no\n * events. Your app owns the page state, URL/query syncing, cursors and any data\n * fetching; Nord supplies the semantic/layout primitives, the styling and the\n * `paginate()` math utility for building the page window.\n *\n * As a root it is a `navigation` landmark — it sets `role=\"navigation\"` and a\n * default accessible label so screen-reader users can jump to it. Compose the\n * lower-level primitives inside it:\n *\n * - [Pagination Content](/components/pagination-content/) — the list row.\n * - [Pagination Item](/components/pagination-item/) — a slot in the row.\n * - [Pagination Link](/components/pagination-link/) — a page link (set `current`).\n * - [Pagination Previous](/components/pagination-previous/) — the previous control.\n * - [Pagination Next](/components/pagination-next/) — the next control.\n * - [Pagination Ellipsis](/components/pagination-ellipsis/) — the collapsed-pages marker.\n *\n * Bring your own interactive element — an `<a>` (e.g. a framework `<Link>` /\n * `<NuxtLink>`) or a `nord-button` — and own its `href`, navigation and\n * `disabled` state. See the framework adapters in the docs.\n *\n * @status draft\n * @category navigation\n * @lightDom true\n *\n * @localization label - Accessible label for the pagination navigation landmark.\n *\n * @cssprop [--n-pagination-gap=var(--n-space-xs)] - Controls the spacing between pagination controls.\n *\n * @slot - Default slot for the composed pagination primitives.\n */\n@customElement('nord-pagination')\nexport default class Pagination extends DraftComponentMixin(LitElement) {\n protected localize = new LocalizeController<'nord-pagination'>(this)\n\n /**\n * Dims the pagination and disables interaction while results are loading.\n */\n @property({ reflect: true, type: Boolean }) loading = false\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n\n // As the navigation root, expose a landmark with an accessible name. Only\n // set defaults when the consumer hasn't provided their own semantics.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'navigation')\n }\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n this.setAttribute('aria-label', this.localize.term('label'))\n }\n }\n\n protected updated() {\n // Light DOM with no render(): reflect the loading state onto the host for\n // assistive tech, mirroring the visual dim/disable applied via CSS.\n if (this.loading) {\n this.setAttribute('aria-busy', 'true')\n }\n else {\n this.removeAttribute('aria-busy')\n }\n }\n\n // No render() — the composed primitives are the element's own light-DOM\n // content; we only style them and set the landmark semantics.\n protected createRenderRoot() {\n return this\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-pagination': Pagination\n }\n}\n"],"names":["Pagination","DraftComponentMixin","LitElement","constructor","this","localize","LocalizeController","loading","connectedCallback","super","injectLightDomStyles","style","hasAttribute","setAttribute","term","updated","removeAttribute","createRenderRoot","__decorate","property","reflect","type","Boolean","prototype","customElement"],"mappings":"8nCAyCe,IAAMA,EAAN,cAAyBC,EAAoBC,IAA7C,WAAAC,uBACHC,KAAAC,SAAW,IAAIC,EAAsCF,MAKnBA,KAAOG,SAAG,CAgCvD,CA9BC,iBAAAC,GACEC,MAAMD,oBACNE,EAAqBN,KAAMO,GAItBP,KAAKQ,aAAa,SACrBR,KAAKS,aAAa,OAAQ,cAEvBT,KAAKQ,aAAa,eAAkBR,KAAKQ,aAAa,oBACzDR,KAAKS,aAAa,aAAcT,KAAKC,SAASS,KAAK,SAEtD,CAES,OAAAC,GAGJX,KAAKG,QACPH,KAAKS,aAAa,YAAa,QAG/BT,KAAKY,gBAAgB,YAExB,CAIS,gBAAAC,GACR,OAAOb,IACR,GA/B2Cc,EAAA,CAA3CC,EAAS,CAAEC,SAAS,EAAMC,KAAMC,WAA0BtB,EAAAuB,UAAA,eAAA,GANxCvB,EAAUkB,EAAA,CAD9BM,EAAc,oBACMxB,SAAAA"}
1
+ {"version":3,"file":"Pagination.js","sources":["../src/pagination/Pagination.ts"],"sourcesContent":["import { LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './Pagination.css'\n\n/**\n * Pagination is the navigation root for a paginated collection. It is\n * composition-first: it owns no page state, renders no controls, and emits no\n * events. Your app owns the page state, URL/query syncing, cursors and any data\n * fetching; Nord supplies the semantic/layout primitives, the styling and the\n * `paginate()` math utility for building the page window.\n *\n * As a root it is a `navigation` landmark — it sets `role=\"navigation\"` and a\n * default accessible label so screen-reader users can jump to it. Compose the\n * lower-level primitives inside it:\n *\n * - [Pagination Content](/components/pagination-content/) — the list row.\n * - [Pagination Item](/components/pagination-item/) — a slot in the row.\n * - [Pagination Link](/components/pagination-link/) — a page link (set `current`).\n * - [Pagination Previous](/components/pagination-previous/) — the previous control.\n * - [Pagination Next](/components/pagination-next/) — the next control.\n * - [Pagination Ellipsis](/components/pagination-ellipsis/) — the collapsed-pages marker.\n *\n * Bring your own interactive element — an `<a>` (e.g. a framework `<Link>` /\n * `<NuxtLink>`) or a `nord-button` — and own its `href`, navigation and\n * `disabled` state. See the framework adapters in the docs.\n *\n * @status draft\n * @category navigation\n * @lightDom true\n *\n * @localization label - Accessible label for the pagination navigation landmark.\n *\n * @cssprop [--n-pagination-gap=var(--n-space-xs)] - Controls the spacing between pagination controls.\n *\n * @slot - Default slot for the composed pagination primitives.\n */\n@customElement('nord-pagination')\nexport default class Pagination extends DraftComponentMixin(LitElement) {\n protected localize = new LocalizeController<'nord-pagination'>(this)\n\n /**\n * Dims the pagination and disables interaction while results are loading.\n */\n @property({ reflect: true, type: Boolean }) loading = false\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n\n // As the navigation root, expose a landmark with an accessible name. Only\n // set defaults when the consumer hasn't provided their own semantics.\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'navigation')\n }\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n this.setAttribute('aria-label', this.localize.term('label'))\n }\n }\n\n protected updated() {\n // Light DOM with no render(): reflect the loading state onto the host for\n // assistive tech, mirroring the visual dim/disable applied via CSS.\n if (this.loading) {\n this.setAttribute('aria-busy', 'true')\n }\n else {\n this.removeAttribute('aria-busy')\n }\n }\n\n // No render() — the composed primitives are the element's own light-DOM\n // content; we only style them and set the landmark semantics.\n protected createRenderRoot() {\n return this\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-pagination': Pagination\n }\n}\n"],"names":["Pagination","DraftComponentMixin","LitElement","constructor","this","localize","LocalizeController","loading","connectedCallback","super","injectLightDomStyles","style","hasAttribute","setAttribute","term","updated","removeAttribute","createRenderRoot","__decorate","property","reflect","type","Boolean","prototype","customElement"],"mappings":"0pCAyCe,IAAMA,EAAN,cAAyBC,EAAoBC,IAA7C,WAAAC,uBACHC,KAAAC,SAAW,IAAIC,EAAsCF,MAKnBA,KAAOG,SAAG,CAgCvD,CA9BC,iBAAAC,GACEC,MAAMD,oBACNE,EAAqBN,KAAMO,GAItBP,KAAKQ,aAAa,SACrBR,KAAKS,aAAa,OAAQ,cAEvBT,KAAKQ,aAAa,eAAkBR,KAAKQ,aAAa,oBACzDR,KAAKS,aAAa,aAAcT,KAAKC,SAASS,KAAK,SAEtD,CAES,OAAAC,GAGJX,KAAKG,QACPH,KAAKS,aAAa,YAAa,QAG/BT,KAAKY,gBAAgB,YAExB,CAIS,gBAAAC,GACR,OAAOb,IACR,GA/B2Cc,EAAA,CAA3CC,EAAS,CAAEC,SAAS,EAAMC,KAAMC,WAA0BtB,EAAAuB,UAAA,eAAA,GANxCvB,EAAUkB,EAAA,CAD9BM,EAAc,oBACMxB,SAAAA"}
@@ -0,0 +1,2 @@
1
+ import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{o as e,a as o,s as i,h as s,l as n,f as a,c as r,b as l}from"./positioning-D-K8Mueq.js";import{css as h,html as p,LitElement as d}from"lit";import{property as c,query as m,state as u,customElement as f}from"lit/decorators.js";import{D as g}from"./DirectionController-ChvNGESZ.js";import{E as v}from"./EventController-BBOmvfLa.js";import{L as y}from"./LightDismissController-wcL1ziJa.js";import{S as b}from"./ScrollbarController-BFC67Y2x.js";import{o as w}from"./observe-D0n0zOfU.js";import{N as x,t as E}from"./events-Bv6wNHwJ.js";import{s as A}from"./Component-BJ5O5n8k.js";function k(e){class o extends e{constructor(){super(...arguments),this.open=!1,this.align="start",this.position="block-end",this.sideOffset=8,this.alignOffset=0}}return t([c({type:Boolean,reflect:!0})],o.prototype,"open",void 0),t([c({reflect:!0})],o.prototype,"align",void 0),t([c({reflect:!0})],o.prototype,"position",void 0),t([c({reflect:!0,type:Number,attribute:"side-offset"})],o.prototype,"sideOffset",void 0),t([c({reflect:!0,type:Number,attribute:"align-offset"})],o.prototype,"alignOffset",void 0),o}const C=h`:host{background:none;block-size:auto;border:none;color:var(--n-color-text);inline-size:auto;inset:auto;left:var(--_n-popout-position-x);margin:0;opacity:0;overflow:visible;padding:0;pointer-events:none;position:fixed;top:var(--_n-popout-position-y);transition:opacity var(--n-transition-slowly);z-index:var(--n-index-popout)}.n-popout{background:var(--n-popout-background,var(--n-color-surface));border-radius:var(--n-border-radius-s);box-shadow:var(--n-popout-box-shadow,var(--n-box-shadow-popout));pointer-events:none;transform:translateY(-10px) scale(.97);transform-origin:top left;transition:transform var(--n-transition-slowly),visibility var(--n-transition-slowly);visibility:hidden;will-change:opacity,visibility}:host([open]){opacity:1}:host([open]) .n-popout{pointer-events:auto;transform:none;transition-property:transform;visibility:visible}@media (max-width:35.9375em){:host(:not([always-floating])){background:#0000;inset:0;opacity:1;overflow-y:auto;position:fixed;transition:background var(--n-transition-mobile)}:host([open]:not([always-floating])){background:var(--n-color-overlay);pointer-events:auto}:host([open]:not([always-floating])) .n-popout{transform:translateY(0)}:host(:not([always-floating])) .n-popout{border-radius:0;inset:0;inset-block-start:auto;position:fixed;transform:translateY(100%);transform-origin:bottom center;transition:transform var(--n-transition-mobile),visibility var(--n-transition-mobile)}}.top-end,.top-start{transform:translateY(10px) scale(.97)}.left-end,.left-start{transform:translateX(10px) scale(.97)}.right-end,.right-start{transform:translateX(-10px) scale(.97)}.bottom-start.is-rtl,.left-end,.top-end{transform-origin:bottom right}.bottom-end,.left-start,.top-start.is-rtl{transform-origin:top right}.bottom-end.is-rtl,.right-end,.right-start{transform-origin:bottom left}.right-start,.top-end.is-rtl{transform-origin:top left}`,O="undefined"==typeof matchMedia?{matches:!1,addEventListener(){}}:matchMedia("(max-width: 35.9375em)");let P=class extends(k(d)){constructor(){super(...arguments),this.scrollBar=new b(this),this.dismiss=new y(this,{isOpen:()=>this.open,onDismiss:t=>this.hide("click"!==t.type),isDismissible:t=>t!==this.popout&&t!==this.targetElement}),this.events=new v(this),this.direction=new g(this),this.smallViewport=O.matches,this.id="",this.alwaysFloating=!1,this.controlled=!1,this.enableScroll=()=>{this.open||(this.scrollBar.unlockScroll(),this.leaveTopLayer())},this.updatePosition=async()=>{var t;if(!this.anchorElement)return;const l={strategy:"fixed"};"auto"===this.position?l.middleware=[e({mainAxis:this.sideOffset,alignmentAxis:this.alignOffset}),o({alignment:this.align,padding:8}),i({padding:8}),s()]:(l.placement=n(this.position,this.align,this.direction.dir),l.middleware=[e({mainAxis:this.sideOffset,alignmentAxis:this.alignOffset}),a(),i({padding:8}),s()]);const{x:h,y:p,placement:d,middlewareData:c}=await r(this.anchorElement,this,l);this.computedPosition=d,this.style.setProperty("--_n-popout-position-x",`${h}px`),this.style.setProperty("--_n-popout-position-y",`${p}px`),(null===(t=c.hide)||void 0===t?void 0:t.referenceHidden)&&this.hide()},this.toggleOpen=t=>{t.preventDefault(),this.open?this.hide(!1):!this.smallViewport||this.alwaysFloating?(this.enterTopLayer(),this.updatePosition().then((()=>this.show()))):this.show()},this.handleMediaQueryChange=()=>{var t;this.smallViewport=O.matches,null===(t=this.cleanupAutoUpdate)||void 0===t||t.call(this),(!this.smallViewport||this.alwaysFloating)&&this.open&&this.anchorElement?(this.cleanupAutoUpdate=l(this.anchorElement,this,this.updatePosition),this.scrollBar.unlockScroll()):this.open&&this.scrollBar.lockScroll()}}async show(){return this.open?Promise.resolve():(this.enterTopLayer(),this.open=!0,await this.updateComplete,this.dispatchEvent(new x("open")),E(this.popout))}async hide(t=!0){var e,o;if(!this.open)return Promise.resolve();this.open=!1,null===(e=this.cleanupAutoUpdate)||void 0===e||e.call(this),this.dispatchEvent(new x("close")),t&&(null===(o=this.targetElement)||void 0===o||o.focus({preventScroll:!0}));const i=await E(this.popout);return this.leaveTopLayer(),i}firstUpdated(){this.smallViewport&&!this.alwaysFloating||this.updatePosition()}connectedCallback(){super.connectedCallback(),this.events.listen(O,"change",this.handleMediaQueryChange),this.initializeElements()}disconnectedCallback(){var t,e;super.disconnectedCallback(),null===(t=this.cleanupAutoUpdate)||void 0===t||t.call(this),null===(e=this.targetElement)||void 0===e||e.removeAttribute("aria-expanded")}render(){return p`<div class="n-popout ${this.computedPosition} is-${this.direction.dir}" aria-hidden="${this.open?"false":"true"}" @transitionend="${this.enableScroll}"><slot></slot></div>`}handleIdChange(){var t;null===(t=this.targetElement)||void 0===t||t.removeEventListener("click",this.toggleOpen),this.id?this.initializeElements():console.warn("NORD: popout requires an id attribute and value")}initializeElements(){this.targetElement=this.getToggle(),this.anchorElement=this.getAnchor(),this.controlled||this.events.listen(this.targetElement,"click",this.toggleOpen)}handleOpenChange(){var t,e;null===(t=this.targetElement)||void 0===t||t.setAttribute("aria-expanded",`${this.open}`),this.open?(this.enterTopLayer(),this.smallViewport&&!this.alwaysFloating?this.scrollBar.lockScroll():this.anchorElement&&(this.cleanupAutoUpdate=l(this.anchorElement,this,this.updatePosition))):null===(e=this.cleanupAutoUpdate)||void 0===e||e.call(this)}handleAnchorChange(){var t;null===(t=this.cleanupAutoUpdate)||void 0===t||t.call(this),this.anchorElement=this.getAnchor(),this.open&&(!this.smallViewport||this.alwaysFloating)&&this.anchorElement&&(this.cleanupAutoUpdate=l(this.anchorElement,this,this.updatePosition))}enterTopLayer(){if("function"==typeof this.showPopover)try{this.setAttribute("popover","manual"),this.showPopover()}catch(t){this.removeAttribute("popover")}}leaveTopLayer(){this.removeAttribute("popover")}getToggle(){const t=this.getRootNode(),e=t.querySelectorAll(`[aria-controls='${this.id}']`);let o=e[0];if(e.length>1){const i=[...t.querySelectorAll(`[id='${this.id}']`)].indexOf(this);i>=0&&i<e.length&&(o=e[i])}return o instanceof HTMLSlotElement?o.assignedElements()[0]:o}getAnchor(){if(!this.anchor)return this.targetElement;const t=this.getRootNode().querySelector(`#${this.anchor}`);return t instanceof HTMLSlotElement?t.assignedElements()[0]:t}};P.styles=[A,C],t([m(".n-popout",!0)],P.prototype,"popout",void 0),t([u()],P.prototype,"computedPosition",void 0),t([u()],P.prototype,"smallViewport",void 0),t([c({reflect:!0})],P.prototype,"id",void 0),t([c({reflect:!0})],P.prototype,"anchor",void 0),t([c({reflect:!0,type:Boolean,attribute:"always-floating"})],P.prototype,"alwaysFloating",void 0),t([c({reflect:!0,type:Boolean})],P.prototype,"controlled",void 0),t([w("id")],P.prototype,"handleIdChange",null),t([w("open")],P.prototype,"handleOpenChange",null),t([w("anchor")],P.prototype,"handleAnchorChange",null),P=t([f("nord-popout")],P);var S=P;export{k as F,S as P};
2
+ //# sourceMappingURL=Popout-B6Hirj3y.js.map