@f-ewald/components 1.0.0 → 1.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 (172) hide show
  1. package/README.md +6 -0
  2. package/custom-elements.json +891 -22
  3. package/dist/address-autocomplete.d.ts +8 -0
  4. package/dist/address-autocomplete.d.ts.map +1 -1
  5. package/dist/address-autocomplete.js +165 -15
  6. package/dist/address-autocomplete.js.map +1 -1
  7. package/dist/animate-confetti.d.ts +8 -5
  8. package/dist/animate-confetti.d.ts.map +1 -1
  9. package/dist/animate-confetti.js +46 -19
  10. package/dist/animate-confetti.js.map +1 -1
  11. package/dist/autocomplete-input.d.ts +8 -0
  12. package/dist/autocomplete-input.d.ts.map +1 -1
  13. package/dist/autocomplete-input.js +165 -15
  14. package/dist/autocomplete-input.js.map +1 -1
  15. package/dist/calendar-month.d.ts.map +1 -1
  16. package/dist/calendar-month.js +27 -13
  17. package/dist/calendar-month.js.map +1 -1
  18. package/dist/calendar-year.d.ts.map +1 -1
  19. package/dist/calendar-year.js +11 -2
  20. package/dist/calendar-year.js.map +1 -1
  21. package/dist/chat-message.d.ts.map +1 -1
  22. package/dist/chat-message.js +77 -24
  23. package/dist/chat-message.js.map +1 -1
  24. package/dist/confirm-dialog.d.ts +8 -1
  25. package/dist/confirm-dialog.d.ts.map +1 -1
  26. package/dist/confirm-dialog.js +130 -18
  27. package/dist/confirm-dialog.js.map +1 -1
  28. package/dist/copy-link-button.d.ts +2 -0
  29. package/dist/copy-link-button.d.ts.map +1 -1
  30. package/dist/copy-link-button.js +35 -3
  31. package/dist/copy-link-button.js.map +1 -1
  32. package/dist/data-table.d.ts +2 -0
  33. package/dist/data-table.d.ts.map +1 -1
  34. package/dist/data-table.js +83 -11
  35. package/dist/data-table.js.map +1 -1
  36. package/dist/distance-value.d.ts +0 -1
  37. package/dist/distance-value.d.ts.map +1 -1
  38. package/dist/distance-value.js +3 -8
  39. package/dist/distance-value.js.map +1 -1
  40. package/dist/distribution-chart.d.ts.map +1 -1
  41. package/dist/distribution-chart.js +54 -17
  42. package/dist/distribution-chart.js.map +1 -1
  43. package/dist/dropdown-button.d.ts.map +1 -1
  44. package/dist/dropdown-button.js +60 -11
  45. package/dist/dropdown-button.js.map +1 -1
  46. package/dist/editable-text.d.ts.map +1 -1
  47. package/dist/editable-text.js +46 -13
  48. package/dist/editable-text.js.map +1 -1
  49. package/dist/form-select.d.ts.map +1 -1
  50. package/dist/form-select.js +70 -22
  51. package/dist/form-select.js.map +1 -1
  52. package/dist/frame-box.d.ts.map +1 -1
  53. package/dist/frame-box.js +20 -12
  54. package/dist/frame-box.js.map +1 -1
  55. package/dist/icon-button.d.ts.map +1 -1
  56. package/dist/icon-button.js +11 -0
  57. package/dist/icon-button.js.map +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/kbd-hint.d.ts +30 -0
  63. package/dist/kbd-hint.d.ts.map +1 -0
  64. package/dist/kbd-hint.js +184 -0
  65. package/dist/kbd-hint.js.map +1 -0
  66. package/dist/live-timer.d.ts +0 -1
  67. package/dist/live-timer.d.ts.map +1 -1
  68. package/dist/live-timer.js +1 -6
  69. package/dist/live-timer.js.map +1 -1
  70. package/dist/map-circle.d.ts.map +1 -1
  71. package/dist/map-circle.js +16 -1
  72. package/dist/map-circle.js.map +1 -1
  73. package/dist/map-pin.d.ts.map +1 -1
  74. package/dist/map-pin.js +16 -1
  75. package/dist/map-pin.js.map +1 -1
  76. package/dist/percent-bar-chart.d.ts +3 -0
  77. package/dist/percent-bar-chart.d.ts.map +1 -1
  78. package/dist/percent-bar-chart.js +60 -4
  79. package/dist/percent-bar-chart.js.map +1 -1
  80. package/dist/photo-gallery.d.ts.map +1 -1
  81. package/dist/photo-gallery.js +12 -3
  82. package/dist/photo-gallery.js.map +1 -1
  83. package/dist/popover-panel.d.ts.map +1 -1
  84. package/dist/popover-panel.js +132 -23
  85. package/dist/popover-panel.js.map +1 -1
  86. package/dist/price-history-chart.d.ts.map +1 -1
  87. package/dist/price-history-chart.js +52 -18
  88. package/dist/price-history-chart.js.map +1 -1
  89. package/dist/radio-cards.d.ts +2 -0
  90. package/dist/radio-cards.d.ts.map +1 -1
  91. package/dist/radio-cards.js +51 -5
  92. package/dist/radio-cards.js.map +1 -1
  93. package/dist/radio-pills.d.ts +2 -0
  94. package/dist/radio-pills.d.ts.map +1 -1
  95. package/dist/radio-pills.js +46 -4
  96. package/dist/radio-pills.js.map +1 -1
  97. package/dist/relative-time.d.ts +0 -1
  98. package/dist/relative-time.d.ts.map +1 -1
  99. package/dist/relative-time.js +1 -6
  100. package/dist/relative-time.js.map +1 -1
  101. package/dist/reveal-button.d.ts +2 -0
  102. package/dist/reveal-button.d.ts.map +1 -1
  103. package/dist/reveal-button.js +42 -5
  104. package/dist/reveal-button.js.map +1 -1
  105. package/dist/roman-numeral.js +1 -1
  106. package/dist/roman-numeral.js.map +1 -1
  107. package/dist/slide-panel.d.ts +7 -3
  108. package/dist/slide-panel.d.ts.map +1 -1
  109. package/dist/slide-panel.js +95 -23
  110. package/dist/slide-panel.js.map +1 -1
  111. package/dist/stat-meter.d.ts.map +1 -1
  112. package/dist/stat-meter.js +17 -7
  113. package/dist/stat-meter.js.map +1 -1
  114. package/dist/status-pill.d.ts.map +1 -1
  115. package/dist/status-pill.js +26 -12
  116. package/dist/status-pill.js.map +1 -1
  117. package/dist/tile-grid.d.ts +8 -0
  118. package/dist/tile-grid.d.ts.map +1 -1
  119. package/dist/tile-grid.js +88 -12
  120. package/dist/tile-grid.js.map +1 -1
  121. package/dist/toast-notification.d.ts.map +1 -1
  122. package/dist/toast-notification.js +40 -11
  123. package/dist/toast-notification.js.map +1 -1
  124. package/dist/tokens.css +19 -0
  125. package/dist/tokens.d.ts.map +1 -1
  126. package/dist/tokens.js +13 -0
  127. package/dist/tokens.js.map +1 -1
  128. package/dist/ui-button.d.ts +2 -0
  129. package/dist/ui-button.d.ts.map +1 -1
  130. package/dist/ui-button.js +58 -9
  131. package/dist/ui-button.js.map +1 -1
  132. package/dist/user-avatar.d.ts.map +1 -1
  133. package/dist/user-avatar.js +18 -3
  134. package/dist/user-avatar.js.map +1 -1
  135. package/dist/utils/form.d.ts +3 -0
  136. package/dist/utils/form.d.ts.map +1 -0
  137. package/dist/utils/form.js +14 -0
  138. package/dist/utils/form.js.map +1 -0
  139. package/dist/utils/layer-stack.d.ts +9 -0
  140. package/dist/utils/layer-stack.d.ts.map +1 -0
  141. package/dist/utils/layer-stack.js +35 -0
  142. package/dist/utils/layer-stack.js.map +1 -0
  143. package/dist/weight-bar-chart.d.ts.map +1 -1
  144. package/dist/weight-bar-chart.js +27 -8
  145. package/dist/weight-bar-chart.js.map +1 -1
  146. package/docs/address-autocomplete.md +5 -0
  147. package/docs/autocomplete-input.md +5 -0
  148. package/docs/calendar-month.md +2 -0
  149. package/docs/chat-message.md +4 -0
  150. package/docs/confirm-dialog.md +2 -0
  151. package/docs/copy-link-button.md +2 -0
  152. package/docs/data-table.md +2 -0
  153. package/docs/design-language.md +149 -0
  154. package/docs/distribution-chart.md +4 -0
  155. package/docs/dropdown-button.md +1 -0
  156. package/docs/frame-box.md +2 -0
  157. package/docs/kbd-hint.md +42 -0
  158. package/docs/percent-bar-chart.md +4 -1
  159. package/docs/photo-gallery.md +1 -0
  160. package/docs/popover-panel.md +2 -0
  161. package/docs/price-history-chart.md +8 -1
  162. package/docs/radio-cards.md +2 -0
  163. package/docs/radio-pills.md +2 -0
  164. package/docs/reveal-button.md +3 -0
  165. package/docs/slide-panel.md +4 -2
  166. package/docs/status-pill.md +3 -0
  167. package/docs/tile-grid.md +10 -1
  168. package/docs/toast-notification.md +4 -1
  169. package/docs/ui-button.md +2 -0
  170. package/docs/user-avatar.md +1 -0
  171. package/llms.txt +59 -34
  172. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"editable-text.js","sourceRoot":"","sources":["../src/editable-text.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property, query, state } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Jira/GitHub-style click-to-edit text: a display span that turns into an\n * `<input>` (or auto-growing `<textarea>` when `multiline`) on click. The\n * input/textarea inherits the host's font, so a title wrapped in an `<h1>`\n * edits at title size.\n *\n * @element editable-text\n * @fires change - Fired with `{ value: string }` when the committed value differs from the previous one.\n */\n@customElement(\"editable-text\")\nexport class EditableText extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: inherit;\n font-size: inherit;\n font-weight: inherit;\n line-height: inherit;\n }\n .display {\n cursor: text;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.1rem 0.3rem;\n margin: -0.1rem -0.3rem;\n }\n .display.multiline {\n white-space: pre-wrap;\n }\n .display:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .display.empty {\n color: var(--ui-text-muted, #64748b);\n }\n .display.readonly {\n cursor: inherit;\n }\n .display.readonly:hover {\n background: none;\n }\n input,\n textarea {\n display: block;\n width: 100%;\n box-sizing: border-box;\n font: inherit;\n color: inherit;\n background: var(--ui-surface, #fff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.1rem 0.3rem;\n margin: -0.1rem -0.3rem;\n outline: none;\n }\n input:focus,\n textarea:focus {\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n textarea {\n resize: none;\n overflow: hidden;\n }\n `,\n ];\n\n /** Current text. */\n @property() value = \"\";\n /** `false` renders an `<input>`, `true` an auto-growing `<textarea>`. */\n @property({ type: Boolean }) multiline = false;\n /** Muted placeholder text shown when `value` is empty, and as the input's placeholder. */\n @property() placeholder = \"\";\n /** Disables entering edit mode. */\n @property({ type: Boolean }) readonly = false;\n /** `aria-label` applied to the input/textarea. */\n @property() label = \"\";\n\n @state() private _editing = false;\n @state() private _draft = \"\";\n\n @query(\"input, textarea\") private _field?: HTMLInputElement | HTMLTextAreaElement;\n\n /** Enters edit mode, seeding the draft from the current value. */\n private _startEdit() {\n if (this.readonly) return;\n this._draft = this.value;\n this._editing = true;\n }\n\n /** Commits the draft (reverting an empty single-line commit) and exits edit mode.\n *\n * Guarded on `_editing`: removing the focused input/textarea from the DOM\n * (which happens as soon as `_editing` flips to false) makes the browser\n * fire a native `blur` on it, re-invoking this handler a second time after\n * a cancel already ran — the guard makes that second call a no-op instead\n * of re-committing the stale draft.\n */\n private _commit() {\n if (!this._editing) return;\n const next = this._draft;\n this._editing = false;\n if (!this.multiline && next.trim() === \"\") return;\n if (next === this.value) return;\n this.value = next;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value: next } }));\n }\n\n /** Discards the draft and exits edit mode without committing. */\n private _cancel() {\n this._editing = false;\n }\n\n private _onInput(e: Event) {\n this._draft = (e.target as HTMLInputElement | HTMLTextAreaElement).value;\n if (this.multiline) this._resize();\n }\n\n private _onSingleLineKeydown(e: KeyboardEvent) {\n if (e.key === \"Enter\") {\n e.preventDefault();\n this._commit();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n this._cancel();\n }\n }\n\n private _onMultilineKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n this._cancel();\n } else if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n this._commit();\n }\n }\n\n /** Grows the textarea's height to fit its content. */\n private _resize() {\n const field = this._field;\n if (!field) return;\n field.style.height = \"auto\";\n field.style.height = `${field.scrollHeight}px`;\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has(\"_editing\") && this._editing) {\n const field = this._field;\n if (!field) return;\n field.focus();\n const end = field.value.length;\n field.setSelectionRange(end, end);\n if (this.multiline) this._resize();\n }\n }\n\n override render() {\n if (this._editing) {\n return this.multiline\n ? html`<textarea\n rows=\"3\"\n .value=${this._draft}\n placeholder=${this.placeholder}\n aria-label=${this.label || nothing}\n @input=${this._onInput}\n @keydown=${this._onMultilineKeydown}\n @blur=${this._commit}\n ></textarea>`\n : html`<input\n type=\"text\"\n .value=${this._draft}\n placeholder=${this.placeholder}\n aria-label=${this.label || nothing}\n @input=${this._onInput}\n @keydown=${this._onSingleLineKeydown}\n @blur=${this._commit}\n />`;\n }\n\n const isEmpty = this.value.trim() === \"\";\n const classes = `display ${this.multiline ? \"multiline\" : \"\"} ${isEmpty ? \"empty\" : \"\"} ${this.readonly ? \"readonly\" : \"\"}`;\n return html`<span class=${classes} @click=${this._startEdit}\n >${isEmpty ? this.placeholder : this.value}</span\n >`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"editable-text\": EditableText;\n }\n}\n"]}
