@f-ewald/components 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +4 -1
  2. package/custom-elements.json +7 -7
  3. package/dist/address-autocomplete.d.ts.map +1 -1
  4. package/dist/address-autocomplete.js +3 -1
  5. package/dist/address-autocomplete.js.map +1 -1
  6. package/dist/autocomplete-input.d.ts.map +1 -1
  7. package/dist/autocomplete-input.js +3 -1
  8. package/dist/autocomplete-input.js.map +1 -1
  9. package/dist/calendar-month.d.ts.map +1 -1
  10. package/dist/calendar-month.js +9 -8
  11. package/dist/calendar-month.js.map +1 -1
  12. package/dist/chat-message.d.ts.map +1 -1
  13. package/dist/chat-message.js +15 -5
  14. package/dist/chat-message.js.map +1 -1
  15. package/dist/confirm-dialog.d.ts.map +1 -1
  16. package/dist/confirm-dialog.js +24 -6
  17. package/dist/confirm-dialog.js.map +1 -1
  18. package/dist/copy-link-button.d.ts.map +1 -1
  19. package/dist/copy-link-button.js +4 -2
  20. package/dist/copy-link-button.js.map +1 -1
  21. package/dist/data-table.js +1 -1
  22. package/dist/data-table.js.map +1 -1
  23. package/dist/distribution-chart.d.ts +2 -2
  24. package/dist/distribution-chart.js +4 -4
  25. package/dist/distribution-chart.js.map +1 -1
  26. package/dist/dropdown-button.d.ts.map +1 -1
  27. package/dist/dropdown-button.js +13 -2
  28. package/dist/dropdown-button.js.map +1 -1
  29. package/dist/form-select.d.ts.map +1 -1
  30. package/dist/form-select.js +32 -8
  31. package/dist/form-select.js.map +1 -1
  32. package/dist/frame-box.js +3 -3
  33. package/dist/frame-box.js.map +1 -1
  34. package/dist/icon-button.d.ts +1 -1
  35. package/dist/icon-button.js +1 -1
  36. package/dist/icon-button.js.map +1 -1
  37. package/dist/kbd-hint.js +1 -1
  38. package/dist/kbd-hint.js.map +1 -1
  39. package/dist/map-circle.js +2 -2
  40. package/dist/map-circle.js.map +1 -1
  41. package/dist/map-pin.js +2 -2
  42. package/dist/map-pin.js.map +1 -1
  43. package/dist/percent-bar-chart.js +1 -1
  44. package/dist/percent-bar-chart.js.map +1 -1
  45. package/dist/photo-gallery.d.ts.map +1 -1
  46. package/dist/photo-gallery.js +33 -9
  47. package/dist/photo-gallery.js.map +1 -1
  48. package/dist/popover-panel.d.ts.map +1 -1
  49. package/dist/popover-panel.js +7 -4
  50. package/dist/popover-panel.js.map +1 -1
  51. package/dist/radio-cards.d.ts.map +1 -1
  52. package/dist/radio-cards.js +4 -3
  53. package/dist/radio-cards.js.map +1 -1
  54. package/dist/radio-pills.d.ts.map +1 -1
  55. package/dist/radio-pills.js +7 -4
  56. package/dist/radio-pills.js.map +1 -1
  57. package/dist/reveal-button.d.ts.map +1 -1
  58. package/dist/reveal-button.js +4 -1
  59. package/dist/reveal-button.js.map +1 -1
  60. package/dist/slide-panel.d.ts.map +1 -1
  61. package/dist/slide-panel.js +8 -5
  62. package/dist/slide-panel.js.map +1 -1
  63. package/dist/stat-meter.js +3 -3
  64. package/dist/stat-meter.js.map +1 -1
  65. package/dist/status-pill.js +2 -2
  66. package/dist/status-pill.js.map +1 -1
  67. package/dist/tile-grid.js +1 -1
  68. package/dist/tile-grid.js.map +1 -1
  69. package/dist/toast-notification.d.ts.map +1 -1
  70. package/dist/toast-notification.js +10 -5
  71. package/dist/toast-notification.js.map +1 -1
  72. package/dist/tokens.css +10 -0
  73. package/dist/tokens.d.ts.map +1 -1
  74. package/dist/tokens.js +15 -2
  75. package/dist/tokens.js.map +1 -1
  76. package/dist/ui-button.d.ts.map +1 -1
  77. package/dist/ui-button.js +3 -1
  78. package/dist/ui-button.js.map +1 -1
  79. package/dist/user-avatar.js +1 -1
  80. package/dist/user-avatar.js.map +1 -1
  81. package/dist/weight-bar-chart.js +2 -2
  82. package/dist/weight-bar-chart.js.map +1 -1
  83. package/docs/address-autocomplete.md +1 -0
  84. package/docs/autocomplete-input.md +1 -0
  85. package/docs/calendar-month.md +6 -1
  86. package/docs/chat-message.md +2 -0
  87. package/docs/confirm-dialog.md +3 -0
  88. package/docs/data-table.md +1 -0
  89. package/docs/design-language.md +68 -40
  90. package/docs/distribution-chart.md +3 -2
  91. package/docs/dropdown-button.md +2 -0
  92. package/docs/form-select.md +2 -0
  93. package/docs/frame-box.md +3 -1
  94. package/docs/icon-button.md +1 -1
  95. package/docs/kbd-hint.md +1 -0
  96. package/docs/map-circle.md +2 -0
  97. package/docs/map-pin.md +2 -0
  98. package/docs/photo-gallery.md +1 -0
  99. package/docs/popover-panel.md +3 -1
  100. package/docs/radio-cards.md +2 -0
  101. package/docs/radio-pills.md +1 -0
  102. package/docs/reveal-button.md +3 -1
  103. package/docs/slide-panel.md +3 -1
  104. package/docs/stat-meter.md +3 -0
  105. package/docs/status-pill.md +1 -0
  106. package/docs/toast-notification.md +2 -0
  107. package/docs/ui-button.md +2 -0
  108. package/docs/user-avatar.md +1 -0
  109. package/docs/weight-bar-chart.md +0 -1
  110. package/llms.txt +27 -27
  111. package/package.json +1 -3
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-button.js","sourceRoot":"","sources":["../src/dropdown-button.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } 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 menu action. */\nexport interface DropdownOption {\n value: string;\n label: string;\n}\n\n/**\n * A primary-styled button with a label and chevron that opens an anchored\n * menu of actions — essentially `form-select` minus \"current value\"\n * semantics: a menu, not a select. Use for a set of mutually exclusive\n * next-step actions (e.g. a failed task's Retry / Close / Backlog).\n *\n * @element dropdown-button\n * @fires select - Fired with `{ value: string }` when a menu item is picked.\n */\n@customElement(\"dropdown-button\")\nexport class DropdownButton 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 }\n button.trigger {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n font: inherit;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: 500;\n color: var(--ui-on-accent, #ffffff);\n background: var(--ui-primary, #4f46e5);\n border: 1px solid transparent;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 1rem;\n cursor: pointer;\n }\n button.trigger:hover:not(:disabled) {\n background: var(--ui-primary-hover, #4338ca);\n }\n button.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n button.trigger:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .chevron {\n display: flex;\n transform: rotate(90deg);\n transition: transform 150ms ease;\n }\n :host([open]) .chevron {\n transform: rotate(-90deg);\n }\n ul.options {\n position: absolute;\n top: 100%;\n right: 0;\n z-index: 10;\n min-width: 100%;\n max-height: 40vh;\n overflow-y: auto;\n margin: 0.25rem 0 0;\n padding: 0.25rem 0;\n list-style: none;\n white-space: nowrap;\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 li {\n padding: 0.5rem 0.75rem;\n cursor: pointer;\n color: var(--ui-text, #0f172a);\n }\n li.active,\n li:hover {\n background: var(--ui-surface-muted, #f8fafc);\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 outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n button.trigger:disabled {\n color: GrayText;\n opacity: 1;\n }\n li.active,\n li:hover {\n color: HighlightText;\n background: Highlight;\n }\n }\n `,\n ];\n\n /** The trigger button's label. */\n @property() label = \"\";\n /** The menu's actions. */\n @property({ attribute: false }) options: DropdownOption[] = [];\n /** Disables the trigger, preventing the menu from opening. */\n @property({ type: Boolean }) disabled = false;\n\n @state() private _open = false;\n @state() private _activeIndex = -1;\n readonly #menuId = `dropdown-button-menu-${++instanceCount}`;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n this._open = false;\n this._activeIndex = -1;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"disabled\") && this.disabled) {\n this._open = false;\n this._activeIndex = -1;\n }\n if (!changed.has(\"_open\")) return;\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\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!e.composedPath().includes(this)) this._open = false;\n };\n\n #toggle(): void {\n if (this.disabled) return;\n this._open = !this._open;\n if (this._open) this._activeIndex = 0;\n }\n\n #select(option: DropdownOption): void {\n if (this.disabled) return;\n this._open = false;\n this.dispatchEvent(new CustomEvent(\"select\", { 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._open = false;\n }\n }\n\n #moveActive(delta: number): void {\n if (this.options.length === 0) return;\n const n = this.options.length;\n this._activeIndex = (this._activeIndex + delta + n) % n;\n }\n\n #confirmActive(): void {\n const option = this.options[this._activeIndex];\n if (option) this.#select(option);\n }\n\n private renderMenu() {\n if (!this._open) return nothing;\n return html`\n <ul id=${this.#menuId} class=\"options\" role=\"menu\" aria-label=${this.label}>\n ${this.options.map(\n (o, i) => html`\n <li\n id=${`${this.#menuId}-item-${i}`}\n role=\"menuitem\"\n class=${i === this._activeIndex ? \"active\" : \"\"}\n @mousedown=${(e: MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n this.#select(o);\n }}\n >\n ${o.label}\n </li>\n `,\n )}\n </ul>\n `;\n }\n\n override render() {\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#menuId}-item-${this._activeIndex}`\n : nothing;\n return html`\n <button\n type=\"button\"\n class=\"trigger\"\n aria-haspopup=\"menu\"\n aria-expanded=${this._open}\n aria-controls=${this.#menuId}\n aria-activedescendant=${activeDescendant}\n ?disabled=${this.disabled}\n @click=${() => this.#toggle()}\n @keydown=${(e: KeyboardEvent) => this.#onTriggerKeydown(e)}\n >\n <span>${this.label}</span>\n <span class=\"chevron\" aria-hidden=\"true\">${iconChevronRight(14)}</span>\n </button>\n ${this.renderMenu()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"dropdown-button\": DropdownButton;\n }\n}\n"]}
1
+ {"version":3,"file":"dropdown-button.js","sourceRoot":"","sources":["../src/dropdown-button.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } 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 menu action. */\nexport interface DropdownOption {\n value: string;\n label: string;\n}\n\n/**\n * A primary-styled button with a label and chevron that opens an anchored\n * menu of actions — essentially `form-select` minus \"current value\"\n * semantics: a menu, not a select. Use for a set of mutually exclusive\n * next-step actions (e.g. a failed task's Retry / Close / Backlog).\n *\n * @element dropdown-button\n * @fires select - Fired with `{ value: string }` when a menu item is picked.\n */\n@customElement(\"dropdown-button\")\nexport class DropdownButton 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 }\n button.trigger {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n height: 2rem;\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 font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-on-accent, #ffffff);\n background: var(--ui-primary, #4f46e5);\n border: 1px solid transparent;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 1rem;\n cursor: pointer;\n }\n button.trigger:hover:not(:disabled) {\n background: var(--ui-primary-hover, #4338ca);\n }\n button.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n button.trigger:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .chevron {\n display: flex;\n transform: rotate(90deg);\n transition: transform 150ms ease;\n }\n :host([open]) .chevron {\n transform: rotate(-90deg);\n }\n ul.options {\n position: absolute;\n top: 100%;\n right: 0;\n z-index: 10;\n min-width: 100%;\n max-height: 40vh;\n overflow-y: auto;\n margin: 0.25rem 0 0;\n padding: 0.25rem 0;\n list-style: none;\n white-space: nowrap;\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 li {\n padding: 0.5rem 0.75rem;\n cursor: pointer;\n color: var(--ui-text, #0f172a);\n }\n li.active,\n li:hover {\n background: var(--ui-surface-muted, #f8fafc);\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 outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n button.trigger:disabled {\n color: GrayText;\n opacity: 1;\n }\n li.active,\n li:hover {\n color: HighlightText;\n background: Highlight;\n }\n }\n `,\n ];\n\n /** The trigger button's label. */\n @property() label = \"\";\n /** The menu's actions. */\n @property({ attribute: false }) options: DropdownOption[] = [];\n /** Disables the trigger, preventing the menu from opening. */\n @property({ type: Boolean }) disabled = false;\n\n @state() private _open = false;\n @state() private _activeIndex = -1;\n readonly #menuId = `dropdown-button-menu-${++instanceCount}`;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n this._open = false;\n this._activeIndex = -1;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"disabled\") && this.disabled) {\n this._open = false;\n this._activeIndex = -1;\n }\n if (!changed.has(\"_open\")) return;\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\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!e.composedPath().includes(this)) this._open = false;\n };\n\n #toggle(): void {\n if (this.disabled) return;\n this._open = !this._open;\n if (this._open) this._activeIndex = 0;\n }\n\n #select(option: DropdownOption): void {\n if (this.disabled) return;\n this._open = false;\n this.dispatchEvent(new CustomEvent(\"select\", { 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._open = false;\n }\n }\n\n #moveActive(delta: number): void {\n if (this.options.length === 0) return;\n const n = this.options.length;\n this._activeIndex = (this._activeIndex + delta + n) % n;\n }\n\n #confirmActive(): void {\n const option = this.options[this._activeIndex];\n if (option) this.#select(option);\n }\n\n private renderMenu() {\n if (!this._open) return nothing;\n return html`\n <ul id=${this.#menuId} class=\"options\" role=\"menu\" aria-label=${this.label}>\n ${this.options.map(\n (o, i) => html`\n <li\n id=${`${this.#menuId}-item-${i}`}\n role=\"menuitem\"\n class=${i === this._activeIndex ? \"active\" : \"\"}\n @mousedown=${(e: MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n this.#select(o);\n }}\n >\n ${o.label}\n </li>\n `,\n )}\n </ul>\n `;\n }\n\n override render() {\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#menuId}-item-${this._activeIndex}`\n : nothing;\n return html`\n <button\n type=\"button\"\n class=\"trigger\"\n aria-haspopup=\"menu\"\n aria-expanded=${this._open}\n aria-controls=${this.#menuId}\n aria-activedescendant=${activeDescendant}\n ?disabled=${this.disabled}\n @click=${() => this.#toggle()}\n @keydown=${(e: KeyboardEvent) => this.#onTriggerKeydown(e)}\n >\n <span>${this.label}</span>\n <span class=\"chevron\" aria-hidden=\"true\">${iconChevronRight(14)}</span>\n </button>\n ${this.renderMenu()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"dropdown-button\": DropdownButton;\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;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"}
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,4BAsOpB;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"}
@@ -89,13 +89,25 @@ let FormSelect = class FormSelect extends LitElement {
89
89
  justify-content: space-between;
90
90
  gap: 0.25rem;
91
91
  width: 100%;
92
+ height: 2rem;
92
93
  box-sizing: border-box;
93
- font: inherit;
94
+ font-family: var(
95
+ --ui-font,
96
+ ui-sans-serif,
97
+ system-ui,
98
+ sans-serif,
99
+ "Apple Color Emoji",
100
+ "Segoe UI Emoji",
101
+ "Segoe UI Symbol",
102
+ "Noto Color Emoji"
103
+ );
104
+ font-size: var(--ui-font-size-sm, 0.75rem);
105
+ line-height: var(--ui-line-height-tight, 1.25);
94
106
  color: var(--ui-text, #0f172a);
95
107
  background: var(--ui-surface, #ffffff);
96
108
  border: 1px solid var(--ui-border, #e2e8f0);
97
109
  border-radius: var(--ui-radius-sm, 0.25rem);
98
- padding: 0.25rem 0.5rem;
110
+ padding: 0.5rem 0.75rem;
99
111
  cursor: pointer;
100
112
  }
101
113
  button.trigger:hover:not(:disabled) {
@@ -116,6 +128,7 @@ let FormSelect = class FormSelect extends LitElement {
116
128
  justify-content: space-between;
117
129
  gap: 0.25rem;
118
130
  width: 100%;
131
+ height: 2rem;
119
132
  box-sizing: border-box;
120
133
  color: var(--ui-text, #0f172a);
121
134
  background: var(--ui-surface, #ffffff);
@@ -141,17 +154,28 @@ let FormSelect = class FormSelect extends LitElement {
141
154
  min-width: 0;
142
155
  flex: 1;
143
156
  box-sizing: border-box;
144
- padding: 0.25rem 0 0.25rem 0.5rem;
157
+ padding: 0.5rem 0 0.5rem 0.75rem;
145
158
  color: inherit;
146
159
  background: transparent;
147
160
  border: 0;
148
161
  outline: 0;
149
- font: inherit;
162
+ font-family: var(
163
+ --ui-font,
164
+ ui-sans-serif,
165
+ system-ui,
166
+ sans-serif,
167
+ "Apple Color Emoji",
168
+ "Segoe UI Emoji",
169
+ "Segoe UI Symbol",
170
+ "Noto Color Emoji"
171
+ );
172
+ font-size: var(--ui-font-size-sm, 0.75rem);
173
+ line-height: var(--ui-line-height-tight, 1.25);
150
174
  }
151
175
  .chevron {
152
176
  display: flex;
153
177
  flex: 0 0 auto;
154
- margin-right: 0.5rem;
178
+ margin-right: 0.75rem;
155
179
  color: var(--ui-text-muted, #64748b);
156
180
  pointer-events: none;
157
181
  transform: rotate(90deg);
@@ -192,7 +216,7 @@ let FormSelect = class FormSelect extends LitElement {
192
216
  background-clip: padding-box;
193
217
  }
194
218
  li {
195
- padding: 0.5rem;
219
+ padding: 0.5rem 0.75rem;
196
220
  cursor: pointer;
197
221
  }
198
222
  li.active,
@@ -200,7 +224,7 @@ let FormSelect = class FormSelect extends LitElement {
200
224
  background: var(--ui-surface-muted, #f8fafc);
201
225
  }
202
226
  li[aria-selected="true"] {
203
- font-weight: 600;
227
+ font-weight: var(--ui-font-weight-semibold, 600);
204
228
  color: var(--ui-primary, #4f46e5);
205
229
  }
206
230
  .option-content {
@@ -235,7 +259,7 @@ let FormSelect = class FormSelect extends LitElement {
235
259
  white-space: nowrap;
236
260
  }
237
261
  li.no-options {
238
- padding: 0.5rem;
262
+ padding: 0.5rem 0.75rem;
239
263
  color: var(--ui-text-muted, #64748b);
240
264
  cursor: default;
241
265
  font-style: italic;
@@ -1 +1 @@
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
+ {"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 height: 2rem;\n box-sizing: border-box;\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 line-height: var(--ui-line-height-tight, 1.25);\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.5rem 0.75rem;\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 height: 2rem;\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.5rem 0 0.5rem 0.75rem;\n color: inherit;\n background: transparent;\n border: 0;\n outline: 0;\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 line-height: var(--ui-line-height-tight, 1.25);\n }\n .chevron {\n display: flex;\n flex: 0 0 auto;\n margin-right: 0.75rem;\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 0.75rem;\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: var(--ui-font-weight-semibold, 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 0.75rem;\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"]}
package/dist/frame-box.js CHANGED
@@ -33,7 +33,7 @@ let FrameBox = class FrameBox extends LitElement {
33
33
  min-width: 0;
34
34
  margin: 0;
35
35
  border: 1px solid var(--ui-border, #e2e8f0);
36
- border-radius: var(--ui-radius-sm, 0.25rem);
36
+ border-radius: var(--ui-radius, 0.5rem);
37
37
  padding: 0.75rem;
38
38
  }
39
39
  .label {
@@ -50,9 +50,9 @@ let FrameBox = class FrameBox extends LitElement {
50
50
  "Noto Color Emoji"
51
51
  );
52
52
  font-size: var(--ui-font-size-xs, 0.6875rem);
53
- font-weight: 600;
53
+ font-weight: var(--ui-font-weight-semibold, 600);
54
54
  text-transform: uppercase;
55
- letter-spacing: 0.05em;
55
+ letter-spacing: var(--ui-tracking-wide, 0.04em);
56
56
  color: var(--ui-text-muted, #64748b);
57
57
  }
58
58
  `,
@@ -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;;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
+ {"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, 0.5rem);\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: var(--ui-font-weight-semibold, 600);\n text-transform: uppercase;\n letter-spacing: var(--ui-tracking-wide, 0.04em);\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"]}
@@ -11,7 +11,7 @@ import type { TemplateResult } from "lit";
11
11
  */
12
12
  export declare class IconButton extends LitElement {
13
13
  static styles: import("lit").CSSResult[];
14
- /** Pre-rendered icon template, e.g. `iconPencil(16)` from this package's icon set. */
14
+ /** Pre-rendered icon template, e.g. `iconPencil(18)` from this package's icon set. */
15
15
  icon: TemplateResult | null;
16
16
  /** Required accessible label, applied as `aria-label`/`title`. */
17
17
  label: string;
@@ -19,7 +19,7 @@ import { tokens } from "./tokens.js";
19
19
  let IconButton = class IconButton extends LitElement {
20
20
  constructor() {
21
21
  super(...arguments);
22
- /** Pre-rendered icon template, e.g. `iconPencil(16)` from this package's icon set. */
22
+ /** Pre-rendered icon template, e.g. `iconPencil(18)` from this package's icon set. */
23
23
  this.icon = null;
24
24
  /** Required accessible label, applied as `aria-label`/`title`. */
25
25
  this.label = "";
@@ -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;;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"]}
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(18)` 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/kbd-hint.js CHANGED
@@ -137,7 +137,7 @@ let KbdHint = class KbdHint extends LitElement {
137
137
  monospace
138
138
  );
139
139
  font-size: var(--ui-font-size-xs, 0.6875rem);
140
- line-height: 1;
140
+ line-height: var(--ui-line-height-glyph, 1);
141
141
  }
142
142
  `,
143
143
  ]; }
@@ -1 +1 @@
1
- {"version":3,"file":"kbd-hint.js","sourceRoot":"","sources":["../src/kbd-hint.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** Platform mode used to render modifier keys. */\nexport type KbdPlatform = \"auto\" | \"mac\" | \"other\";\n\n/** Visual and spoken representations of one shortcut key. */\ninterface KeyRender {\n label: string;\n name: string;\n}\n\n/**\n * Detects macOS via User-Agent Client Hints when available, with legacy\n * navigator fields as fallbacks.\n */\nfunction detectMac(): boolean {\n if (\n typeof window === \"undefined\" ||\n typeof document === \"undefined\" ||\n typeof navigator === \"undefined\"\n ) {\n return false;\n }\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n const source = nav.userAgentData?.platform || nav.platform || nav.userAgent || \"\";\n return /mac/i.test(source);\n}\n\n/**\n * Maps one case-insensitive shortcut token to its visual keycap and spoken\n * name. Unknown tokens remain literal; single letters are uppercased.\n */\nfunction keyLabel(raw: string, mac: boolean): KeyRender {\n switch (raw.trim().toLowerCase()) {\n case \"mod\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Ctrl\", name: \"Control\" };\n case \"cmd\":\n case \"command\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Cmd\", name: \"Command\" };\n case \"meta\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Meta\", name: \"Meta\" };\n case \"super\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Super\", name: \"Super\" };\n case \"win\":\n case \"windows\":\n return { label: \"Win\", name: \"Windows\" };\n case \"ctrl\":\n case \"control\":\n return mac ? { label: \"⌃\", name: \"Control\" } : { label: \"Ctrl\", name: \"Control\" };\n case \"alt\":\n case \"opt\":\n case \"option\":\n return mac ? { label: \"⌥\", name: \"Option\" } : { label: \"Alt\", name: \"Alt\" };\n case \"shift\":\n return mac ? { label: \"⇧\", name: \"Shift\" } : { label: \"Shift\", name: \"Shift\" };\n case \"enter\":\n case \"return\":\n return { label: \"⏎\", name: \"Enter\" };\n case \"tab\":\n return { label: \"⇥\", name: \"Tab\" };\n case \"backspace\":\n return { label: \"⌫\", name: \"Backspace\" };\n case \"delete\":\n case \"del\":\n return { label: \"⌦\", name: \"Delete\" };\n case \"esc\":\n case \"escape\":\n return { label: \"Esc\", name: \"Escape\" };\n case \"space\":\n case \"spacebar\":\n return { label: \"Space\", name: \"Space\" };\n case \"up\":\n case \"arrowup\":\n return { label: \"↑\", name: \"Up arrow\" };\n case \"down\":\n case \"arrowdown\":\n return { label: \"↓\", name: \"Down arrow\" };\n case \"left\":\n case \"arrowleft\":\n return { label: \"←\", name: \"Left arrow\" };\n case \"right\":\n case \"arrowright\":\n return { label: \"→\", name: \"Right arrow\" };\n case \"pageup\":\n return { label: \"PgUp\", name: \"Page Up\" };\n case \"pagedown\":\n return { label: \"PgDn\", name: \"Page Down\" };\n default: {\n const token = raw.trim();\n const label = token.length === 1 ? token.toUpperCase() : token;\n return { label, name: label };\n }\n }\n}\n\n/**\n * Renders a keyboard shortcut as one boxed keycap per `+`-separated token.\n * Modifier keys are platform-aware: `Mod` becomes Command on macOS and\n * Control elsewhere. Keycaps derive their presentation from `currentColor`,\n * so the hint works inside neutral and accent-colored controls.\n *\n * @element kbd-hint\n */\n@customElement(\"kbd-hint\")\nexport class KbdHint extends LitElement {\n /** Shortcut as case-insensitive, `+`-separated tokens, e.g. `\"Mod+Enter\"`. */\n @property() keys = \"\";\n\n /** Platform override; `auto` detects macOS from the browser. */\n @property() platform: KbdPlatform = \"auto\";\n\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n vertical-align: middle;\n }\n .wrap {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: 1.25em;\n height: 1.5em;\n padding: 0 0.25rem;\n color: currentColor;\n background: color-mix(in srgb, currentColor 14%, transparent);\n border: 1px solid color-mix(in srgb, currentColor 38%, transparent);\n border-radius: var(--ui-radius-sm, 0.25rem);\n font-family: var(\n --ui-font-mono,\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n monospace\n );\n font-size: var(--ui-font-size-xs, 0.6875rem);\n line-height: 1;\n }\n `,\n ];\n\n /** Whether modifier aliases should use macOS glyphs. */\n private get isMac(): boolean {\n if (this.platform === \"mac\") return true;\n if (this.platform === \"other\") return false;\n return detectMac();\n }\n\n /** Parses the shortcut into visual/spoken key descriptors. */\n private get parsedKeys(): KeyRender[] {\n const mac = this.isMac;\n return (this.keys ?? \"\")\n .split(\"+\")\n .map((token) => token.trim())\n .filter(Boolean)\n .map((token) => keyLabel(token, mac));\n }\n\n /** Renders nothing for an empty shortcut, otherwise an accessible keycap group. */\n override render() {\n const parsedKeys = this.parsedKeys;\n if (parsedKeys.length === 0) return html``;\n const label = parsedKeys.map((key) => key.name).join(\" \");\n return html`\n <span class=\"wrap\" role=\"img\" aria-label=${label}>\n ${parsedKeys.map((key) => html`<kbd aria-hidden=\"true\">${key.label}</kbd>`)}\n </span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"kbd-hint\": KbdHint;\n }\n}\n"]}
1
+ {"version":3,"file":"kbd-hint.js","sourceRoot":"","sources":["../src/kbd-hint.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** Platform mode used to render modifier keys. */\nexport type KbdPlatform = \"auto\" | \"mac\" | \"other\";\n\n/** Visual and spoken representations of one shortcut key. */\ninterface KeyRender {\n label: string;\n name: string;\n}\n\n/**\n * Detects macOS via User-Agent Client Hints when available, with legacy\n * navigator fields as fallbacks.\n */\nfunction detectMac(): boolean {\n if (\n typeof window === \"undefined\" ||\n typeof document === \"undefined\" ||\n typeof navigator === \"undefined\"\n ) {\n return false;\n }\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n const source = nav.userAgentData?.platform || nav.platform || nav.userAgent || \"\";\n return /mac/i.test(source);\n}\n\n/**\n * Maps one case-insensitive shortcut token to its visual keycap and spoken\n * name. Unknown tokens remain literal; single letters are uppercased.\n */\nfunction keyLabel(raw: string, mac: boolean): KeyRender {\n switch (raw.trim().toLowerCase()) {\n case \"mod\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Ctrl\", name: \"Control\" };\n case \"cmd\":\n case \"command\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Cmd\", name: \"Command\" };\n case \"meta\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Meta\", name: \"Meta\" };\n case \"super\":\n return mac ? { label: \"⌘\", name: \"Command\" } : { label: \"Super\", name: \"Super\" };\n case \"win\":\n case \"windows\":\n return { label: \"Win\", name: \"Windows\" };\n case \"ctrl\":\n case \"control\":\n return mac ? { label: \"⌃\", name: \"Control\" } : { label: \"Ctrl\", name: \"Control\" };\n case \"alt\":\n case \"opt\":\n case \"option\":\n return mac ? { label: \"⌥\", name: \"Option\" } : { label: \"Alt\", name: \"Alt\" };\n case \"shift\":\n return mac ? { label: \"⇧\", name: \"Shift\" } : { label: \"Shift\", name: \"Shift\" };\n case \"enter\":\n case \"return\":\n return { label: \"⏎\", name: \"Enter\" };\n case \"tab\":\n return { label: \"⇥\", name: \"Tab\" };\n case \"backspace\":\n return { label: \"⌫\", name: \"Backspace\" };\n case \"delete\":\n case \"del\":\n return { label: \"⌦\", name: \"Delete\" };\n case \"esc\":\n case \"escape\":\n return { label: \"Esc\", name: \"Escape\" };\n case \"space\":\n case \"spacebar\":\n return { label: \"Space\", name: \"Space\" };\n case \"up\":\n case \"arrowup\":\n return { label: \"↑\", name: \"Up arrow\" };\n case \"down\":\n case \"arrowdown\":\n return { label: \"↓\", name: \"Down arrow\" };\n case \"left\":\n case \"arrowleft\":\n return { label: \"←\", name: \"Left arrow\" };\n case \"right\":\n case \"arrowright\":\n return { label: \"→\", name: \"Right arrow\" };\n case \"pageup\":\n return { label: \"PgUp\", name: \"Page Up\" };\n case \"pagedown\":\n return { label: \"PgDn\", name: \"Page Down\" };\n default: {\n const token = raw.trim();\n const label = token.length === 1 ? token.toUpperCase() : token;\n return { label, name: label };\n }\n }\n}\n\n/**\n * Renders a keyboard shortcut as one boxed keycap per `+`-separated token.\n * Modifier keys are platform-aware: `Mod` becomes Command on macOS and\n * Control elsewhere. Keycaps derive their presentation from `currentColor`,\n * so the hint works inside neutral and accent-colored controls.\n *\n * @element kbd-hint\n */\n@customElement(\"kbd-hint\")\nexport class KbdHint extends LitElement {\n /** Shortcut as case-insensitive, `+`-separated tokens, e.g. `\"Mod+Enter\"`. */\n @property() keys = \"\";\n\n /** Platform override; `auto` detects macOS from the browser. */\n @property() platform: KbdPlatform = \"auto\";\n\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n vertical-align: middle;\n }\n .wrap {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: 1.25em;\n height: 1.5em;\n padding: 0 0.25rem;\n color: currentColor;\n background: color-mix(in srgb, currentColor 14%, transparent);\n border: 1px solid color-mix(in srgb, currentColor 38%, transparent);\n border-radius: var(--ui-radius-sm, 0.25rem);\n font-family: var(\n --ui-font-mono,\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n monospace\n );\n font-size: var(--ui-font-size-xs, 0.6875rem);\n line-height: var(--ui-line-height-glyph, 1);\n }\n `,\n ];\n\n /** Whether modifier aliases should use macOS glyphs. */\n private get isMac(): boolean {\n if (this.platform === \"mac\") return true;\n if (this.platform === \"other\") return false;\n return detectMac();\n }\n\n /** Parses the shortcut into visual/spoken key descriptors. */\n private get parsedKeys(): KeyRender[] {\n const mac = this.isMac;\n return (this.keys ?? \"\")\n .split(\"+\")\n .map((token) => token.trim())\n .filter(Boolean)\n .map((token) => keyLabel(token, mac));\n }\n\n /** Renders nothing for an empty shortcut, otherwise an accessible keycap group. */\n override render() {\n const parsedKeys = this.parsedKeys;\n if (parsedKeys.length === 0) return html``;\n const label = parsedKeys.map((key) => key.name).join(\" \");\n return html`\n <span class=\"wrap\" role=\"img\" aria-label=${label}>\n ${parsedKeys.map((key) => html`<kbd aria-hidden=\"true\">${key.label}</kbd>`)}\n </span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"kbd-hint\": KbdHint;\n }\n}\n"]}
@@ -68,8 +68,8 @@ let MapCircle = class MapCircle extends LitElement {
68
68
  "Segoe UI Symbol",
69
69
  "Noto Color Emoji"
70
70
  );
71
- font-weight: 700;
72
- line-height: 1;
71
+ font-weight: var(--ui-font-weight-bold, 700);
72
+ line-height: var(--ui-line-height-glyph, 1);
73
73
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);
74
74
  pointer-events: none;
75
75
  white-space: nowrap;
@@ -1 +1 @@
1
- {"version":3,"file":"map-circle.js","sourceRoot":"","sources":["../src/map-circle.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;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEI,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,UAAU;IAAlC;;QA+CL,4FAA4F;QAChF,UAAK,GAAG,SAAS,CAAC;QAC9B,+BAA+B;QACH,SAAI,GAAG,EAAE,CAAC;QACtC,wFAAwF;QACnC,cAAS,GAAG,CAAC,CAAC;QACnE,sFAAsF;QAC1C,gBAAW,GAAG,KAAK,CAAC;QAE/C,YAAO,GAAG,mBAAmB,iBAAiB,EAAE,EAAE,CAAC;IA2BtE,CAAC;aAlFiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyCF;KACF,AA5CqB,CA4CpB;IAaO,MAAM;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAA;;;gBAGC,IAAI,CAAC,IAAI;iBACR,IAAI,CAAC,IAAI;;;;;;+BAMK,IAAI,CAAC,OAAO;2CACA,KAAK;6CACH,IAAI;;;oDAGG,IAAI,CAAC,OAAO,oCAAoC,IAAI,CAAC,SAAS;;8CAEpE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;;;KAGpE,CAAC;IACJ,CAAC;CACF,CAAA;AAnCa;IAAX,QAAQ,EAAE;wCAAmB;AAEF;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uCAAW;AAEe;IAApD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;4CAAe;AAEvB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAqB;AAtDrD,SAAS;IADrB,aAAa,CAAC,YAAY,CAAC;GACf,SAAS,CAmFrB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\nimport { mixHex } from \"./utils/color.js\";\n\nlet gradientIdCounter = 0;\n\n/**\n * A plain circular map marker: a light-to-dark gradient fill with a white\n * outer ring, no point/tail (unlike `<map-pin>`) — for markers that don't\n * need to visually \"point\" at their exact coordinate. Purely a visual\n * primitive — it has no `mapbox-gl` (or any mapping library) dependency;\n * the consumer positions it, e.g. via `new mapboxgl.Marker({ element: el })`.\n * It can also replace the former `<map-point>` dense-layer primitive: use\n * `size=\"14\" ring-width=\"3\"`, leave the slot empty, and rasterize one marker\n * per color for use as a map `icon-image`.\n *\n * @element map-circle\n * @slot - Optional badge content shown centered on the circle — a rank\n * number, an emoji, a small icon.\n */\n@customElement(\"map-circle\")\nexport class MapCircle extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n line-height: 0;\n }\n svg {\n display: block;\n transition: transform 120ms ease, filter 120ms ease;\n }\n :host([highlighted]) svg {\n transform: scale(1.12);\n filter: brightness(1.08) drop-shadow(0 0 5px rgb(0 0 0 / 0.35));\n }\n .content {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #fff;\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-weight: 700;\n line-height: 1;\n text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);\n pointer-events: none;\n white-space: nowrap;\n }\n @media (prefers-reduced-motion: reduce) {\n svg {\n transition: none;\n }\n }\n `,\n ];\n\n /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */\n @property() color = \"#4f46e5\";\n /** Diameter, in CSS pixels. */\n @property({ type: Number }) size = 18;\n /** White outer ring thickness, in the same viewBox units as `size` (scales with it). */\n @property({ type: Number, attribute: \"ring-width\" }) ringWidth = 4;\n /** Scales and glows the circle — a generic emphasis state (e.g. hover, selection). */\n @property({ type: Boolean, reflect: true }) highlighted = false;\n\n private readonly _gradId = `map-circle-grad-${gradientIdCounter++}`;\n\n override render() {\n const light = mixHex(this.color, \"#ffffff\", 30);\n const dark = mixHex(this.color, \"#000000\", 30);\n return html`\n <svg\n aria-hidden=\"true\"\n width=${this.size}\n height=${this.size}\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=${this._gradId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=${light} />\n <stop offset=\"100%\" stop-color=${dark} />\n </linearGradient>\n </defs>\n <circle cx=\"16\" cy=\"16\" r=\"13\" fill=\"url(#${this._gradId})\" stroke=\"#ffffff\" stroke-width=${this.ringWidth} />\n </svg>\n <div class=\"content\" style=\"font-size:${Math.round(this.size * 0.4)}px\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"map-circle\": MapCircle;\n }\n}\n"]}
1
+ {"version":3,"file":"map-circle.js","sourceRoot":"","sources":["../src/map-circle.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;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEI,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,UAAU;IAAlC;;QA+CL,4FAA4F;QAChF,UAAK,GAAG,SAAS,CAAC;QAC9B,+BAA+B;QACH,SAAI,GAAG,EAAE,CAAC;QACtC,wFAAwF;QACnC,cAAS,GAAG,CAAC,CAAC;QACnE,sFAAsF;QAC1C,gBAAW,GAAG,KAAK,CAAC;QAE/C,YAAO,GAAG,mBAAmB,iBAAiB,EAAE,EAAE,CAAC;IA2BtE,CAAC;aAlFiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyCF;KACF,AA5CqB,CA4CpB;IAaO,MAAM;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAA;;;gBAGC,IAAI,CAAC,IAAI;iBACR,IAAI,CAAC,IAAI;;;;;;+BAMK,IAAI,CAAC,OAAO;2CACA,KAAK;6CACH,IAAI;;;oDAGG,IAAI,CAAC,OAAO,oCAAoC,IAAI,CAAC,SAAS;;8CAEpE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;;;KAGpE,CAAC;IACJ,CAAC;CACF,CAAA;AAnCa;IAAX,QAAQ,EAAE;wCAAmB;AAEF;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uCAAW;AAEe;IAApD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;4CAAe;AAEvB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAqB;AAtDrD,SAAS;IADrB,aAAa,CAAC,YAAY,CAAC;GACf,SAAS,CAmFrB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\nimport { mixHex } from \"./utils/color.js\";\n\nlet gradientIdCounter = 0;\n\n/**\n * A plain circular map marker: a light-to-dark gradient fill with a white\n * outer ring, no point/tail (unlike `<map-pin>`) — for markers that don't\n * need to visually \"point\" at their exact coordinate. Purely a visual\n * primitive — it has no `mapbox-gl` (or any mapping library) dependency;\n * the consumer positions it, e.g. via `new mapboxgl.Marker({ element: el })`.\n * It can also replace the former `<map-point>` dense-layer primitive: use\n * `size=\"14\" ring-width=\"3\"`, leave the slot empty, and rasterize one marker\n * per color for use as a map `icon-image`.\n *\n * @element map-circle\n * @slot - Optional badge content shown centered on the circle — a rank\n * number, an emoji, a small icon.\n */\n@customElement(\"map-circle\")\nexport class MapCircle extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n line-height: 0;\n }\n svg {\n display: block;\n transition: transform 120ms ease, filter 120ms ease;\n }\n :host([highlighted]) svg {\n transform: scale(1.12);\n filter: brightness(1.08) drop-shadow(0 0 5px rgb(0 0 0 / 0.35));\n }\n .content {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #fff;\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-weight: var(--ui-font-weight-bold, 700);\n line-height: var(--ui-line-height-glyph, 1);\n text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);\n pointer-events: none;\n white-space: nowrap;\n }\n @media (prefers-reduced-motion: reduce) {\n svg {\n transition: none;\n }\n }\n `,\n ];\n\n /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */\n @property() color = \"#4f46e5\";\n /** Diameter, in CSS pixels. */\n @property({ type: Number }) size = 18;\n /** White outer ring thickness, in the same viewBox units as `size` (scales with it). */\n @property({ type: Number, attribute: \"ring-width\" }) ringWidth = 4;\n /** Scales and glows the circle — a generic emphasis state (e.g. hover, selection). */\n @property({ type: Boolean, reflect: true }) highlighted = false;\n\n private readonly _gradId = `map-circle-grad-${gradientIdCounter++}`;\n\n override render() {\n const light = mixHex(this.color, \"#ffffff\", 30);\n const dark = mixHex(this.color, \"#000000\", 30);\n return html`\n <svg\n aria-hidden=\"true\"\n width=${this.size}\n height=${this.size}\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=${this._gradId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=${light} />\n <stop offset=\"100%\" stop-color=${dark} />\n </linearGradient>\n </defs>\n <circle cx=\"16\" cy=\"16\" r=\"13\" fill=\"url(#${this._gradId})\" stroke=\"#ffffff\" stroke-width=${this.ringWidth} />\n </svg>\n <div class=\"content\" style=\"font-size:${Math.round(this.size * 0.4)}px\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"map-circle\": MapCircle;\n }\n}\n"]}
package/dist/map-pin.js CHANGED
@@ -65,8 +65,8 @@ let MapPin = class MapPin extends LitElement {
65
65
  "Segoe UI Symbol",
66
66
  "Noto Color Emoji"
67
67
  );
68
- font-weight: 700;
69
- line-height: 1;
68
+ font-weight: var(--ui-font-weight-bold, 700);
69
+ line-height: var(--ui-line-height-glyph, 1);
70
70
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);
71
71
  pointer-events: none;
72
72
  white-space: nowrap;
@@ -1 +1 @@
1
- {"version":3,"file":"map-pin.js","sourceRoot":"","sources":["../src/map-pin.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;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;GASG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,UAAU;IAA/B;;QAkDL,4FAA4F;QAChF,UAAK,GAAG,SAAS,CAAC;QAC9B,oDAAoD;QACxB,SAAI,GAAG,EAAE,CAAC;QACtC,mFAAmF;QACvC,gBAAW,GAAG,KAAK,CAAC;QAE/C,YAAO,GAAG,gBAAgB,iBAAiB,EAAE,EAAE,CAAC;IAiCnE,CAAC;aAzFiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4CF;KACF,AA/CqB,CA+CpB;IAWO,MAAM;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAA;;;gBAGC,IAAI,CAAC,IAAI;iBACR,MAAM;;;;;;+BAMQ,IAAI,CAAC,OAAO;2CACA,KAAK;6CACH,IAAI;;;;;uBAK1B,IAAI,CAAC,OAAO;;;;;8CAKW,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;;;KAGpE,CAAC;IACJ,CAAC;CACF,CAAA;AAvCa;IAAX,QAAQ,EAAE;qCAAmB;AAEF;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oCAAW;AAEM;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;2CAAqB;AAvDrD,MAAM;IADlB,aAAa,CAAC,SAAS,CAAC;GACZ,MAAM,CA0FlB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\nimport { mixHex } from \"./utils/color.js\";\n\nlet gradientIdCounter = 0;\n\n/**\n * A circular \"Apple Maps\"-style map pin: a light-to-dark gradient fill with\n * a slight point at the bottom. Purely a visual primitive — it has no\n * `mapbox-gl` (or any mapping library) dependency; the consumer positions\n * it, e.g. via `new mapboxgl.Marker({ element: pinEl })`.\n *\n * @element map-pin\n * @slot - Badge content shown centered on the pin's circular head — a rank\n * number, an emoji, a small icon.\n */\n@customElement(\"map-pin\")\nexport class MapPin extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n line-height: 0;\n }\n svg {\n display: block;\n transition: transform 120ms ease, filter 120ms ease;\n }\n :host([highlighted]) svg {\n transform: scale(1.12);\n filter: brightness(1.08) drop-shadow(0 0 5px rgb(0 0 0 / 0.35));\n }\n .content {\n position: absolute;\n /* The path's circular head is centered at viewBox y=13 of 34 total\n (13/34 ≈ 38%) — not the pin's full bounding box, which is pulled\n down by the point below the circle. */\n top: 38%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #fff;\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-weight: 700;\n line-height: 1;\n text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);\n pointer-events: none;\n white-space: nowrap;\n }\n @media (prefers-reduced-motion: reduce) {\n svg {\n transition: none;\n }\n }\n `,\n ];\n\n /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */\n @property() color = \"#4f46e5\";\n /** Diameter of the circular head, in CSS pixels. */\n @property({ type: Number }) size = 32;\n /** Scales and glows the pin — a generic emphasis state (e.g. hover, selection). */\n @property({ type: Boolean, reflect: true }) highlighted = false;\n\n private readonly _gradId = `map-pin-grad-${gradientIdCounter++}`;\n\n override render() {\n const light = mixHex(this.color, \"#ffffff\", 30);\n const dark = mixHex(this.color, \"#000000\", 30);\n const height = Math.round(this.size * (34 / 32));\n return html`\n <svg\n aria-hidden=\"true\"\n width=${this.size}\n height=${height}\n viewBox=\"0 0 32 34\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=${this._gradId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=${light} />\n <stop offset=\"100%\" stop-color=${dark} />\n </linearGradient>\n </defs>\n <path\n d=\"M16 30 C10 24 4 19.5 4 13 A12 12 0 1 1 28 13 C28 19.5 22 24 16 30 Z\"\n fill=\"url(#${this._gradId})\"\n stroke=\"#ffffff\"\n stroke-width=\"1.5\"\n />\n </svg>\n <div class=\"content\" style=\"font-size:${Math.round(this.size * 0.4)}px\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"map-pin\": MapPin;\n }\n}\n"]}
1
+ {"version":3,"file":"map-pin.js","sourceRoot":"","sources":["../src/map-pin.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;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;GASG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,UAAU;IAA/B;;QAkDL,4FAA4F;QAChF,UAAK,GAAG,SAAS,CAAC;QAC9B,oDAAoD;QACxB,SAAI,GAAG,EAAE,CAAC;QACtC,mFAAmF;QACvC,gBAAW,GAAG,KAAK,CAAC;QAE/C,YAAO,GAAG,gBAAgB,iBAAiB,EAAE,EAAE,CAAC;IAiCnE,CAAC;aAzFiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4CF;KACF,AA/CqB,CA+CpB;IAWO,MAAM;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAA;;;gBAGC,IAAI,CAAC,IAAI;iBACR,MAAM;;;;;;+BAMQ,IAAI,CAAC,OAAO;2CACA,KAAK;6CACH,IAAI;;;;;uBAK1B,IAAI,CAAC,OAAO;;;;;8CAKW,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;;;KAGpE,CAAC;IACJ,CAAC;CACF,CAAA;AAvCa;IAAX,QAAQ,EAAE;qCAAmB;AAEF;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oCAAW;AAEM;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;2CAAqB;AAvDrD,MAAM;IADlB,aAAa,CAAC,SAAS,CAAC;GACZ,MAAM,CA0FlB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\nimport { mixHex } from \"./utils/color.js\";\n\nlet gradientIdCounter = 0;\n\n/**\n * A circular \"Apple Maps\"-style map pin: a light-to-dark gradient fill with\n * a slight point at the bottom. Purely a visual primitive — it has no\n * `mapbox-gl` (or any mapping library) dependency; the consumer positions\n * it, e.g. via `new mapboxgl.Marker({ element: pinEl })`.\n *\n * @element map-pin\n * @slot - Badge content shown centered on the pin's circular head — a rank\n * number, an emoji, a small icon.\n */\n@customElement(\"map-pin\")\nexport class MapPin extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n position: relative;\n line-height: 0;\n }\n svg {\n display: block;\n transition: transform 120ms ease, filter 120ms ease;\n }\n :host([highlighted]) svg {\n transform: scale(1.12);\n filter: brightness(1.08) drop-shadow(0 0 5px rgb(0 0 0 / 0.35));\n }\n .content {\n position: absolute;\n /* The path's circular head is centered at viewBox y=13 of 34 total\n (13/34 ≈ 38%) — not the pin's full bounding box, which is pulled\n down by the point below the circle. */\n top: 38%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #fff;\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-weight: var(--ui-font-weight-bold, 700);\n line-height: var(--ui-line-height-glyph, 1);\n text-shadow: 0 1px 2px rgb(0 0 0 / 0.35);\n pointer-events: none;\n white-space: nowrap;\n }\n @media (prefers-reduced-motion: reduce) {\n svg {\n transition: none;\n }\n }\n `,\n ];\n\n /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */\n @property() color = \"#4f46e5\";\n /** Diameter of the circular head, in CSS pixels. */\n @property({ type: Number }) size = 32;\n /** Scales and glows the pin — a generic emphasis state (e.g. hover, selection). */\n @property({ type: Boolean, reflect: true }) highlighted = false;\n\n private readonly _gradId = `map-pin-grad-${gradientIdCounter++}`;\n\n override render() {\n const light = mixHex(this.color, \"#ffffff\", 30);\n const dark = mixHex(this.color, \"#000000\", 30);\n const height = Math.round(this.size * (34 / 32));\n return html`\n <svg\n aria-hidden=\"true\"\n width=${this.size}\n height=${height}\n viewBox=\"0 0 32 34\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=${this._gradId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=${light} />\n <stop offset=\"100%\" stop-color=${dark} />\n </linearGradient>\n </defs>\n <path\n d=\"M16 30 C10 24 4 19.5 4 13 A12 12 0 1 1 28 13 C28 19.5 22 24 16 30 Z\"\n fill=\"url(#${this._gradId})\"\n stroke=\"#ffffff\"\n stroke-width=\"1.5\"\n />\n </svg>\n <div class=\"content\" style=\"font-size:${Math.round(this.size * 0.4)}px\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"map-pin\": MapPin;\n }\n}\n"]}
@@ -115,7 +115,7 @@ let PercentBarChart = class PercentBarChart extends LitElement {
115
115
  <text class="chart-label" x=${PAD.left} y=${cy} font-size="10"
116
116
  text-anchor="start" dominant-baseline="middle">${g.label}</text>
117
117
  <rect x=${PAD.left + LABEL_W} y=${cy - 5}
118
- width=${bw} height="10" rx="2"
118
+ width=${bw} height="10" rx="5"
119
119
  fill=${rowFills[i].fill} />
120
120
  <text class="chart-label" x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size="10"
121
121
  text-anchor="start" dominant-baseline="middle">${g.pct.toFixed(1)}%</text>