1
+ {"version":3,"file":"editable-text.js","sourceRoot":"","sources":["../src/editable-text.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property, query, state } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Jira/GitHub-style click-to-edit text: a display span that turns into an\n * `<input>` (or auto-growing `<textarea>` when `multiline`) on click. The\n * input/textarea inherits the host's font, so a title wrapped in an `<h1>`\n * edits at title size.\n *\n * @element editable-text\n * @fires change - Fired with `{ value: string }` when the committed value differs from the previous one.\n */\n@customElement(\"editable-text\")\nexport class EditableText extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: inherit;\n font-size: inherit;\n font-weight: inherit;\n line-height: inherit;\n }\n .display {\n display: block;\n width: 100%;\n box-sizing: border-box;\n border: 0;\n color: inherit;\n background: transparent;\n font: inherit;\n line-height: inherit;\n text-align: inherit;\n cursor: text;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.25rem;\n margin: -0.25rem;\n }\n .display.multiline {\n /* Inactive multiline text is flush; the active textarea keeps its editor inset. */\n white-space: pre-wrap;\n padding: 0;\n margin: 0;\n }\n .display:hover:not(:disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .display.empty {\n color: var(--ui-text-muted, #64748b);\n }\n .display:disabled {\n cursor: inherit;\n opacity: 0.6;\n }\n .display:disabled:hover {\n background: none;\n }\n .display:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n input,\n textarea {\n display: block;\n width: 100%;\n box-sizing: border-box;\n font: inherit;\n color: inherit;\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.25rem;\n margin: -0.25rem;\n outline: none;\n }\n input:focus-visible,\n textarea:focus-visible {\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n textarea {\n resize: none;\n overflow: hidden;\n }\n @media (forced-colors: active) {\n .display:focus-visible,\n input:focus-visible,\n textarea:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n .display:disabled {\n color: GrayText;\n opacity: 1;\n }\n }\n `,\n ];\n\n /** Current text. */\n @property() value = \"\";\n /** `false` renders an `<input>`, `true` an auto-growing `<textarea>`. */\n @property({ type: Boolean }) multiline = false;\n /** Muted placeholder text shown when `value` is empty, and as the input's placeholder. */\n @property() placeholder = \"\";\n /** Disables entering edit mode. */\n @property({ type: Boolean }) readonly = false;\n /** `aria-label` applied to the input/textarea. */\n @property() label = \"\";\n\n @state() private _editing = false;\n @state() private _draft = \"\";\n\n @query(\"input, textarea\") private _field?: HTMLInputElement | HTMLTextAreaElement;\n\n /** Enters edit mode, seeding the draft from the current value. */\n private _startEdit() {\n if (this.readonly) return;\n this._draft = this.value;\n this._editing = true;\n }\n\n /** Commits the draft (reverting an empty single-line commit) and exits edit mode.\n *\n * Guarded on `_editing`: removing the focused input/textarea from the DOM\n * (which happens as soon as `_editing` flips to false) makes the browser\n * fire a native `blur` on it, re-invoking this handler a second time after\n * a cancel already ran — the guard makes that second call a no-op instead\n * of re-committing the stale draft.\n */\n private _commit() {\n if (!this._editing) return;\n const next = this._draft;\n this._editing = false;\n if (!this.multiline && next.trim() === \"\") return;\n if (next === this.value) return;\n this.value = next;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value: next } }));\n }\n\n /** Discards the draft and exits edit mode without committing. */\n private _cancel() {\n this._editing = false;\n }\n\n private _onInput(e: Event) {\n this._draft = (e.target as HTMLInputElement | HTMLTextAreaElement).value;\n if (this.multiline) this._resize();\n }\n\n private _onSingleLineKeydown(e: KeyboardEvent) {\n if (e.key === \"Enter\") {\n e.preventDefault();\n this._commit();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n this._cancel();\n }\n }\n\n private _onMultilineKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n this._cancel();\n } else if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n this._commit();\n }\n }\n\n /** Grows the textarea's height to fit its content. */\n private _resize() {\n const field = this._field;\n if (!field) return;\n field.style.height = \"auto\";\n field.style.height = `${field.scrollHeight}px`;\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has(\"_editing\") && this._editing) {\n const field = this._field;\n if (!field) return;\n field.focus();\n const end = field.value.length;\n field.setSelectionRange(end, end);\n if (this.multiline) this._resize();\n }\n }\n\n override render() {\n if (this._editing) {\n return this.multiline\n ? html`<textarea\n rows=\"3\"\n .value=${this._draft}\n placeholder=${this.placeholder}\n aria-label=${this.label || nothing}\n @input=${this._onInput}\n @keydown=${this._onMultilineKeydown}\n @blur=${this._commit}\n ></textarea>`\n : html`<input\n type=\"text\"\n .value=${this._draft}\n placeholder=${this.placeholder}\n aria-label=${this.label || nothing}\n @input=${this._onInput}\n @keydown=${this._onSingleLineKeydown}\n @blur=${this._commit}\n />`;\n }\n\n const isEmpty = this.value.trim() === \"\";\n const classes = `display ${this.multiline ? \"multiline\" : \"\"} ${isEmpty ? \"empty\" : \"\"} ${this.readonly ? \"readonly\" : \"\"}`;\n return html`<button\n type=\"button\"\n class=${classes}\n ?disabled=${this.readonly}\n @click=${this._startEdit}\n >${isEmpty ? this.placeholder : this.value}</button>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"editable-text\": EditableText;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"form-select.d.ts","sourceRoot":"","sources":["../src/form-select.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAKb,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,4BAuKpB;IAEF,2CAA2C;IACX,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7D,qEAAqE;IACzD,KAAK,SAAM;IACvB,kDAAkD;IACtC,KAAK,SAAM;IACvB,iEAAiE;IACpC,QAAQ,UAAS;IAC9C;;;OAGG;IACyC,UAAU,UAAS;IAEtD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,MAAM,CAAuB;IAWrC,oBAAoB,IAAI,IAAI,CAWpC;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CA2BxD;IAkPD,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,mBAAmB;IA2C3B,OAAO,CAAC,mBAAmB;IAoBlB,MAAM,sBAQd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
1
+ {"version":3,"file":"form-select.d.ts","sourceRoot":"","sources":["../src/form-select.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAOb,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,4BA8MpB;IAEF,2CAA2C;IACX,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7D,qEAAqE;IACzD,KAAK,SAAM;IACvB,kDAAkD;IACtC,KAAK,SAAM;IACvB,iEAAiE;IACpC,QAAQ,UAAS;IAC9C;;;OAGG;IACyC,UAAU,UAAS;IAEtD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,MAAM,CAAuB;IAYrC,oBAAoB,IAAI,IAAI,CAWpC;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CA2BxD;IAkPD,OAAO,CAAC,aAAa;IA+BrB,OAAO,CAAC,mBAAmB;IA2C3B,OAAO,CAAC,mBAAmB;IA0BlB,MAAM,sBAQd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
@@ -8,6 +8,7 @@ import { LitElement, css, html, nothing, } from "lit";
8
8
  import { customElement, property, state } from "lit/decorators.js";
9
9
  import { iconChevronRight } from "./icons.js";
10
10
  import { tokens } from "./tokens.js";
11
+ let instanceCount = 0;
11
12
  /**
12
13
  * A styled dropdown select: a trigger button showing the current option's
13
14
  * label, opening a listbox popover on click. Drop-in generic replacement for
@@ -58,6 +59,7 @@ let FormSelect = class FormSelect extends LitElement {
58
59
  this.#compositionJustEnded = false;
59
60
  this.#compositionEndTimer = null;
60
61
  this.#blurTimer = null;
62
+ this.#listboxId = `form-select-listbox-${++instanceCount}`;
61
63
  this.#onWindowMousedown = (e) => {
62
64
  if (!e.composedPath().includes(this))
63
65
  this.#close();
@@ -69,25 +71,34 @@ let FormSelect = class FormSelect extends LitElement {
69
71
  :host {
70
72
  display: inline-block;
71
73
  position: relative;
72
- font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
74
+ font-family: var(
75
+ --ui-font,
76
+ ui-sans-serif,
77
+ system-ui,
78
+ sans-serif,
79
+ "Apple Color Emoji",
80
+ "Segoe UI Emoji",
81
+ "Segoe UI Symbol",
82
+ "Noto Color Emoji"
83
+ );
73
84
  font-size: var(--ui-font-size-sm, 0.75rem);
74
85
  }
75
86
  button.trigger {
76
87
  display: flex;
77
88
  align-items: center;
78
89
  justify-content: space-between;
79
- gap: 0.35rem;
90
+ gap: 0.25rem;
80
91
  width: 100%;
81
92
  box-sizing: border-box;
82
93
  font: inherit;
83
94
  color: var(--ui-text, #0f172a);
84
- background: var(--ui-surface, #fff);
95
+ background: var(--ui-surface, #ffffff);
85
96
  border: 1px solid var(--ui-border, #e2e8f0);
86
97
  border-radius: var(--ui-radius-sm, 0.25rem);
87
- padding: 0.3rem 0.5rem;
98
+ padding: 0.25rem 0.5rem;
88
99
  cursor: pointer;
89
100
  }
90
- button.trigger:hover {
101
+ button.trigger:hover:not(:disabled) {
91
102
  background: var(--ui-surface-muted, #f8fafc);
92
103
  }
93
104
  button.trigger:disabled {
@@ -103,11 +114,11 @@ let FormSelect = class FormSelect extends LitElement {
103
114
  display: flex;
104
115
  align-items: center;
105
116
  justify-content: space-between;
106
- gap: 0.35rem;
117
+ gap: 0.25rem;
107
118
  width: 100%;
108
119
  box-sizing: border-box;
109
120
  color: var(--ui-text, #0f172a);
110
- background: var(--ui-surface, #fff);
121
+ background: var(--ui-surface, #ffffff);
111
122
  border: 1px solid var(--ui-border, #e2e8f0);
112
123
  border-radius: var(--ui-radius-sm, 0.25rem);
113
124
  cursor: text;
@@ -115,7 +126,7 @@ let FormSelect = class FormSelect extends LitElement {
115
126
  .search-trigger:hover:not(.disabled) {
116
127
  background: var(--ui-surface-muted, #f8fafc);
117
128
  }
118
- .search-trigger:focus-within {
129
+ .search-trigger:not(.disabled):focus-within {
119
130
  border-color: var(--ui-primary, #4f46e5);
120
131
  box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
121
132
  }
@@ -130,7 +141,7 @@ let FormSelect = class FormSelect extends LitElement {
130
141
  min-width: 0;
131
142
  flex: 1;
132
143
  box-sizing: border-box;
133
- padding: 0.3rem 0 0.3rem 0.5rem;
144
+ padding: 0.25rem 0 0.25rem 0.5rem;
134
145
  color: inherit;
135
146
  background: transparent;
136
147
  border: 0;
@@ -144,7 +155,7 @@ let FormSelect = class FormSelect extends LitElement {
144
155
  color: var(--ui-text-muted, #64748b);
145
156
  pointer-events: none;
146
157
  transform: rotate(90deg);
147
- transition: transform 0.1s ease;
158
+ transition: transform 150ms ease;
148
159
  }
149
160
  button.trigger .chevron {
150
161
  margin-right: 0;
@@ -161,12 +172,12 @@ let FormSelect = class FormSelect extends LitElement {
161
172
  max-height: 40vh;
162
173
  overflow-y: auto;
163
174
  scrollbar-gutter: stable;
164
- margin: 2px 0 0;
165
- padding: 4px 0;
175
+ margin: 0.25rem 0 0;
176
+ padding: 0.25rem 0;
166
177
  list-style: none;
167
178
  white-space: nowrap;
168
179
  color: var(--ui-text, #0f172a);
169
- background: var(--ui-surface, #fff);
180
+ background: var(--ui-surface, #ffffff);
170
181
  border: 1px solid var(--ui-border, #e2e8f0);
171
182
  border-radius: var(--ui-radius-sm, 0.25rem);
172
183
  box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));
@@ -176,12 +187,12 @@ let FormSelect = class FormSelect extends LitElement {
176
187
  }
177
188
  ul.options::-webkit-scrollbar-thumb {
178
189
  background: var(--ui-border, #e2e8f0);
179
- border: 0.2rem solid transparent;
190
+ border: 0.25rem solid transparent;
180
191
  border-radius: 999px;
181
192
  background-clip: padding-box;
182
193
  }
183
194
  li {
184
- padding: 0.35rem 0.6rem;
195
+ padding: 0.5rem;
185
196
  cursor: pointer;
186
197
  }
187
198
  li.active,
@@ -196,7 +207,7 @@ let FormSelect = class FormSelect extends LitElement {
196
207
  display: inline-flex;
197
208
  min-width: 0;
198
209
  align-items: center;
199
- gap: 0.4rem;
210
+ gap: 0.5rem;
200
211
  }
201
212
  li .option-content {
202
213
  display: flex;
@@ -224,11 +235,41 @@ let FormSelect = class FormSelect extends LitElement {
224
235
  white-space: nowrap;
225
236
  }
226
237
  li.no-options {
227
- padding: 0.35rem 0.6rem;
238
+ padding: 0.5rem;
228
239
  color: var(--ui-text-muted, #64748b);
229
240
  cursor: default;
230
241
  font-style: italic;
231
242
  }
243
+ @media (prefers-reduced-motion: reduce) {
244
+ .chevron {
245
+ transition: none;
246
+ }
247
+ }
248
+ @media (forced-colors: active) {
249
+ button.trigger:focus-visible,
250
+ .search-trigger:not(.disabled):focus-within {
251
+ outline: 2px solid CanvasText;
252
+ outline-offset: 2px;
253
+ box-shadow: none;
254
+ }
255
+ button.trigger:disabled,
256
+ .search-trigger.disabled {
257
+ color: GrayText;
258
+ opacity: 1;
259
+ }
260
+ li.active,
261
+ li:hover {
262
+ color: HighlightText;
263
+ background: Highlight;
264
+ }
265
+ li[aria-selected="true"] {
266
+ color: Highlight;
267
+ }
268
+ li.active[aria-selected="true"],
269
+ li[aria-selected="true"]:hover {
270
+ color: HighlightText;
271
+ }
272
+ }
232
273
  `,
233
274
  ]; }
234
275
  #listboxPointerDown;
@@ -239,6 +280,7 @@ let FormSelect = class FormSelect extends LitElement {
239
280
  #compositionJustEnded;
240
281
  #compositionEndTimer;
241
282
  #blurTimer;
283
+ #listboxId;
242
284
  disconnectedCallback() {
243
285
  super.disconnectedCallback();
244
286
  window.removeEventListener("mousedown", this.#onWindowMousedown, true);
@@ -277,7 +319,7 @@ let FormSelect = class FormSelect extends LitElement {
277
319
  this._open &&
278
320
  this._activeIndex >= 0) {
279
321
  this.renderRoot
280
- .querySelector(`#form-select-option-${this._activeIndex}`)
322
+ .querySelector(`#${this.#listboxId}-option-${this._activeIndex}`)
281
323
  ?.scrollIntoView({ block: "nearest", inline: "nearest" });
282
324
  }
283
325
  }
@@ -526,14 +568,15 @@ let FormSelect = class FormSelect extends LitElement {
526
568
  const options = this.#visibleOptions();
527
569
  return html `
528
570
  <ul
529
- id="form-select-listbox"
571
+ id=${this.#listboxId}
530
572
  class="options"
531
573
  role="listbox"
574
+ aria-label=${this.label ? `${this.label} options` : "Options"}
532
575
  @mousedown=${(e) => this.#onListboxMousedown(e)}
533
576
  >
534
577
  ${options.map((o, i) => html `
535
578
  <li
536
- id=${`form-select-option-${i}`}
579
+ id=${`${this.#listboxId}-option-${i}`}
537
580
  role="option"
538
581
  aria-selected=${o.value === this.value}
539
582
  class=${i === this._activeIndex ? "active" : ""}
@@ -552,7 +595,7 @@ let FormSelect = class FormSelect extends LitElement {
552
595
  const displayValue = this._query ?? current?.label ?? this.value;
553
596
  const showSelectedIcon = this._query === null && Boolean(current?.icon);
554
597
  const activeDescendant = this._open && this._activeIndex >= 0
555
- ? `form-select-option-${this._activeIndex}`
598
+ ? `${this.#listboxId}-option-${this._activeIndex}`
556
599
  : nothing;
557
600
  return html `
558
601
  <div
@@ -570,7 +613,7 @@ let FormSelect = class FormSelect extends LitElement {
570
613
  role="combobox"
571
614
  aria-autocomplete="list"
572
615
  aria-expanded=${this._open}
573
- aria-controls="form-select-listbox"
616
+ aria-controls=${this.#listboxId}
574
617
  aria-activedescendant=${activeDescendant}
575
618
  aria-label=${this.label || "Select an option"}
576
619
  autocomplete="off"
@@ -590,12 +633,17 @@ let FormSelect = class FormSelect extends LitElement {
590
633
  `;
591
634
  }
592
635
  renderButtonTrigger(current) {
636
+ const activeDescendant = this._open && this._activeIndex >= 0
637
+ ? `${this.#listboxId}-option-${this._activeIndex}`
638
+ : nothing;
593
639
  return html `
594
640
  <button
595
641
  type="button"
596
642
  class="trigger"
597
643
  aria-haspopup="listbox"
598
644
  aria-expanded=${this._open}
645
+ aria-controls=${this.#listboxId}
646
+ aria-activedescendant=${activeDescendant}
599
647
  aria-label=${this.label || nothing}
600
648
  ?disabled=${this.disabled}
601
649
  @click=${() => this.#toggle()}
@@ -1 +1 @@
1
- {"version":3,"file":"form-select.js","sourceRoot":"","sources":["../src/form-select.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACL,UAAU,EACV,GAAG,EACH,IAAI,EACJ,OAAO,GAGR,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAYrC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QA0KL,2CAA2C;QACX,YAAO,GAAmB,EAAE,CAAC;QAC7D,qEAAqE;QACzD,UAAK,GAAG,EAAE,CAAC;QACvB,kDAAkD;QACtC,UAAK,GAAG,EAAE,CAAC;QACvB,iEAAiE;QACpC,aAAQ,GAAG,KAAK,CAAC;QAC9C;;;WAGG;QACyC,eAAU,GAAG,KAAK,CAAC;QAE9C,UAAK,GAAG,KAAK,CAAC;QACd,iBAAY,GAAG,CAAC,CAAC,CAAC;QAClB,WAAM,GAAkB,IAAI,CAAC;QAE9C,wBAAmB,GAAG,KAAK,CAAC;QAC5B,sBAAiB,GAAG,KAAK,CAAC;QAC1B,0BAAqB,GAAG,KAAK,CAAC;QAC9B,qBAAgB,GAA0C,IAAI,CAAC;QAC/D,iBAAY,GAAG,KAAK,CAAC;QACrB,0BAAqB,GAAG,KAAK,CAAC;QAC9B,yBAAoB,GAAyC,IAAI,CAAC;QAClE,eAAU,GAAyC,IAAI,CAAC;QA4CxD,uBAAkB,GAAG,CAAC,CAAa,EAAQ,EAAE;YAC3C,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QACtD,CAAC,CAAC;IAoVJ,CAAC;aApkBiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoKF;KACF,AAvKqB,CAuKpB;IAoBF,mBAAmB,CAAS;IAC5B,iBAAiB,CAAS;IAC1B,qBAAqB,CAAS;IAC9B,gBAAgB,CAA+C;IAC/D,YAAY,CAAS;IACrB,qBAAqB,CAAS;IAC9B,oBAAoB,CAA8C;IAClE,UAAU,CAA8C;IAE/C,oBAAoB;QAC3B,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACvE,IAAI,IAAI,CAAC,UAAU;YAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,oBAAoB;YAAE,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvE,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;QACjC,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEkB,OAAO,CAAC,OAAuB;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACzC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjD,CAAC;aAAM,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACtE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjD,CAAC;QACD,IACE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAChF,IAAI,CAAC,KAAK;YACV,IAAI,CAAC,YAAY,IAAI,CAAC,EACtB,CAAC;YACD,IAAI,CAAC,UAAU;iBACZ,aAAa,CAAc,uBAAuB,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvE,EAAE,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,kBAAkB,CAEhB;IAEF,OAAO;QACL,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,MAAM,EAAE,CAAC;;YACzB,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACjD,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC/B,CAAC;IAED,mBAAmB;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC;QACnC,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;QACjF,OAAO,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,eAAe;QACb,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CACpC,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAClD,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAoB;QAC1B,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO;QACxC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,iBAAiB,CAAC,CAAgB;QAChC,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YACvF,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;YACD,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW;gBAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;iBAC1C,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS;gBAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;;gBAC9C,IAAI,CAAC,cAAc,EAAE,CAAC;QAC7B,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC5C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACjC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,cAAc;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,MAAM;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,cAAc,CAAC,CAAa;QAC1B,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,qBAAqB;YAAG,CAAC,CAAC,aAAkC,CAAC,MAAM,EAAE,CAAC;IAClF,CAAC;IAED,cAAc,CAAC,CAAa;QAC1B,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;YAAG,CAAC,CAAC,aAAkC,CAAC,MAAM,EAAE,CAAC;IAC3E,CAAC;IAED,kBAAkB,CAAC,CAAa;QAC9B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,CAAC,CAAC,cAAc,EAAE,CAAC;IACzC,CAAC;IAED,cAAc,CAAC,CAAa;QAC1B,IAAI,CAAC,MAAM,GAAI,CAAC,CAAC,aAAkC,CAAC,KAAK,CAAC;QAC1D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,gBAAgB,CAAC,CAAgB;QAC/B,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,OAAO,KAAK,GAAG,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC1F,OAAO;QACT,CAAC;QACD,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACjD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC3C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC5C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,aAAa;QACX,IAAI,IAAI,CAAC,UAAU;YAAE,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACxB,IAAI,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAAC,IAAI,CAAC,iBAAiB;gBAAE,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,CAAa;QAC7B,IACE,CAAC,CAAC,MAAM,KAAK,CAAC;YACd,IAAI,CAAC,QAAQ;YACb,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,gBAAgB,EAC/C,CAAC;YACD,OAAO;QACT,CAAC;QACD,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAmB,oBAAoB,CAAC,CAAC;QACpF,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,KAAK,EAAE,KAAK,EAAE,CAAC;QACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAClB,CAAC;IAED,mBAAmB;QACjB,IAAI,IAAI,CAAC,oBAAoB;YAAE,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;QAClC,IAAI,IAAI,CAAC,oBAAoB;YAAE,YAAY,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvE,IAAI,CAAC,oBAAoB,GAAG,UAAU,CAAC,GAAG,EAAE;YAC1C,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;YACnC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB,CAAC,CAAa;QAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC3B,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAmB,oBAAoB,CAAC,CAAC;QACpF,IAAI,CAAC,gBAAgB,GAAG,KAAK;YAC3B,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,CAAC;YAC5C,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,CAAC,gBAAgB,CACrB,SAAS,EACT,GAAG,EAAE;YACH,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;YACjC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,WAAW,GACf,IAAI,CAAC,UAAU,CAAC,aAAa,CAAmB,oBAAoB,CAAC,CAAC;gBACxE,IAAI,WAAW,EAAE,CAAC;oBAChB,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;oBAClC,WAAW,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC3C,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;oBACnC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBAC3D,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI;wBAAE,WAAW,CAAC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAChF,CAAC;YACH,CAAC;YACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAC9B,CAAC;IACJ,CAAC;IAED,kBAAkB,CAAC,CAAa,EAAE,MAAoB;QACpD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC3B,MAAM,aAAa,GAAG,CAAC,CAAC,aAA4B,CAAC;QACrD,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC;QAC5C,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;YACjE,MAAM,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC;YAC5D,MAAM,iBAAiB,GAAG,KAAK;gBAC7B,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,cAAc;gBAC3C,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,GAAG,cAAc,CAAC;YAC/C,IAAI,cAAc,GAAG,CAAC,IAAI,iBAAiB;gBAAE,OAAO;QACtD,CAAC;QACD,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,eAAe,CAAC,MAAoB;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,CAAC;IAED,iBAAiB,CAAC,MAAoB,EAAE,SAAS,GAAG,aAAa;QAC/D,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE,OAAO,OAAO,CAAC;QACjC,OAAO,IAAI,CAAA;;gBAEC,SAAS;gBACT,4BAA4B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI;;;UAGlE,MAAM,CAAC,IAAI;;KAEhB,CAAC;IACJ,CAAC;IAED,oBAAoB,CAAC,MAAoB;QACvC,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;qCACH,MAAM,CAAC,KAAK;;KAE5C,CAAC;IACJ,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,OAAO,IAAI,CAAA;;;;;qBAKM,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;;UAEzD,OAAO,CAAC,GAAG,CACX,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;;mBAEL,sBAAsB,CAAC,EAAE;;8BAEd,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;sBAC9B,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;2BAClC,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC;;gBAE3D,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;;WAEjC,CACF;UACC,OAAO,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,IAAI,CAAA,6FAA6F;YACnG,CAAC,CAAC,OAAO;;KAEd,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,OAAiC;QAC3D,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;QACjE,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACxE,MAAM,gBAAgB,GACpB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC;YAClC,CAAC,CAAC,sBAAsB,IAAI,CAAC,YAAY,EAAE;YAC3C,CAAC,CAAC,OAAO,CAAC;QACd,OAAO,IAAI,CAAA;;gCAEiB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,gBAAgB;YACzE,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,EAAE;qBACO,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;;UAEvD,gBAAgB,IAAI,OAAO;YAC3B,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,2BAA2B,CAAC;YAC9D,CAAC,CAAC,OAAO;;;;;;0BAMO,IAAI,CAAC,KAAK;;kCAEF,gBAAgB;uBAC3B,IAAI,CAAC,KAAK,IAAI,kBAAkB;;sBAEjC,IAAI,CAAC,QAAQ;mBAChB,YAAY;uBACR,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC;mBACjD,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;mBACzC,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;mBACzC,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;8BAC9B,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE;4BAClC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE;qBACrC,CAAC,CAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;kBACjD,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE;;gCAEZ,gBAAgB,CAAC,EAAE,CAAC;;KAE/C,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,OAAiC;QAC3D,OAAO,IAAI,CAAA;;;;;wBAKS,IAAI,CAAC,KAAK;qBACb,IAAI,CAAC,KAAK,IAAI,OAAO;oBACtB,IAAI,CAAC,QAAQ;iBAChB,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;mBAClB,CAAC,CAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;;UAExD,OAAO;YACP,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC;YACpC,CAAC,CAAC,IAAI,CAAA,8BAA8B,IAAI,CAAC,KAAK,SAAS;gCACjC,gBAAgB,CAAC,EAAE,CAAC;;KAE/C,CAAC;IACJ,CAAC;IAEQ,MAAM;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;QACjE,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,UAAU;YACf,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;QACnC,IAAI,CAAC,aAAa,EAAE;KACvB,CAAC;IACJ,CAAC;CACF,CAAA;AA1ZiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;2CAA8B;AAEjD;IAAX,QAAQ,EAAE;yCAAY;AAEX;IAAX,QAAQ,EAAE;yCAAY;AAEM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAkB;AAKF;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAoB;AAE9C;IAAhB,KAAK,EAAE;yCAAuB;AACd;IAAhB,KAAK,EAAE;gDAA2B;AAClB;IAAhB,KAAK,EAAE;0CAAsC;AA1LnC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAqkBtB","sourcesContent":["import {\n LitElement,\n css,\n html,\n nothing,\n type PropertyValues,\n type TemplateResult,\n} from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { iconChevronRight } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** A single selectable option. */\nexport interface SelectOption {\n value: string;\n label: string;\n /** Optional pre-rendered icon template displayed before the label. */\n icon?: TemplateResult;\n /** Square icon size in pixels. Defaults to 16 when `icon` is set. */\n iconSize?: number;\n}\n\n/**\n * A styled dropdown select: a trigger button showing the current option's\n * label, opening a listbox popover on click. Drop-in generic replacement for\n * a native `<select>` wherever consistent cross-browser styling and a\n * `change` event carrying `{ value }` are wanted (e.g. a task's status\n * picker).\n *\n * The trigger fills its host's width (`justify-content: space-between`\n * pushes the chevron to the far edge), but the host itself stays\n * `display: inline-block` — so usages that never size the host (a filter\n * bar, a status picker) keep shrink-to-fit auto-width unchanged. To make an\n * instance full-width, size the host itself: `form-select { width: 100%; }`.\n *\n * Set `searchable` to replace the button trigger with an editable combobox\n * that filters the predefined options by case-insensitive label infix. Typed\n * text is only a query: `value` changes exclusively when an actual option is\n * selected, and an uncommitted query is discarded when the list closes.\n * Each option may also provide a pre-rendered `icon` and square `iconSize`;\n * iconless options reserve no leading space.\n *\n * @element form-select\n * @fires change - Fired with `{ value: string }` when a different option is picked.\n */\n@customElement(\"form-select\")\nexport class FormSelect extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n button.trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.35rem;\n width: 100%;\n box-sizing: border-box;\n font: inherit;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #fff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.3rem 0.5rem;\n cursor: pointer;\n }\n button.trigger:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n button.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n button.trigger:focus-visible {\n outline: none;\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .search-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.35rem;\n width: 100%;\n box-sizing: border-box;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #fff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n cursor: text;\n }\n .search-trigger:hover:not(.disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .search-trigger:focus-within {\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .search-trigger.disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n .search-trigger.has-icon input.search-input {\n padding-left: 0;\n }\n input.search-input {\n min-width: 0;\n flex: 1;\n box-sizing: border-box;\n padding: 0.3rem 0 0.3rem 0.5rem;\n color: inherit;\n background: transparent;\n border: 0;\n outline: 0;\n font: inherit;\n }\n .chevron {\n display: flex;\n flex: 0 0 auto;\n margin-right: 0.5rem;\n color: var(--ui-text-muted, #64748b);\n pointer-events: none;\n transform: rotate(90deg);\n transition: transform 0.1s ease;\n }\n button.trigger .chevron {\n margin-right: 0;\n }\n :host([open]) .chevron {\n transform: rotate(-90deg);\n }\n ul.options {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 10;\n min-width: 100%;\n max-height: 40vh;\n overflow-y: auto;\n scrollbar-gutter: stable;\n margin: 2px 0 0;\n padding: 4px 0;\n list-style: none;\n white-space: nowrap;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #fff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));\n }\n ul.options::-webkit-scrollbar {\n width: 0.75rem;\n }\n ul.options::-webkit-scrollbar-thumb {\n background: var(--ui-border, #e2e8f0);\n border: 0.2rem solid transparent;\n border-radius: 999px;\n background-clip: padding-box;\n }\n li {\n padding: 0.35rem 0.6rem;\n cursor: pointer;\n }\n li.active,\n li:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n li[aria-selected=\"true\"] {\n font-weight: 600;\n color: var(--ui-primary, #4f46e5);\n }\n .option-content {\n display: inline-flex;\n min-width: 0;\n align-items: center;\n gap: 0.4rem;\n }\n li .option-content {\n display: flex;\n width: 100%;\n }\n .option-icon {\n display: inline-flex;\n width: var(--form-select-icon-size);\n height: var(--form-select-icon-size);\n flex: 0 0 var(--form-select-icon-size);\n align-items: center;\n justify-content: center;\n }\n .option-icon > svg {\n width: 100%;\n height: 100%;\n }\n .selected-icon {\n margin-left: 0.5rem;\n }\n .option-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n li.no-options {\n padding: 0.35rem 0.6rem;\n color: var(--ui-text-muted, #64748b);\n cursor: default;\n font-style: italic;\n }\n `,\n ];\n\n /** The full list of selectable options. */\n @property({ attribute: false }) options: SelectOption[] = [];\n /** Currently selected value; must match one of `options[].value`. */\n @property() value = \"\";\n /** `aria-label` applied to the trigger button. */\n @property() label = \"\";\n /** Disables the trigger, preventing the popover from opening. */\n @property({ type: Boolean }) disabled = false;\n /**\n * Enables editable, case-insensitive infix filtering by option label.\n * Typed text never becomes the selected `value`.\n */\n @property({ type: Boolean, reflect: true }) searchable = false;\n\n @state() private _open = false;\n @state() private _activeIndex = -1;\n @state() private _query: string | null = null;\n\n #listboxPointerDown = false;\n #suppressNextBlur = false;\n #restoringSearchFocus = false;\n #searchSelection: [number | null, number | null] | null = null;\n #isComposing = false;\n #compositionJustEnded = false;\n #compositionEndTimer: ReturnType<typeof setTimeout> | null = null;\n #blurTimer: ReturnType<typeof setTimeout> | null = null;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#listboxPointerDown = false;\n this.#suppressNextBlur = false;\n this.#searchSelection = null;\n this.#isComposing = false;\n this.#compositionJustEnded = false;\n this.#close();\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"_open\")) {\n this.toggleAttribute(\"open\", this._open);\n if (this._open) {\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n } else {\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n }\n }\n if ((changed.has(\"disabled\") && this.disabled) || changed.has(\"searchable\")) {\n this.#close();\n return;\n }\n if (changed.has(\"options\") && this._open) {\n this._activeIndex = this.#initialActiveIndex();\n } else if (changed.has(\"value\") && this._open && this._query === null) {\n this._activeIndex = this.#initialActiveIndex();\n }\n if (\n (changed.has(\"_activeIndex\") || changed.has(\"_query\") || changed.has(\"options\")) &&\n this._open &&\n this._activeIndex >= 0\n ) {\n this.renderRoot\n .querySelector<HTMLElement>(`#form-select-option-${this._activeIndex}`)\n ?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n }\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #toggle(): void {\n if (this.disabled) return;\n if (this._open) this.#close();\n else this.#open();\n }\n\n #open(): void {\n if (this.disabled) return;\n this._query = null;\n this._open = true;\n this._activeIndex = this.#initialActiveIndex();\n }\n\n #close(): void {\n this._open = false;\n this._query = null;\n this._activeIndex = -1;\n this.#searchSelection = null;\n }\n\n #initialActiveIndex(): number {\n const options = this.#visibleOptions();\n if (options.length === 0) return -1;\n if (this._query !== null) return 0;\n const selectedIndex = options.findIndex((option) => option.value === this.value);\n return selectedIndex >= 0 ? selectedIndex : 0;\n }\n\n #visibleOptions(): SelectOption[] {\n if (!this.searchable || this._query === null) return this.options;\n const needle = this._query.trim().toLocaleLowerCase();\n if (!needle) return this.options;\n return this.options.filter((option) =>\n option.label.toLocaleLowerCase().includes(needle),\n );\n }\n\n #select(option: SelectOption): void {\n this.#close();\n if (option.value === this.value) return;\n this.value = option.value;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value: option.value } }));\n }\n\n #onTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\" || e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n if (!this._open) {\n this.#toggle();\n return;\n }\n if (e.key === \"ArrowDown\") this.#moveActive(1);\n else if (e.key === \"ArrowUp\") this.#moveActive(-1);\n else this.#confirmActive();\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n }\n }\n\n #moveActive(delta: number): void {\n const options = this.#visibleOptions();\n if (options.length === 0) return;\n const n = options.length;\n this._activeIndex = (this._activeIndex + delta + n) % n;\n }\n\n #confirmActive(): void {\n const options = this.#visibleOptions();\n const option = options[this._activeIndex] ?? options[0];\n if (option) this.#select(option);\n }\n\n #onSearchFocus(e: FocusEvent): void {\n if (this.disabled) return;\n if (this.#blurTimer) {\n clearTimeout(this.#blurTimer);\n this.#blurTimer = null;\n }\n if (!this._open) this.#open();\n if (!this.#restoringSearchFocus) (e.currentTarget as HTMLInputElement).select();\n }\n\n #onSearchClick(e: MouseEvent): void {\n if (!this._open) this.#open();\n if (this._query === null) (e.currentTarget as HTMLInputElement).select();\n }\n\n #onSearchMousedown(e: MouseEvent): void {\n if (e.button !== 0) e.preventDefault();\n }\n\n #onSearchInput(e: InputEvent): void {\n this._query = (e.currentTarget as HTMLInputElement).value;\n this._open = true;\n const options = this.#visibleOptions();\n this._activeIndex = options.length > 0 ? 0 : -1;\n }\n\n #onSearchKeydown(e: KeyboardEvent): void {\n if (e.isComposing || e.keyCode === 229 || this.#isComposing || this.#compositionJustEnded) {\n return;\n }\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n if (!this._open) {\n this.#open();\n return;\n }\n this.#moveActive(e.key === \"ArrowDown\" ? 1 : -1);\n } else if (e.key === \"Enter\" && this._open) {\n e.preventDefault();\n this.#confirmActive();\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n }\n }\n\n #onSearchBlur(): void {\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n this.#blurTimer = setTimeout(() => {\n this.#blurTimer = null;\n if (!this._open) return;\n if (!this.#listboxPointerDown && !this.#suppressNextBlur) this.#close();\n });\n }\n\n #focusSearchInput(e: MouseEvent): void {\n if (\n e.button !== 0 ||\n this.disabled ||\n e.composedPath()[0] instanceof HTMLInputElement\n ) {\n return;\n }\n e.preventDefault();\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (!this._open) this.#open();\n input?.focus();\n input?.select();\n }\n\n #onCompositionStart(): void {\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = null;\n this.#compositionJustEnded = false;\n this.#isComposing = true;\n }\n\n #onCompositionEnd(): void {\n this.#isComposing = false;\n this.#compositionJustEnded = true;\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = setTimeout(() => {\n this.#compositionJustEnded = false;\n this.#compositionEndTimer = null;\n });\n }\n\n #onListboxMousedown(e: MouseEvent): void {\n if (e.button !== 0) return;\n this.#listboxPointerDown = true;\n this.#suppressNextBlur = true;\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n this.#searchSelection = input\n ? [input.selectionStart, input.selectionEnd]\n : null;\n window.addEventListener(\n \"mouseup\",\n () => {\n this.#listboxPointerDown = false;\n if (this._open) {\n const searchInput =\n this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (searchInput) {\n this.#restoringSearchFocus = true;\n searchInput.focus({ preventScroll: true });\n this.#restoringSearchFocus = false;\n const [start, end] = this.#searchSelection ?? [null, null];\n if (start !== null && end !== null) searchInput.setSelectionRange(start, end);\n }\n }\n this.#searchSelection = null;\n setTimeout(() => {\n this.#suppressNextBlur = false;\n });\n },\n { capture: true, once: true },\n );\n }\n\n #onOptionMousedown(e: MouseEvent, option: SelectOption): void {\n if (e.button !== 0) return;\n const optionElement = e.currentTarget as HTMLElement;\n const listbox = optionElement.parentElement;\n if (listbox) {\n const scrollbarWidth = listbox.offsetWidth - listbox.clientWidth;\n const bounds = listbox.getBoundingClientRect();\n const isRtl = getComputedStyle(listbox).direction === \"rtl\";\n const inScrollbarGutter = isRtl\n ? e.clientX <= bounds.left + scrollbarWidth\n : e.clientX >= bounds.right - scrollbarWidth;\n if (scrollbarWidth > 0 && inScrollbarGutter) return;\n }\n e.preventDefault();\n this.#select(option);\n }\n\n #optionIconSize(option: SelectOption): number {\n const size = option.iconSize ?? 16;\n return Number.isFinite(size) && size > 0 ? size : 16;\n }\n\n #renderOptionIcon(option: SelectOption, className = \"option-icon\") {\n if (!option.icon) return nothing;\n return html`\n <span\n class=${className}\n style=${`--form-select-icon-size: ${this.#optionIconSize(option)}px`}\n aria-hidden=\"true\"\n >\n ${option.icon}\n </span>\n `;\n }\n\n #renderOptionContent(option: SelectOption) {\n return html`\n <span class=\"option-content\">\n ${this.#renderOptionIcon(option)}\n <span class=\"option-label\">${option.label}</span>\n </span>\n `;\n }\n\n private renderListbox() {\n if (!this._open) return nothing;\n const options = this.#visibleOptions();\n return html`\n <ul\n id=\"form-select-listbox\"\n class=\"options\"\n role=\"listbox\"\n @mousedown=${(e: MouseEvent) => this.#onListboxMousedown(e)}\n >\n ${options.map(\n (o, i) => html`\n <li\n id=${`form-select-option-${i}`}\n role=\"option\"\n aria-selected=${o.value === this.value}\n class=${i === this._activeIndex ? \"active\" : \"\"}\n @mousedown=${(e: MouseEvent) => this.#onOptionMousedown(e, o)}\n >\n ${this.#renderOptionContent(o)}\n </li>\n `,\n )}\n ${options.length === 0\n ? html`<li class=\"no-options\" role=\"presentation\"><span role=\"status\">No options found</span></li>`\n : nothing}\n </ul>\n `;\n }\n\n private renderSearchTrigger(current: SelectOption | undefined) {\n const displayValue = this._query ?? current?.label ?? this.value;\n const showSelectedIcon = this._query === null && Boolean(current?.icon);\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `form-select-option-${this._activeIndex}`\n : nothing;\n return html`\n <div\n class=\"search-trigger ${this.disabled ? \"disabled\" : \"\"} ${showSelectedIcon\n ? \"has-icon\"\n : \"\"}\"\n @mousedown=${(e: MouseEvent) => this.#focusSearchInput(e)}\n >\n ${showSelectedIcon && current\n ? this.#renderOptionIcon(current, \"option-icon selected-icon\")\n : nothing}\n <input\n type=\"text\"\n class=\"search-input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=${this._open}\n aria-controls=\"form-select-listbox\"\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || \"Select an option\"}\n autocomplete=\"off\"\n ?disabled=${this.disabled}\n .value=${displayValue}\n @mousedown=${(e: MouseEvent) => this.#onSearchMousedown(e)}\n @focus=${(e: FocusEvent) => this.#onSearchFocus(e)}\n @click=${(e: MouseEvent) => this.#onSearchClick(e)}\n @input=${(e: InputEvent) => this.#onSearchInput(e)}\n @compositionstart=${() => this.#onCompositionStart()}\n @compositionend=${() => this.#onCompositionEnd()}\n @keydown=${(e: KeyboardEvent) => this.#onSearchKeydown(e)}\n @blur=${() => this.#onSearchBlur()}\n />\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </div>\n `;\n }\n\n private renderButtonTrigger(current: SelectOption | undefined) {\n return html`\n <button\n type=\"button\"\n class=\"trigger\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open}\n aria-label=${this.label || nothing}\n ?disabled=${this.disabled}\n @click=${() => this.#toggle()}\n @keydown=${(e: KeyboardEvent) => this.#onTriggerKeydown(e)}\n >\n ${current\n ? this.#renderOptionContent(current)\n : html`<span class=\"option-label\">${this.value}</span>`}\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </button>\n `;\n }\n\n override render() {\n const current = this.options.find((o) => o.value === this.value);\n return html`\n ${this.searchable\n ? this.renderSearchTrigger(current)\n : this.renderButtonTrigger(current)}\n ${this.renderListbox()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"form-select\": FormSelect;\n }\n}\n"]}
1
+ {"version":3,"file":"form-select.js","sourceRoot":"","sources":["../src/form-select.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n LitElement,\n css,\n html,\n nothing,\n type PropertyValues,\n type TemplateResult,\n} from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { iconChevronRight } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\nlet instanceCount = 0;\n\n/** A single selectable option. */\nexport interface SelectOption {\n value: string;\n label: string;\n /** Optional pre-rendered icon template displayed before the label. */\n icon?: TemplateResult;\n /** Square icon size in pixels. Defaults to 16 when `icon` is set. */\n iconSize?: number;\n}\n\n/**\n * A styled dropdown select: a trigger button showing the current option's\n * label, opening a listbox popover on click. Drop-in generic replacement for\n * a native `<select>` wherever consistent cross-browser styling and a\n * `change` event carrying `{ value }` are wanted (e.g. a task's status\n * picker).\n *\n * The trigger fills its host's width (`justify-content: space-between`\n * pushes the chevron to the far edge), but the host itself stays\n * `display: inline-block` — so usages that never size the host (a filter\n * bar, a status picker) keep shrink-to-fit auto-width unchanged. To make an\n * instance full-width, size the host itself: `form-select { width: 100%; }`.\n *\n * Set `searchable` to replace the button trigger with an editable combobox\n * that filters the predefined options by case-insensitive label infix. Typed\n * text is only a query: `value` changes exclusively when an actual option is\n * selected, and an uncommitted query is discarded when the list closes.\n * Each option may also provide a pre-rendered `icon` and square `iconSize`;\n * iconless options reserve no leading space.\n *\n * @element form-select\n * @fires change - Fired with `{ value: string }` when a different option is picked.\n */\n@customElement(\"form-select\")\nexport class FormSelect extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n button.trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.25rem;\n width: 100%;\n box-sizing: border-box;\n font: inherit;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.25rem 0.5rem;\n cursor: pointer;\n }\n button.trigger:hover:not(:disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n button.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n button.trigger:focus-visible {\n outline: none;\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .search-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.25rem;\n width: 100%;\n box-sizing: border-box;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n cursor: text;\n }\n .search-trigger:hover:not(.disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .search-trigger:not(.disabled):focus-within {\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .search-trigger.disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n .search-trigger.has-icon input.search-input {\n padding-left: 0;\n }\n input.search-input {\n min-width: 0;\n flex: 1;\n box-sizing: border-box;\n padding: 0.25rem 0 0.25rem 0.5rem;\n color: inherit;\n background: transparent;\n border: 0;\n outline: 0;\n font: inherit;\n }\n .chevron {\n display: flex;\n flex: 0 0 auto;\n margin-right: 0.5rem;\n color: var(--ui-text-muted, #64748b);\n pointer-events: none;\n transform: rotate(90deg);\n transition: transform 150ms ease;\n }\n button.trigger .chevron {\n margin-right: 0;\n }\n :host([open]) .chevron {\n transform: rotate(-90deg);\n }\n ul.options {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 10;\n min-width: 100%;\n max-height: 40vh;\n overflow-y: auto;\n scrollbar-gutter: stable;\n margin: 0.25rem 0 0;\n padding: 0.25rem 0;\n list-style: none;\n white-space: nowrap;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));\n }\n ul.options::-webkit-scrollbar {\n width: 0.75rem;\n }\n ul.options::-webkit-scrollbar-thumb {\n background: var(--ui-border, #e2e8f0);\n border: 0.25rem solid transparent;\n border-radius: 999px;\n background-clip: padding-box;\n }\n li {\n padding: 0.5rem;\n cursor: pointer;\n }\n li.active,\n li:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n li[aria-selected=\"true\"] {\n font-weight: 600;\n color: var(--ui-primary, #4f46e5);\n }\n .option-content {\n display: inline-flex;\n min-width: 0;\n align-items: center;\n gap: 0.5rem;\n }\n li .option-content {\n display: flex;\n width: 100%;\n }\n .option-icon {\n display: inline-flex;\n width: var(--form-select-icon-size);\n height: var(--form-select-icon-size);\n flex: 0 0 var(--form-select-icon-size);\n align-items: center;\n justify-content: center;\n }\n .option-icon > svg {\n width: 100%;\n height: 100%;\n }\n .selected-icon {\n margin-left: 0.5rem;\n }\n .option-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n li.no-options {\n padding: 0.5rem;\n color: var(--ui-text-muted, #64748b);\n cursor: default;\n font-style: italic;\n }\n @media (prefers-reduced-motion: reduce) {\n .chevron {\n transition: none;\n }\n }\n @media (forced-colors: active) {\n button.trigger:focus-visible,\n .search-trigger:not(.disabled):focus-within {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n button.trigger:disabled,\n .search-trigger.disabled {\n color: GrayText;\n opacity: 1;\n }\n li.active,\n li:hover {\n color: HighlightText;\n background: Highlight;\n }\n li[aria-selected=\"true\"] {\n color: Highlight;\n }\n li.active[aria-selected=\"true\"],\n li[aria-selected=\"true\"]:hover {\n color: HighlightText;\n }\n }\n `,\n ];\n\n /** The full list of selectable options. */\n @property({ attribute: false }) options: SelectOption[] = [];\n /** Currently selected value; must match one of `options[].value`. */\n @property() value = \"\";\n /** `aria-label` applied to the trigger button. */\n @property() label = \"\";\n /** Disables the trigger, preventing the popover from opening. */\n @property({ type: Boolean }) disabled = false;\n /**\n * Enables editable, case-insensitive infix filtering by option label.\n * Typed text never becomes the selected `value`.\n */\n @property({ type: Boolean, reflect: true }) searchable = false;\n\n @state() private _open = false;\n @state() private _activeIndex = -1;\n @state() private _query: string | null = null;\n\n #listboxPointerDown = false;\n #suppressNextBlur = false;\n #restoringSearchFocus = false;\n #searchSelection: [number | null, number | null] | null = null;\n #isComposing = false;\n #compositionJustEnded = false;\n #compositionEndTimer: ReturnType<typeof setTimeout> | null = null;\n #blurTimer: ReturnType<typeof setTimeout> | null = null;\n readonly #listboxId = `form-select-listbox-${++instanceCount}`;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#listboxPointerDown = false;\n this.#suppressNextBlur = false;\n this.#searchSelection = null;\n this.#isComposing = false;\n this.#compositionJustEnded = false;\n this.#close();\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"_open\")) {\n this.toggleAttribute(\"open\", this._open);\n if (this._open) {\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n } else {\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n }\n }\n if ((changed.has(\"disabled\") && this.disabled) || changed.has(\"searchable\")) {\n this.#close();\n return;\n }\n if (changed.has(\"options\") && this._open) {\n this._activeIndex = this.#initialActiveIndex();\n } else if (changed.has(\"value\") && this._open && this._query === null) {\n this._activeIndex = this.#initialActiveIndex();\n }\n if (\n (changed.has(\"_activeIndex\") || changed.has(\"_query\") || changed.has(\"options\")) &&\n this._open &&\n this._activeIndex >= 0\n ) {\n this.renderRoot\n .querySelector<HTMLElement>(`#${this.#listboxId}-option-${this._activeIndex}`)\n ?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n }\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #toggle(): void {\n if (this.disabled) return;\n if (this._open) this.#close();\n else this.#open();\n }\n\n #open(): void {\n if (this.disabled) return;\n this._query = null;\n this._open = true;\n this._activeIndex = this.#initialActiveIndex();\n }\n\n #close(): void {\n this._open = false;\n this._query = null;\n this._activeIndex = -1;\n this.#searchSelection = null;\n }\n\n #initialActiveIndex(): number {\n const options = this.#visibleOptions();\n if (options.length === 0) return -1;\n if (this._query !== null) return 0;\n const selectedIndex = options.findIndex((option) => option.value === this.value);\n return selectedIndex >= 0 ? selectedIndex : 0;\n }\n\n #visibleOptions(): SelectOption[] {\n if (!this.searchable || this._query === null) return this.options;\n const needle = this._query.trim().toLocaleLowerCase();\n if (!needle) return this.options;\n return this.options.filter((option) =>\n option.label.toLocaleLowerCase().includes(needle),\n );\n }\n\n #select(option: SelectOption): void {\n this.#close();\n if (option.value === this.value) return;\n this.value = option.value;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value: option.value } }));\n }\n\n #onTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\" || e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n if (!this._open) {\n this.#toggle();\n return;\n }\n if (e.key === \"ArrowDown\") this.#moveActive(1);\n else if (e.key === \"ArrowUp\") this.#moveActive(-1);\n else this.#confirmActive();\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n }\n }\n\n #moveActive(delta: number): void {\n const options = this.#visibleOptions();\n if (options.length === 0) return;\n const n = options.length;\n this._activeIndex = (this._activeIndex + delta + n) % n;\n }\n\n #confirmActive(): void {\n const options = this.#visibleOptions();\n const option = options[this._activeIndex] ?? options[0];\n if (option) this.#select(option);\n }\n\n #onSearchFocus(e: FocusEvent): void {\n if (this.disabled) return;\n if (this.#blurTimer) {\n clearTimeout(this.#blurTimer);\n this.#blurTimer = null;\n }\n if (!this._open) this.#open();\n if (!this.#restoringSearchFocus) (e.currentTarget as HTMLInputElement).select();\n }\n\n #onSearchClick(e: MouseEvent): void {\n if (!this._open) this.#open();\n if (this._query === null) (e.currentTarget as HTMLInputElement).select();\n }\n\n #onSearchMousedown(e: MouseEvent): void {\n if (e.button !== 0) e.preventDefault();\n }\n\n #onSearchInput(e: InputEvent): void {\n this._query = (e.currentTarget as HTMLInputElement).value;\n this._open = true;\n const options = this.#visibleOptions();\n this._activeIndex = options.length > 0 ? 0 : -1;\n }\n\n #onSearchKeydown(e: KeyboardEvent): void {\n if (e.isComposing || e.keyCode === 229 || this.#isComposing || this.#compositionJustEnded) {\n return;\n }\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n if (!this._open) {\n this.#open();\n return;\n }\n this.#moveActive(e.key === \"ArrowDown\" ? 1 : -1);\n } else if (e.key === \"Enter\" && this._open) {\n e.preventDefault();\n this.#confirmActive();\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n }\n }\n\n #onSearchBlur(): void {\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n this.#blurTimer = setTimeout(() => {\n this.#blurTimer = null;\n if (!this._open) return;\n if (!this.#listboxPointerDown && !this.#suppressNextBlur) this.#close();\n });\n }\n\n #focusSearchInput(e: MouseEvent): void {\n if (\n e.button !== 0 ||\n this.disabled ||\n e.composedPath()[0] instanceof HTMLInputElement\n ) {\n return;\n }\n e.preventDefault();\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (!this._open) this.#open();\n input?.focus();\n input?.select();\n }\n\n #onCompositionStart(): void {\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = null;\n this.#compositionJustEnded = false;\n this.#isComposing = true;\n }\n\n #onCompositionEnd(): void {\n this.#isComposing = false;\n this.#compositionJustEnded = true;\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = setTimeout(() => {\n this.#compositionJustEnded = false;\n this.#compositionEndTimer = null;\n });\n }\n\n #onListboxMousedown(e: MouseEvent): void {\n if (e.button !== 0) return;\n this.#listboxPointerDown = true;\n this.#suppressNextBlur = true;\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n this.#searchSelection = input\n ? [input.selectionStart, input.selectionEnd]\n : null;\n window.addEventListener(\n \"mouseup\",\n () => {\n this.#listboxPointerDown = false;\n if (this._open) {\n const searchInput =\n this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (searchInput) {\n this.#restoringSearchFocus = true;\n searchInput.focus({ preventScroll: true });\n this.#restoringSearchFocus = false;\n const [start, end] = this.#searchSelection ?? [null, null];\n if (start !== null && end !== null) searchInput.setSelectionRange(start, end);\n }\n }\n this.#searchSelection = null;\n setTimeout(() => {\n this.#suppressNextBlur = false;\n });\n },\n { capture: true, once: true },\n );\n }\n\n #onOptionMousedown(e: MouseEvent, option: SelectOption): void {\n if (e.button !== 0) return;\n const optionElement = e.currentTarget as HTMLElement;\n const listbox = optionElement.parentElement;\n if (listbox) {\n const scrollbarWidth = listbox.offsetWidth - listbox.clientWidth;\n const bounds = listbox.getBoundingClientRect();\n const isRtl = getComputedStyle(listbox).direction === \"rtl\";\n const inScrollbarGutter = isRtl\n ? e.clientX <= bounds.left + scrollbarWidth\n : e.clientX >= bounds.right - scrollbarWidth;\n if (scrollbarWidth > 0 && inScrollbarGutter) return;\n }\n e.preventDefault();\n this.#select(option);\n }\n\n #optionIconSize(option: SelectOption): number {\n const size = option.iconSize ?? 16;\n return Number.isFinite(size) && size > 0 ? size : 16;\n }\n\n #renderOptionIcon(option: SelectOption, className = \"option-icon\") {\n if (!option.icon) return nothing;\n return html`\n <span\n class=${className}\n style=${`--form-select-icon-size: ${this.#optionIconSize(option)}px`}\n aria-hidden=\"true\"\n >\n ${option.icon}\n </span>\n `;\n }\n\n #renderOptionContent(option: SelectOption) {\n return html`\n <span class=\"option-content\">\n ${this.#renderOptionIcon(option)}\n <span class=\"option-label\">${option.label}</span>\n </span>\n `;\n }\n\n private renderListbox() {\n if (!this._open) return nothing;\n const options = this.#visibleOptions();\n return html`\n <ul\n id=${this.#listboxId}\n class=\"options\"\n role=\"listbox\"\n aria-label=${this.label ? `${this.label} options` : \"Options\"}\n @mousedown=${(e: MouseEvent) => this.#onListboxMousedown(e)}\n >\n ${options.map(\n (o, i) => html`\n <li\n id=${`${this.#listboxId}-option-${i}`}\n role=\"option\"\n aria-selected=${o.value === this.value}\n class=${i === this._activeIndex ? \"active\" : \"\"}\n @mousedown=${(e: MouseEvent) => this.#onOptionMousedown(e, o)}\n >\n ${this.#renderOptionContent(o)}\n </li>\n `,\n )}\n ${options.length === 0\n ? html`<li class=\"no-options\" role=\"presentation\"><span role=\"status\">No options found</span></li>`\n : nothing}\n </ul>\n `;\n }\n\n private renderSearchTrigger(current: SelectOption | undefined) {\n const displayValue = this._query ?? current?.label ?? this.value;\n const showSelectedIcon = this._query === null && Boolean(current?.icon);\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#listboxId}-option-${this._activeIndex}`\n : nothing;\n return html`\n <div\n class=\"search-trigger ${this.disabled ? \"disabled\" : \"\"} ${showSelectedIcon\n ? \"has-icon\"\n : \"\"}\"\n @mousedown=${(e: MouseEvent) => this.#focusSearchInput(e)}\n >\n ${showSelectedIcon && current\n ? this.#renderOptionIcon(current, \"option-icon selected-icon\")\n : nothing}\n <input\n type=\"text\"\n class=\"search-input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=${this._open}\n aria-controls=${this.#listboxId}\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || \"Select an option\"}\n autocomplete=\"off\"\n ?disabled=${this.disabled}\n .value=${displayValue}\n @mousedown=${(e: MouseEvent) => this.#onSearchMousedown(e)}\n @focus=${(e: FocusEvent) => this.#onSearchFocus(e)}\n @click=${(e: MouseEvent) => this.#onSearchClick(e)}\n @input=${(e: InputEvent) => this.#onSearchInput(e)}\n @compositionstart=${() => this.#onCompositionStart()}\n @compositionend=${() => this.#onCompositionEnd()}\n @keydown=${(e: KeyboardEvent) => this.#onSearchKeydown(e)}\n @blur=${() => this.#onSearchBlur()}\n />\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </div>\n `;\n }\n\n private renderButtonTrigger(current: SelectOption | undefined) {\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#listboxId}-option-${this._activeIndex}`\n : nothing;\n return html`\n <button\n type=\"button\"\n class=\"trigger\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open}\n aria-controls=${this.#listboxId}\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || nothing}\n ?disabled=${this.disabled}\n @click=${() => this.#toggle()}\n @keydown=${(e: KeyboardEvent) => this.#onTriggerKeydown(e)}\n >\n ${current\n ? this.#renderOptionContent(current)\n : html`<span class=\"option-label\">${this.value}</span>`}\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </button>\n `;\n }\n\n override render() {\n const current = this.options.find((o) => o.value === this.value);\n return html`\n ${this.searchable\n ? this.renderSearchTrigger(current)\n : this.renderButtonTrigger(current)}\n ${this.renderListbox()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"form-select\": FormSelect;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"frame-box.d.ts","sourceRoot":"","sources":["../src/frame-box.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;;;;;GAQG;AACH,qBACa,QAAS,SAAQ,UAAU;IACtC,OAAgB,MAAM,4BA0BpB;IAEF,iDAAiD;IACrC,KAAK,SAAM;IAEd,MAAM,yCAOd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
1
+ {"version":3,"file":"frame-box.d.ts","sourceRoot":"","sources":["../src/frame-box.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;;;;;GAQG;AACH,qBACa,QAAS,SAAQ,UAAU;IACtC,OAAgB,MAAM,4BAkCpB;IAEF,iDAAiD;IACrC,KAAK,SAAM;IAEd,MAAM,yCAOd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
package/dist/frame-box.js CHANGED
@@ -27,21 +27,29 @@ let FrameBox = class FrameBox extends LitElement {
27
27
  css `
28
28
  :host {
29
29
  display: block;
30
- position: relative;
31
- margin-top: 0.6rem;
30
+ margin-top: 0.5rem;
32
31
  }
33
32
  .frame {
33
+ min-width: 0;
34
+ margin: 0;
34
35
  border: 1px solid var(--ui-border, #e2e8f0);
35
36
  border-radius: var(--ui-radius-sm, 0.25rem);
36
- padding: 1rem 0.75rem 0.75rem;
37
+ padding: 0.75rem;
37
38
  }
38
39
  .label {
39
- position: absolute;
40
- top: -0.55rem;
41
- left: 0.6rem;
42
- padding: 0 0.4rem;
43
- background: var(--ui-surface, #fff);
44
- font-size: 0.65rem;
40
+ padding: 0 0.5rem;
41
+ background: var(--ui-surface, #ffffff);
42
+ font-family: var(
43
+ --ui-font,
44
+ ui-sans-serif,
45
+ system-ui,
46
+ sans-serif,
47
+ "Apple Color Emoji",
48
+ "Segoe UI Emoji",
49
+ "Segoe UI Symbol",
50
+ "Noto Color Emoji"
51
+ );
52
+ font-size: var(--ui-font-size-xs, 0.6875rem);
45
53
  font-weight: 600;
46
54
  text-transform: uppercase;
47
55
  letter-spacing: 0.05em;
@@ -51,10 +59,10 @@ let FrameBox = class FrameBox extends LitElement {
51
59
  ]; }
52
60
  render() {
53
61
  return html `
54
- <div class="frame">
55
- ${this.label ? html `<span class="label">${this.label}</span>` : null}
62
+ <fieldset class="frame">
63
+ ${this.label ? html `<legend class="label">${this.label}</legend>` : null}
56
64
  <slot></slot>
57
- </div>
65
+ </fieldset>
58
66
  `;
59
67
  }
60
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"frame-box.js","sourceRoot":"","sources":["../src/frame-box.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;GAQG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,UAAU;IAAjC;;QA6BL,iDAAiD;QACrC,UAAK,GAAG,EAAE,CAAC;IAUzB,CAAC;aAvCiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;KAuBF;KACF,AA1BqB,CA0BpB;IAKO,MAAM;QACb,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,uBAAuB,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI;;;KAGvE,CAAC;IACJ,CAAC;CACF,CAAA;AAVa;IAAX,QAAQ,EAAE;uCAAY;AA9BZ,QAAQ;IADpB,aAAa,CAAC,WAAW,CAAC;GACd,QAAQ,CAwCpB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A titled frame around a slot: a gray border with a small uppercase,\n * muted label overlapping the top edge (fieldset/legend-style). Generic —\n * the label text is entirely up to the consumer (e.g. \"Debug\" to visually\n * fence off dev-only chrome from the product UI).\n *\n * @element frame-box\n * @slot - Framed content.\n */\n@customElement(\"frame-box\")\nexport class FrameBox extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n position: relative;\n margin-top: 0.6rem;\n }\n .frame {\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 1rem 0.75rem 0.75rem;\n }\n .label {\n position: absolute;\n top: -0.55rem;\n left: 0.6rem;\n padding: 0 0.4rem;\n background: var(--ui-surface, #fff);\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ui-text-muted, #64748b);\n }\n `,\n ];\n\n /** The overlapping title label, e.g. \"Debug\". */\n @property() label = \"\";\n\n override render() {\n return html`\n <div class=\"frame\">\n ${this.label ? html`<span class=\"label\">${this.label}</span>` : null}\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"frame-box\": FrameBox;\n }\n}\n"]}
1
+ {"version":3,"file":"frame-box.js","sourceRoot":"","sources":["../src/frame-box.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;GAQG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,UAAU;IAAjC;;QAqCL,iDAAiD;QACrC,UAAK,GAAG,EAAE,CAAC;IAUzB,CAAC;aA/CiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+BF;KACF,AAlCqB,CAkCpB;IAKO,MAAM;QACb,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,yBAAyB,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI;;;KAG3E,CAAC;IACJ,CAAC;CACF,CAAA;AAVa;IAAX,QAAQ,EAAE;uCAAY;AAtCZ,QAAQ;IADpB,aAAa,CAAC,WAAW,CAAC;GACd,QAAQ,CAgDpB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A titled frame around a slot: a gray border with a small uppercase,\n * muted label overlapping the top edge (fieldset/legend-style). Generic —\n * the label text is entirely up to the consumer (e.g. \"Debug\" to visually\n * fence off dev-only chrome from the product UI).\n *\n * @element frame-box\n * @slot - Framed content.\n */\n@customElement(\"frame-box\")\nexport class FrameBox extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n margin-top: 0.5rem;\n }\n .frame {\n min-width: 0;\n margin: 0;\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.75rem;\n }\n .label {\n padding: 0 0.5rem;\n background: var(--ui-surface, #ffffff);\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-xs, 0.6875rem);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ui-text-muted, #64748b);\n }\n `,\n ];\n\n /** The overlapping title label, e.g. \"Debug\". */\n @property() label = \"\";\n\n override render() {\n return html`\n <fieldset class=\"frame\">\n ${this.label ? html`<legend class=\"label\">${this.label}</legend>` : null}\n <slot></slot>\n </fieldset>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"frame-box\": FrameBox;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../src/icon-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAI1C;;;;;;;;GAQG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,OAAgB,MAAM,4BAgCpB;IAEF,sFAAsF;IACtD,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IACnE,kEAAkE;IACtD,KAAK,SAAM;IACvB,uCAAuC;IACV,QAAQ,UAAS;IAErC,MAAM,sBAMd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
1
+ {"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../src/icon-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAI1C;;;;;;;;GAQG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,OAAgB,MAAM,4BA2CpB;IAEF,sFAAsF;IACtD,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IACnE,kEAAkE;IACtD,KAAK,SAAM;IACvB,uCAAuC;IACV,QAAQ,UAAS;IAErC,MAAM,sBAMd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
@@ -57,6 +57,17 @@ let IconButton = class IconButton extends LitElement {
57
57
  outline: none;
58
58
  box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
59
59
  }
60
+ @media (forced-colors: active) {
61
+ button:focus-visible {
62
+ outline: 2px solid CanvasText;
63
+ outline-offset: 2px;
64
+ box-shadow: none;
65
+ }
66
+ button:disabled {
67
+ color: GrayText;
68
+ opacity: 1;
69
+ }
70
+ }
60
71
  `,
61
72
  ]; }
62
73
  render() {
@@ -1 +1 @@
1
- {"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../src/icon-button.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;GAQG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QAmCL,sFAAsF;QACtD,SAAI,GAA0B,IAAI,CAAC;QACnE,kEAAkE;QACtD,UAAK,GAAG,EAAE,CAAC;QACvB,uCAAuC;QACV,aAAQ,GAAG,KAAK,CAAC;IAShD,CAAC;aAhDiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6BF;KACF,AAhCqB,CAgCpB;IASO,MAAM;QACb,OAAO,IAAI,CAAA;yCAC0B,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,QAAQ;UACxF,IAAI,CAAC,IAAI,IAAI,OAAO;;KAEzB,CAAC;IACJ,CAAC;CACF,CAAA;AAbiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;wCAAoC;AAEvD;IAAX,QAAQ,EAAE;yCAAY;AAEM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAkB;AAxCnC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAiDtB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport type { TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A borderless button wrapping a passed-in icon, with a rounded\n * hover-highlight background. Use for a low-emphasis affordance next to\n * content it acts on (e.g. an \"Edit\" pencil at the end of a table row)\n * where a bordered `ui-button` would be too heavy.\n *\n * @element icon-button\n * @fires click - Native click, bubbling as usual — listen on the element itself.\n */\n@customElement(\"icon-button\")\nexport class IconButton extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n }\n button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n background: none;\n color: var(--ui-text-muted, #64748b);\n cursor: pointer;\n }\n button:hover:not(:disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n color: var(--ui-text, #0f172a);\n }\n button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n button:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n `,\n ];\n\n /** Pre-rendered icon template, e.g. `iconPencil(16)` from this package's icon set. */\n @property({ attribute: false }) icon: TemplateResult | null = null;\n /** Required accessible label, applied as `aria-label`/`title`. */\n @property() label = \"\";\n /** Disables the button and dims it. */\n @property({ type: Boolean }) disabled = false;\n\n override render() {\n return html`\n <button type=\"button\" aria-label=${this.label} title=${this.label} ?disabled=${this.disabled}>\n ${this.icon ?? nothing}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"icon-button\": IconButton;\n }\n}\n"]}
1
+ {"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../src/icon-button.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;GAQG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QA8CL,sFAAsF;QACtD,SAAI,GAA0B,IAAI,CAAC;QACnE,kEAAkE;QACtD,UAAK,GAAG,EAAE,CAAC;QACvB,uCAAuC;QACV,aAAQ,GAAG,KAAK,CAAC;IAShD,CAAC;aA3DiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCF;KACF,AA3CqB,CA2CpB;IASO,MAAM;QACb,OAAO,IAAI,CAAA;yCAC0B,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,QAAQ;UACxF,IAAI,CAAC,IAAI,IAAI,OAAO;;KAEzB,CAAC;IACJ,CAAC;CACF,CAAA;AAbiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;wCAAoC;AAEvD;IAAX,QAAQ,EAAE;yCAAY;AAEM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAkB;AAnDnC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CA4DtB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport type { TemplateResult } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A borderless button wrapping a passed-in icon, with a rounded\n * hover-highlight background. Use for a low-emphasis affordance next to\n * content it acts on (e.g. an \"Edit\" pencil at the end of a table row)\n * where a bordered `ui-button` would be too heavy.\n *\n * @element icon-button\n * @fires click - Native click, bubbling as usual — listen on the element itself.\n */\n@customElement(\"icon-button\")\nexport class IconButton extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n }\n button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n background: none;\n color: var(--ui-text-muted, #64748b);\n cursor: pointer;\n }\n button:hover:not(:disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n color: var(--ui-text, #0f172a);\n }\n button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n button:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @media (forced-colors: active) {\n button:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n button:disabled {\n color: GrayText;\n opacity: 1;\n }\n }\n `,\n ];\n\n /** Pre-rendered icon template, e.g. `iconPencil(16)` from this package's icon set. */\n @property({ attribute: false }) icon: TemplateResult | null = null;\n /** Required accessible label, applied as `aria-label`/`title`. */\n @property() label = \"\";\n /** Disables the button and dims it. */\n @property({ type: Boolean }) disabled = false;\n\n override render() {\n return html`\n <button type=\"button\" aria-label=${this.label} title=${this.label} ?disabled=${this.disabled}>\n ${this.icon ?? nothing}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"icon-button\": IconButton;\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ export { TileGrid } from "./tile-grid.js";
33
33
  export { PopoverPanel } from "./popover-panel.js";
34
34
  export { DropdownButton, type DropdownOption } from "./dropdown-button.js";
35
35
  export { IconButton } from "./icon-button.js";
36
+ export { KbdHint, type KbdPlatform } from "./kbd-hint.js";
36
37
  export { FrameBox } from "./frame-box.js";
37
38
  export { CalendarEntry } from "./calendar-entry.js";
38
39
  export { CalendarMonth } from "./calendar-month.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}