@f-ewald/components 0.7.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -47
- package/custom-elements.json +3049 -910
- package/dist/address-autocomplete.d.ts +8 -0
- package/dist/address-autocomplete.d.ts.map +1 -1
- package/dist/address-autocomplete.js +165 -15
- package/dist/address-autocomplete.js.map +1 -1
- package/dist/animate-confetti.d.ts +8 -5
- package/dist/animate-confetti.d.ts.map +1 -1
- package/dist/animate-confetti.js +46 -19
- package/dist/animate-confetti.js.map +1 -1
- package/dist/autocomplete-input.d.ts +8 -0
- package/dist/autocomplete-input.d.ts.map +1 -1
- package/dist/autocomplete-input.js +165 -15
- package/dist/autocomplete-input.js.map +1 -1
- package/dist/calendar-entry.d.ts +33 -0
- package/dist/calendar-entry.d.ts.map +1 -0
- package/dist/calendar-entry.js +64 -0
- package/dist/calendar-entry.js.map +1 -0
- package/dist/calendar-month.d.ts +67 -0
- package/dist/calendar-month.d.ts.map +1 -0
- package/dist/calendar-month.js +469 -0
- package/dist/calendar-month.js.map +1 -0
- package/dist/calendar-year.d.ts +43 -0
- package/dist/calendar-year.d.ts.map +1 -0
- package/dist/calendar-year.js +145 -0
- package/dist/calendar-year.js.map +1 -0
- package/dist/chat-message.d.ts.map +1 -1
- package/dist/chat-message.js +77 -24
- package/dist/chat-message.js.map +1 -1
- package/dist/confirm-dialog.d.ts +8 -1
- package/dist/confirm-dialog.d.ts.map +1 -1
- package/dist/confirm-dialog.js +130 -18
- package/dist/confirm-dialog.js.map +1 -1
- package/dist/copy-link-button.d.ts +2 -0
- package/dist/copy-link-button.d.ts.map +1 -1
- package/dist/copy-link-button.js +35 -3
- package/dist/copy-link-button.js.map +1 -1
- package/dist/data-table.d.ts +2 -0
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +83 -11
- package/dist/data-table.js.map +1 -1
- package/dist/distance-value.d.ts +0 -1
- package/dist/distance-value.d.ts.map +1 -1
- package/dist/distance-value.js +3 -8
- package/dist/distance-value.js.map +1 -1
- package/dist/distribution-chart.d.ts.map +1 -1
- package/dist/distribution-chart.js +54 -17
- package/dist/distribution-chart.js.map +1 -1
- package/dist/dropdown-button.d.ts.map +1 -1
- package/dist/dropdown-button.js +60 -11
- package/dist/dropdown-button.js.map +1 -1
- package/dist/editable-text.d.ts.map +1 -1
- package/dist/editable-text.js +46 -13
- package/dist/editable-text.js.map +1 -1
- package/dist/form-select.d.ts +21 -2
- package/dist/form-select.d.ts.map +1 -1
- package/dist/form-select.js +489 -37
- package/dist/form-select.js.map +1 -1
- package/dist/frame-box.d.ts.map +1 -1
- package/dist/frame-box.js +20 -12
- package/dist/frame-box.js.map +1 -1
- package/dist/icon-button.d.ts.map +1 -1
- package/dist/icon-button.js +11 -0
- package/dist/icon-button.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/kbd-hint.d.ts +30 -0
- package/dist/kbd-hint.d.ts.map +1 -0
- package/dist/kbd-hint.js +184 -0
- package/dist/kbd-hint.js.map +1 -0
- package/dist/live-timer.d.ts +0 -1
- package/dist/live-timer.d.ts.map +1 -1
- package/dist/live-timer.js +1 -6
- package/dist/live-timer.js.map +1 -1
- package/dist/map-circle.d.ts +3 -0
- package/dist/map-circle.d.ts.map +1 -1
- package/dist/map-circle.js +19 -1
- package/dist/map-circle.js.map +1 -1
- package/dist/map-pin.d.ts.map +1 -1
- package/dist/map-pin.js +16 -1
- package/dist/map-pin.js.map +1 -1
- package/dist/percent-bar-chart.d.ts +3 -0
- package/dist/percent-bar-chart.d.ts.map +1 -1
- package/dist/percent-bar-chart.js +60 -4
- package/dist/percent-bar-chart.js.map +1 -1
- package/dist/photo-gallery.d.ts.map +1 -1
- package/dist/photo-gallery.js +12 -3
- package/dist/photo-gallery.js.map +1 -1
- package/dist/popover-panel.d.ts.map +1 -1
- package/dist/popover-panel.js +132 -23
- package/dist/popover-panel.js.map +1 -1
- package/dist/price-history-chart.d.ts.map +1 -1
- package/dist/price-history-chart.js +52 -18
- package/dist/price-history-chart.js.map +1 -1
- package/dist/radio-cards.d.ts +2 -0
- package/dist/radio-cards.d.ts.map +1 -1
- package/dist/radio-cards.js +51 -5
- package/dist/radio-cards.js.map +1 -1
- package/dist/radio-pills.d.ts +2 -0
- package/dist/radio-pills.d.ts.map +1 -1
- package/dist/radio-pills.js +46 -4
- package/dist/radio-pills.js.map +1 -1
- package/dist/relative-time.d.ts +0 -1
- package/dist/relative-time.d.ts.map +1 -1
- package/dist/relative-time.js +1 -6
- package/dist/relative-time.js.map +1 -1
- package/dist/reveal-button.d.ts +2 -0
- package/dist/reveal-button.d.ts.map +1 -1
- package/dist/reveal-button.js +42 -5
- package/dist/reveal-button.js.map +1 -1
- package/dist/roman-numeral.js +1 -1
- package/dist/roman-numeral.js.map +1 -1
- package/dist/slide-panel.d.ts +7 -3
- package/dist/slide-panel.d.ts.map +1 -1
- package/dist/slide-panel.js +95 -23
- package/dist/slide-panel.js.map +1 -1
- package/dist/stat-meter.d.ts.map +1 -1
- package/dist/stat-meter.js +17 -7
- package/dist/stat-meter.js.map +1 -1
- package/dist/status-pill.d.ts.map +1 -1
- package/dist/status-pill.js +26 -12
- package/dist/status-pill.js.map +1 -1
- package/dist/tile-grid.d.ts +8 -0
- package/dist/tile-grid.d.ts.map +1 -1
- package/dist/tile-grid.js +88 -12
- package/dist/tile-grid.js.map +1 -1
- package/dist/toast-notification.d.ts.map +1 -1
- package/dist/toast-notification.js +40 -11
- package/dist/toast-notification.js.map +1 -1
- package/dist/tokens.css +23 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +16 -0
- package/dist/tokens.js.map +1 -1
- package/dist/ui-button.d.ts +2 -0
- package/dist/ui-button.d.ts.map +1 -1
- package/dist/ui-button.js +58 -9
- package/dist/ui-button.js.map +1 -1
- package/dist/user-avatar.d.ts.map +1 -1
- package/dist/user-avatar.js +18 -3
- package/dist/user-avatar.js.map +1 -1
- package/dist/utils/calendar.d.ts +77 -0
- package/dist/utils/calendar.d.ts.map +1 -0
- package/dist/utils/calendar.js +135 -0
- package/dist/utils/calendar.js.map +1 -0
- package/dist/utils/form.d.ts +3 -0
- package/dist/utils/form.d.ts.map +1 -0
- package/dist/utils/form.js +14 -0
- package/dist/utils/form.js.map +1 -0
- package/dist/utils/layer-stack.d.ts +9 -0
- package/dist/utils/layer-stack.d.ts.map +1 -0
- package/dist/utils/layer-stack.js +35 -0
- package/dist/utils/layer-stack.js.map +1 -0
- package/dist/weight-bar-chart.d.ts.map +1 -1
- package/dist/weight-bar-chart.js +27 -8
- package/dist/weight-bar-chart.js.map +1 -1
- package/docs/address-autocomplete.md +5 -0
- package/docs/autocomplete-input.md +5 -0
- package/docs/calendar-entry.md +53 -0
- package/docs/calendar-month.md +79 -0
- package/docs/calendar-year.md +53 -0
- package/docs/chat-message.md +4 -0
- package/docs/confirm-dialog.md +2 -0
- package/docs/copy-link-button.md +2 -0
- package/docs/data-table.md +2 -0
- package/docs/design-language.md +149 -0
- package/docs/distribution-chart.md +4 -0
- package/docs/dropdown-button.md +1 -0
- package/docs/form-select.md +15 -3
- package/docs/frame-box.md +2 -0
- package/docs/kbd-hint.md +42 -0
- package/docs/map-circle.md +4 -0
- package/docs/percent-bar-chart.md +4 -1
- package/docs/photo-gallery.md +1 -0
- package/docs/popover-panel.md +2 -0
- package/docs/price-history-chart.md +8 -1
- package/docs/radio-cards.md +2 -0
- package/docs/radio-pills.md +2 -0
- package/docs/reveal-button.md +3 -0
- package/docs/slide-panel.md +4 -2
- package/docs/status-pill.md +3 -0
- package/docs/tile-grid.md +10 -1
- package/docs/toast-notification.md +4 -1
- package/docs/ui-button.md +2 -0
- package/docs/user-avatar.md +1 -0
- package/llms.txt +175 -61
- package/package.json +14 -2
- package/dist/map-point.d.ts +0 -31
- package/dist/map-point.d.ts.map +0 -1
- package/dist/map-point.js +0 -83
- package/dist/map-point.js.map +0 -1
- package/docs/map-point.md +0 -44
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm-dialog.js","sourceRoot":"","sources":["../src/confirm-dialog.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;GAUG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAAtC;;QA8GL,qCAAqC;QACR,SAAI,GAAG,KAAK,CAAC;QAC1C,oCAAoC;QACM,iBAAY,GAAG,QAAQ,CAAC;QAClE,mCAAmC;QACM,gBAAW,GAAG,QAAQ,CAAC;QAChE,wEAAwE;QAC3C,WAAM,GAAG,IAAI,CAAC;QAC3C,8EAA8E;QACjD,SAAI,GAAG,KAAK,CAAC;QAC1C,gEAAgE;QACpD,UAAK,GAAkB,IAAI,CAAC;IA0B1C,CAAC;aAlJiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwGF;KACF,AA3GqB,CA2GpB;IAeM,QAAQ;QACd,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACpF,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;4BACa,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;;;YAGvC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,yBAAyB,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO;;mDAE7B,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW;4BAC3E,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,cAAc,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,QAAQ;gBACrG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA,sBAAsB,aAAa,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY;;;;;KAK1G,CAAC;IACJ,CAAC;CACF,CAAA;AApC8B;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;2CAAc;AAEA;IAAzC,QAAQ,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;mDAAyB;AAEzB;IAAxC,QAAQ,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;kDAAwB;AAEnC;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;6CAAe;AAEd;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;2CAAc;AAE9B;IAAX,QAAQ,EAAE;4CAA6B;AAzH7B,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAmJzB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconArrowPath } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Reusable confirmation dialog: overlay + centered card with a slotted body,\n * an optional error line, and Cancel/Confirm actions. Instant `display:none`\n * → `display:flex` toggle (no transitions). Fires `confirm`/`cancel`\n * (bubbling, composed) instead of owning any deletion logic itself —\n * callers stay in charge of the request.\n *\n * @element confirm-dialog\n * @fires confirm - User clicked the confirm button.\n * @fires cancel - User clicked the cancel button.\n */\n@customElement(\"confirm-dialog\")\nexport class ConfirmDialog extends LitElement {\n static override styles = [\n tokens,\n css`\n .overlay {\n position: fixed;\n inset: 0;\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n z-index: 50;\n display: none;\n align-items: flex-start;\n justify-content: center;\n padding: 10vh 20px 20px;\n box-sizing: border-box;\n }\n .overlay.open {\n display: flex;\n }\n .dialog {\n background: var(--ui-surface, #fff);\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: var(\n --ui-shadow-lg,\n 0 20px 25px -5px rgb(0 0 0 / 0.1),\n 0 8px 10px -6px rgb(0 0 0 / 0.1)\n );\n width: 100%;\n max-width: 420px;\n padding: 1.25rem;\n box-sizing: border-box;\n }\n .dialog-text {\n margin: 0 0 1rem;\n color: var(--ui-text, #0f172a);\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n font-size: var(--ui-font-size, 0.875rem);\n line-height: 1.45;\n }\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.6rem;\n }\n .btn-cancel {\n background: none;\n border: 1px solid var(--ui-border, #e2e8f0);\n color: var(--ui-text, #0f172a);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 0.9rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n cursor: pointer;\n font-family: inherit;\n }\n .btn-cancel:hover:not(:disabled) {\n border-color: var(--ui-text-muted, #64748b);\n }\n .btn-danger,\n .btn-primary {\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 0.9rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n font-family: inherit;\n }\n .btn-danger {\n background: var(--ui-danger, #dc2626);\n color: #fff;\n }\n .btn-danger:hover:not(:disabled) {\n background: var(--ui-danger-hover, #b91c1c);\n }\n .btn-primary {\n background: var(--ui-primary, #4f46e5);\n color: #fff;\n }\n .btn-primary:hover:not(:disabled) {\n background: var(--ui-primary-hover, #4338ca);\n }\n button:disabled {\n opacity: 0.6;\n cursor: default;\n }\n .error-text {\n color: var(--ui-danger, #dc2626);\n font-size: var(--ui-font-size-sm, 0.75rem);\n margin: 0.4rem 0 0.8rem;\n }\n .spin {\n display: inline-flex;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n @media (max-width: 768px) {\n .overlay {\n padding: 12px;\n overflow-y: auto;\n }\n }\n `,\n ];\n\n /** Whether the dialog is visible. */\n @property({ type: Boolean }) open = false;\n /** Label for the confirm button. */\n @property({ attribute: \"confirm-label\" }) confirmLabel = \"Delete\";\n /** Label for the cancel button. */\n @property({ attribute: \"cancel-label\" }) cancelLabel = \"Cancel\";\n /** Danger (red) vs. primary (indigo) styling for the confirm button. */\n @property({ type: Boolean }) danger = true;\n /** Shows a spinner and disables both buttons while a request is in flight. */\n @property({ type: Boolean }) busy = false;\n /** Inline error line shown below the body, or null for none. */\n @property() error: string | null = null;\n\n private _confirm() {\n this.dispatchEvent(new CustomEvent(\"confirm\", { bubbles: true, composed: true }));\n }\n\n private _cancel() {\n this.dispatchEvent(new CustomEvent(\"cancel\", { bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <div class=\"overlay ${this.open ? \"open\" : \"\"}\">\n <div class=\"dialog\">\n <p class=\"dialog-text\"><slot></slot></p>\n ${this.error ? html`<p class=\"error-text\">${this.error}</p>` : nothing}\n <div class=\"dialog-actions\">\n <button class=\"btn-cancel\" ?disabled=${this.busy} @click=${this._cancel}>${this.cancelLabel}</button>\n <button class=${this.danger ? \"btn-danger\" : \"btn-primary\"} ?disabled=${this.busy} @click=${this._confirm}>\n ${this.busy ? html`<span class=\"spin\">${iconArrowPath(14)}</span>` : nothing} ${this.confirmLabel}\n </button>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"confirm-dialog\": ConfirmDialog;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"confirm-dialog.js","sourceRoot":"","sources":["../src/confirm-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconArrowPath } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\nimport {\n activateLayer,\n claimEscape,\n deactivateLayer,\n isTopLayer,\n} from \"./utils/layer-stack.js\";\n\n/**\n * Reusable confirmation dialog: overlay + centered card with a slotted body,\n * an optional error line, and Cancel/Confirm actions. Instant `display:none`\n * → `display:flex` toggle (no transitions). Fires `confirm`/`cancel`\n * (bubbling, composed) instead of owning any deletion logic itself —\n * callers stay in charge of the request.\n *\n * @element confirm-dialog\n * @fires confirm - User clicked the confirm button.\n * @fires cancel - User clicked the cancel button.\n */\n@customElement(\"confirm-dialog\")\nexport class ConfirmDialog extends LitElement {\n static override styles = [\n tokens,\n css`\n .overlay {\n position: fixed;\n inset: 0;\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n z-index: var(--component-layer-z, 50);\n display: none;\n align-items: flex-start;\n justify-content: center;\n padding: 10vh 1.25rem 1.25rem;\n box-sizing: border-box;\n }\n .overlay.open {\n display: flex;\n }\n .dialog {\n background: var(--ui-surface, #ffffff);\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: var(\n --ui-shadow-lg,\n 0 20px 25px -5px rgb(0 0 0 / 0.1),\n 0 8px 10px -6px rgb(0 0 0 / 0.1)\n );\n width: 100%;\n max-width: 26.25rem;\n padding: 1.25rem;\n box-sizing: border-box;\n outline: none;\n }\n .dialog-text {\n margin: 0 0 1rem;\n color: var(--ui-text, #0f172a);\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, 0.875rem);\n line-height: 1.45;\n }\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: 0.5rem;\n }\n .btn-cancel {\n background: none;\n border: 1px solid var(--ui-border, #e2e8f0);\n color: var(--ui-text, #0f172a);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 1rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n cursor: pointer;\n font-family: inherit;\n }\n .btn-cancel:hover:not(:disabled) {\n border-color: var(--ui-text-muted, #64748b);\n }\n .btn-danger,\n .btn-primary {\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 1rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-family: inherit;\n }\n .btn-danger {\n background: var(--ui-danger, #dc2626);\n color: var(--ui-on-accent, #ffffff);\n }\n .btn-danger:hover:not(:disabled) {\n background: var(--ui-danger-hover, #b91c1c);\n }\n .btn-primary {\n background: var(--ui-primary, #4f46e5);\n color: var(--ui-on-accent, #ffffff);\n }\n .btn-primary:hover:not(:disabled) {\n background: var(--ui-primary-hover, #4338ca);\n }\n button:disabled {\n opacity: 0.6;\n cursor: default;\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 .error-text {\n color: var(--ui-danger, #dc2626);\n font-size: var(--ui-font-size-sm, 0.75rem);\n margin: 0.5rem 0 0.75rem;\n }\n .spin {\n display: inline-flex;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .spin {\n animation: none;\n }\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 }\n @media (max-width: 48rem) {\n .overlay {\n padding: 0.75rem;\n overflow-y: auto;\n }\n }\n `,\n ];\n\n /** Whether the dialog is visible. */\n @property({ type: Boolean }) open = false;\n /** Label for the confirm button. */\n @property({ attribute: \"confirm-label\" }) confirmLabel = \"Delete\";\n /** Label for the cancel button. */\n @property({ attribute: \"cancel-label\" }) cancelLabel = \"Cancel\";\n /** Danger (red) vs. primary (indigo) styling for the confirm button. */\n @property({ type: Boolean }) danger = true;\n /** Shows a spinner and disables both buttons while a request is in flight. */\n @property({ type: Boolean }) busy = false;\n /** Inline error line shown below the body, or null for none. */\n @property() error: string | null = null;\n\n private _previousFocus: HTMLElement | null = null;\n\n private _confirm() {\n this.dispatchEvent(new CustomEvent(\"confirm\", { bubbles: true, composed: true }));\n }\n\n private _cancel() {\n this.dispatchEvent(new CustomEvent(\"cancel\", { bubbles: true, composed: true }));\n }\n\n private _getFocusableElements(): HTMLElement[] {\n const selector =\n \"a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex='-1'])\";\n const slotted = Array.from(this.querySelectorAll<HTMLElement>(selector));\n const internal = Array.from(\n this.shadowRoot?.querySelectorAll<HTMLElement>(selector) ?? [],\n ).filter((element) => element.closest(\".dialog\") !== null);\n return [...slotted, ...internal].filter((element) => !element.hasAttribute(\"hidden\"));\n }\n\n private _focusInitial(): void {\n const autofocus = this.querySelector<HTMLElement>(\"[autofocus]\");\n const cancel = this.shadowRoot?.querySelector<HTMLElement>(\".btn-cancel:not(:disabled)\");\n const dialog = this.shadowRoot?.querySelector<HTMLElement>(\".dialog\");\n (autofocus ?? cancel ?? this._getFocusableElements()[0] ?? dialog)?.focus();\n }\n\n private _onDocumentFocusIn = (event: FocusEvent): void => {\n if (!this.open || !isTopLayer(this) || event.composedPath().includes(this)) return;\n this._focusInitial();\n };\n\n private _onWindowKeydown = (event: KeyboardEvent): void => {\n if (!this.open || !isTopLayer(this)) return;\n if (claimEscape(this, event) && !this.busy) {\n this._cancel();\n return;\n }\n if (event.key !== \"Tab\") return;\n\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) {\n event.preventDefault();\n this._focusInitial();\n return;\n }\n const active = (this.shadowRoot?.activeElement ?? document.activeElement) as HTMLElement | null;\n const index = focusable.indexOf(active as HTMLElement);\n if (event.shiftKey && index <= 0) {\n event.preventDefault();\n focusable.at(-1)?.focus();\n } else if (!event.shiftKey && index === focusable.length - 1) {\n event.preventDefault();\n focusable[0]?.focus();\n }\n };\n\n protected override updated(changed: PropertyValues): void {\n if (!changed.has(\"open\")) return;\n if (this.open) {\n activateLayer(this);\n this._previousFocus = document.activeElement as HTMLElement | null;\n document.addEventListener(\"focusin\", this._onDocumentFocusIn, true);\n window.addEventListener(\"keydown\", this._onWindowKeydown, true);\n this._focusInitial();\n return;\n }\n deactivateLayer(this);\n document.removeEventListener(\"focusin\", this._onDocumentFocusIn, true);\n window.removeEventListener(\"keydown\", this._onWindowKeydown, true);\n if (this._previousFocus?.isConnected) this._previousFocus.focus();\n this._previousFocus = null;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener(\"focusin\", this._onDocumentFocusIn, true);\n window.removeEventListener(\"keydown\", this._onWindowKeydown, true);\n deactivateLayer(this);\n if (this._previousFocus?.isConnected) this._previousFocus.focus();\n this._previousFocus = null;\n this.open = false;\n }\n\n override render() {\n const accessibleName = this.getAttribute(\"aria-label\") ?? \"Confirmation\";\n return html`\n <div class=\"overlay ${this.open ? \"open\" : \"\"}\">\n <div\n class=\"dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=${accessibleName}\n aria-describedby=${this.error ? \"dialog-text dialog-error\" : \"dialog-text\"}\n tabindex=\"-1\"\n >\n <p id=\"dialog-text\" class=\"dialog-text\"><slot></slot></p>\n ${this.error\n ? html`<p id=\"dialog-error\" class=\"error-text\" role=\"alert\">${this.error}</p>`\n : nothing}\n <div class=\"dialog-actions\">\n <button class=\"btn-cancel\" ?disabled=${this.busy} @click=${this._cancel}>${this.cancelLabel}</button>\n <button class=${this.danger ? \"btn-danger\" : \"btn-primary\"} ?disabled=${this.busy} @click=${this._confirm}>\n ${this.busy\n ? html`<span class=\"spin\" aria-hidden=\"true\">${iconArrowPath(14)}</span>`\n : nothing}\n ${this.confirmLabel}\n </button>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"confirm-dialog\": ConfirmDialog;\n }\n}\n"]}
|
|
@@ -15,6 +15,8 @@ export declare class CopyLinkButton extends LitElement {
|
|
|
15
15
|
value: string;
|
|
16
16
|
/** Accessible label / tooltip text. */
|
|
17
17
|
label: string;
|
|
18
|
+
/** Disables clipboard copying. */
|
|
19
|
+
disabled: boolean;
|
|
18
20
|
static styles: import("lit").CSSResult[];
|
|
19
21
|
private _onClick;
|
|
20
22
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-link-button.d.ts","sourceRoot":"","sources":["../src/copy-link-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAM5C;;;;;;;;;;GAUG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,sEAAsE;IAC1D,KAAK,SAAM;IACvB,uCAAuC;IAC3B,KAAK,SAAe;
|
|
1
|
+
{"version":3,"file":"copy-link-button.d.ts","sourceRoot":"","sources":["../src/copy-link-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAM5C;;;;;;;;;;GAUG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,sEAAsE;IAC1D,KAAK,SAAM;IACvB,uCAAuC;IAC3B,KAAK,SAAe;IAChC,kCAAkC;IACL,QAAQ,UAAS;IAE9C,OAAgB,MAAM,4BAyCpB;YAEY,QAAQ;IAab,MAAM,yCAYd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
|
package/dist/copy-link-button.js
CHANGED
|
@@ -27,6 +27,8 @@ let CopyLinkButton = class CopyLinkButton extends LitElement {
|
|
|
27
27
|
this.value = "";
|
|
28
28
|
/** Accessible label / tooltip text. */
|
|
29
29
|
this.label = "Copy link";
|
|
30
|
+
/** Disables clipboard copying. */
|
|
31
|
+
this.disabled = false;
|
|
30
32
|
}
|
|
31
33
|
static { this.styles = [
|
|
32
34
|
tokens,
|
|
@@ -38,20 +40,41 @@ let CopyLinkButton = class CopyLinkButton extends LitElement {
|
|
|
38
40
|
background: none;
|
|
39
41
|
border: none;
|
|
40
42
|
cursor: pointer;
|
|
41
|
-
padding:
|
|
43
|
+
padding: 0.25rem;
|
|
42
44
|
color: var(--ui-text-muted, #64748b);
|
|
43
45
|
border-radius: var(--ui-radius-sm, 0.25rem);
|
|
44
46
|
display: inline-flex;
|
|
45
47
|
align-items: center;
|
|
46
48
|
justify-content: center;
|
|
47
49
|
}
|
|
48
|
-
button:hover {
|
|
50
|
+
button:hover:not(:disabled) {
|
|
49
51
|
background: var(--ui-surface-muted, #f8fafc);
|
|
50
52
|
color: var(--ui-text, #0f172a);
|
|
51
53
|
}
|
|
54
|
+
button:disabled {
|
|
55
|
+
cursor: not-allowed;
|
|
56
|
+
opacity: 0.6;
|
|
57
|
+
}
|
|
58
|
+
button:focus-visible {
|
|
59
|
+
outline: none;
|
|
60
|
+
box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
|
|
61
|
+
}
|
|
62
|
+
@media (forced-colors: active) {
|
|
63
|
+
button:focus-visible {
|
|
64
|
+
outline: 2px solid CanvasText;
|
|
65
|
+
outline-offset: 2px;
|
|
66
|
+
box-shadow: none;
|
|
67
|
+
}
|
|
68
|
+
button:disabled {
|
|
69
|
+
color: GrayText;
|
|
70
|
+
opacity: 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
52
73
|
`,
|
|
53
74
|
]; }
|
|
54
75
|
async _onClick() {
|
|
76
|
+
if (this.disabled)
|
|
77
|
+
return;
|
|
55
78
|
const text = this.value || window.location.href;
|
|
56
79
|
try {
|
|
57
80
|
await navigator.clipboard.writeText(text);
|
|
@@ -65,7 +88,13 @@ let CopyLinkButton = class CopyLinkButton extends LitElement {
|
|
|
65
88
|
}
|
|
66
89
|
render() {
|
|
67
90
|
return html `
|
|
68
|
-
<button
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
aria-label=${this.label}
|
|
94
|
+
title=${this.label}
|
|
95
|
+
?disabled=${this.disabled}
|
|
96
|
+
@click=${this._onClick}
|
|
97
|
+
>
|
|
69
98
|
${iconLink(16)}
|
|
70
99
|
</button>
|
|
71
100
|
`;
|
|
@@ -77,6 +106,9 @@ __decorate([
|
|
|
77
106
|
__decorate([
|
|
78
107
|
property()
|
|
79
108
|
], CopyLinkButton.prototype, "label", void 0);
|
|
109
|
+
__decorate([
|
|
110
|
+
property({ type: Boolean })
|
|
111
|
+
], CopyLinkButton.prototype, "disabled", void 0);
|
|
80
112
|
CopyLinkButton = __decorate([
|
|
81
113
|
customElement("copy-link-button")
|
|
82
114
|
], CopyLinkButton);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-link-button.js","sourceRoot":"","sources":["../src/copy-link-button.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,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;GAUG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QACL,sEAAsE;QAC1D,UAAK,GAAG,EAAE,CAAC;QACvB,uCAAuC;QAC3B,UAAK,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"copy-link-button.js","sourceRoot":"","sources":["../src/copy-link-button.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,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;GAUG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QACL,sEAAsE;QAC1D,UAAK,GAAG,EAAE,CAAC;QACvB,uCAAuC;QAC3B,UAAK,GAAG,WAAW,CAAC;QAChC,kCAAkC;QACL,aAAQ,GAAG,KAAK,CAAC;IAuEhD,CAAC;aArEiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCF;KACF,AAzCqB,CAyCpB;IAEM,KAAK,CAAC,QAAQ;QACpB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC1C,aAAa,CAAC,0BAA0B,CAAC,CAAC;YAC1C,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACzF,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,wBAAwB,CAAC,CAAC;YACtC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;;qBAGM,IAAI,CAAC,KAAK;gBACf,IAAI,CAAC,KAAK;oBACN,IAAI,CAAC,QAAQ;iBAChB,IAAI,CAAC,QAAQ;;UAEpB,QAAQ,CAAC,EAAE,CAAC;;KAEjB,CAAC;IACJ,CAAC;CACF,CAAA;AA3Ea;IAAX,QAAQ,EAAE;6CAAY;AAEX;IAAX,QAAQ,EAAE;6CAAqB;AAEH;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gDAAkB;AANnC,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CA6E1B","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconLink } from \"./icons.js\";\nimport { notifyError, notifySuccess } from \"./toast-notification.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Small icon button that copies `value` to the clipboard and shows a toast\n * on success/failure (if a `<toast-notification>` element is present), and\n * always dispatches a `copy-success`/`copy-error` CustomEvent so consumers\n * without a toast element can react. Defaults to the current page URL if\n * `value` is unset.\n *\n * @element copy-link-button\n * @fires copy-success - The value was copied to the clipboard.\n * @fires copy-error - Copying to the clipboard failed.\n */\n@customElement(\"copy-link-button\")\nexport class CopyLinkButton extends LitElement {\n /** Text to copy. Defaults to `window.location.href` at click time. */\n @property() value = \"\";\n /** Accessible label / tooltip text. */\n @property() label = \"Copy link\";\n /** Disables clipboard copying. */\n @property({ type: Boolean }) disabled = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n }\n button {\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem;\n color: var(--ui-text-muted, #64748b);\n border-radius: var(--ui-radius-sm, 0.25rem);\n display: inline-flex;\n align-items: center;\n justify-content: center;\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.6;\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 private async _onClick() {\n if (this.disabled) return;\n const text = this.value || window.location.href;\n try {\n await navigator.clipboard.writeText(text);\n notifySuccess(\"Link copied to clipboard\");\n this.dispatchEvent(new CustomEvent(\"copy-success\", { bubbles: true, composed: true }));\n } catch {\n notifyError(\"Couldn't copy the link\");\n this.dispatchEvent(new CustomEvent(\"copy-error\", { bubbles: true, composed: true }));\n }\n }\n\n override render() {\n return html`\n <button\n type=\"button\"\n aria-label=${this.label}\n title=${this.label}\n ?disabled=${this.disabled}\n @click=${this._onClick}\n >\n ${iconLink(16)}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"copy-link-button\": CopyLinkButton;\n }\n}\n"]}
|
package/dist/data-table.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare class DataTable extends LitElement {
|
|
|
29
29
|
renderCell: (row: unknown, key: string) => unknown;
|
|
30
30
|
/** When set, clicking a row (outside any nested link/button) navigates to this hash. */
|
|
31
31
|
rowHref: ((row: unknown) => string | null) | null;
|
|
32
|
+
/** Accessible label for a row's keyboard link; defaults to primitive cell values. */
|
|
33
|
+
rowLabel: ((row: unknown) => string) | null;
|
|
32
34
|
render(): import("lit-html").TemplateResult<1>;
|
|
33
35
|
}
|
|
34
36
|
declare global {
|
package/dist/data-table.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../src/data-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,yGAAyG;AACzG,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,qBACa,SAAU,SAAQ,UAAU;;IACvC,OAAgB,MAAM,4BA+
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../src/data-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,yGAAyG;AACzG,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,qBACa,SAAU,SAAQ,UAAU;;IACvC,OAAgB,MAAM,4BA+DpB;IAEF,wCAAwC;IACR,OAAO,EAAE,eAAe,EAAE,CAAM;IAChE,gFAAgF;IAChD,IAAI,EAAE,OAAO,EAAE,CAAM;IACrD,oGAAoG;IACpE,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAG7E;IACX,sFAAsF;IACtD,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAGvC;IAC3C,wFAAwF;IACxD,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAQ;IACzF,qFAAqF;IACrD,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC,GAAG,IAAI,CAAQ;IA4B1E,MAAM,yCA0Cd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,SAAS,CAAC;KACzB;CACF"}
|
package/dist/data-table.js
CHANGED
|
@@ -33,13 +33,24 @@ let DataTable = class DataTable extends LitElement {
|
|
|
33
33
|
this.renderCell = (row, key) => row[key];
|
|
34
34
|
/** When set, clicking a row (outside any nested link/button) navigates to this hash. */
|
|
35
35
|
this.rowHref = null;
|
|
36
|
+
/** Accessible label for a row's keyboard link; defaults to primitive cell values. */
|
|
37
|
+
this.rowLabel = null;
|
|
36
38
|
}
|
|
37
39
|
static { this.styles = [
|
|
38
40
|
tokens,
|
|
39
41
|
css `
|
|
40
42
|
:host {
|
|
41
43
|
display: block;
|
|
42
|
-
font-family: var(
|
|
44
|
+
font-family: var(
|
|
45
|
+
--ui-font,
|
|
46
|
+
ui-sans-serif,
|
|
47
|
+
system-ui,
|
|
48
|
+
sans-serif,
|
|
49
|
+
"Apple Color Emoji",
|
|
50
|
+
"Segoe UI Emoji",
|
|
51
|
+
"Segoe UI Symbol",
|
|
52
|
+
"Noto Color Emoji"
|
|
53
|
+
);
|
|
43
54
|
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
44
55
|
}
|
|
45
56
|
table {
|
|
@@ -54,27 +65,69 @@ let DataTable = class DataTable extends LitElement {
|
|
|
54
65
|
border-bottom: 1px solid var(--ui-border, #e2e8f0);
|
|
55
66
|
}
|
|
56
67
|
td {
|
|
57
|
-
padding: 0.
|
|
68
|
+
padding: 0.5rem 0.75rem;
|
|
58
69
|
border-bottom: 1px solid var(--ui-border, #e2e8f0);
|
|
59
70
|
color: var(--ui-text, #0f172a);
|
|
60
71
|
}
|
|
72
|
+
td:first-child {
|
|
73
|
+
position: relative;
|
|
74
|
+
}
|
|
75
|
+
.row-link {
|
|
76
|
+
position: absolute;
|
|
77
|
+
width: 1px;
|
|
78
|
+
height: 1px;
|
|
79
|
+
overflow: hidden;
|
|
80
|
+
clip: rect(0 0 0 0);
|
|
81
|
+
clip-path: inset(50%);
|
|
82
|
+
white-space: nowrap;
|
|
83
|
+
}
|
|
61
84
|
tbody tr.clickable {
|
|
62
85
|
cursor: pointer;
|
|
63
86
|
}
|
|
64
87
|
tbody tr.clickable:hover {
|
|
65
88
|
background: var(--ui-surface-muted, #f8fafc);
|
|
66
89
|
}
|
|
90
|
+
tbody tr.clickable:has(.row-link:focus-visible) {
|
|
91
|
+
outline: none;
|
|
92
|
+
box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35)) inset;
|
|
93
|
+
}
|
|
94
|
+
@media (forced-colors: active) {
|
|
95
|
+
tbody tr.clickable:has(.row-link:focus-visible) {
|
|
96
|
+
outline: 2px solid CanvasText;
|
|
97
|
+
outline-offset: -2px;
|
|
98
|
+
box-shadow: none;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
67
101
|
`,
|
|
68
102
|
]; }
|
|
69
103
|
#onRowClick(row, e) {
|
|
70
104
|
if (!this.rowHref)
|
|
71
105
|
return;
|
|
72
|
-
if (e.
|
|
106
|
+
if (this.#isNestedInteractive(e.composedPath(), e.currentTarget))
|
|
73
107
|
return;
|
|
74
108
|
const href = this.rowHref(row);
|
|
75
109
|
if (href)
|
|
76
110
|
location.hash = href;
|
|
77
111
|
}
|
|
112
|
+
#isNestedInteractive(path, row) {
|
|
113
|
+
const selector = "a, button, input, select, textarea, summary, [contenteditable], [role='button'], [role='link'], [tabindex]";
|
|
114
|
+
for (const target of path) {
|
|
115
|
+
if (target === row)
|
|
116
|
+
return false;
|
|
117
|
+
if (target instanceof HTMLElement && target.matches(selector))
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
#rowLinkLabel(row) {
|
|
123
|
+
const explicitLabel = this.rowLabel?.(row).trim();
|
|
124
|
+
if (explicitLabel)
|
|
125
|
+
return explicitLabel;
|
|
126
|
+
const values = this.columns
|
|
127
|
+
.map((column) => row[column.key])
|
|
128
|
+
.filter((value) => typeof value === "string" || typeof value === "number");
|
|
129
|
+
return values.length > 0 ? `Open ${values.join(", ")}` : "Open row";
|
|
130
|
+
}
|
|
78
131
|
render() {
|
|
79
132
|
return html `
|
|
80
133
|
<table>
|
|
@@ -84,14 +137,30 @@ let DataTable = class DataTable extends LitElement {
|
|
|
84
137
|
</tr>
|
|
85
138
|
</thead>
|
|
86
139
|
<tbody>
|
|
87
|
-
${repeat(this.rows, (row, i) => this.rowKey(row, i), (row) =>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
140
|
+
${repeat(this.rows, (row, i) => this.rowKey(row, i), (row) => {
|
|
141
|
+
const href = this.rowHref?.(row) ?? null;
|
|
142
|
+
return html `
|
|
143
|
+
<tr
|
|
144
|
+
class=${href ? "clickable" : ""}
|
|
145
|
+
@click=${(e) => this.#onRowClick(row, e)}
|
|
146
|
+
>
|
|
147
|
+
${this.columns.map((c, columnIndex) => html `
|
|
148
|
+
<td>
|
|
149
|
+
${href && columnIndex === 0
|
|
150
|
+
? html `
|
|
151
|
+
<a
|
|
152
|
+
class="row-link"
|
|
153
|
+
href=${href}
|
|
154
|
+
aria-label=${this.#rowLinkLabel(row)}
|
|
155
|
+
></a>
|
|
156
|
+
`
|
|
157
|
+
: nothing}
|
|
158
|
+
${this.renderCell(row, c.key) ?? nothing}
|
|
159
|
+
</td>
|
|
160
|
+
`)}
|
|
161
|
+
</tr>
|
|
162
|
+
`;
|
|
163
|
+
})}
|
|
95
164
|
</tbody>
|
|
96
165
|
</table>
|
|
97
166
|
`;
|
|
@@ -112,6 +181,9 @@ __decorate([
|
|
|
112
181
|
__decorate([
|
|
113
182
|
property({ attribute: false })
|
|
114
183
|
], DataTable.prototype, "rowHref", void 0);
|
|
184
|
+
__decorate([
|
|
185
|
+
property({ attribute: false })
|
|
186
|
+
], DataTable.prototype, "rowLabel", void 0);
|
|
115
187
|
DataTable = __decorate([
|
|
116
188
|
customElement("data-table")
|
|
117
189
|
], DataTable);
|
package/dist/data-table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.js","sourceRoot":"","sources":["../src/data-table.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC;;;;;;;;;;;GAWG;AAEI,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,UAAU;IAAlC;;
|
|
1
|
+
{"version":3,"file":"data-table.js","sourceRoot":"","sources":["../src/data-table.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** One column header: `key` is looked up via `renderCell`/`getCellValue`, `label` is the header text. */\nexport interface DataTableColumn {\n key: string;\n label: string;\n}\n\n/**\n * A generic, presentational table shell: renders a `<thead>` from `columns`\n * and one `<tr>` per entry in `rows`, with each cell's content produced by\n * `renderCell` (default: plain property lookup on the row object). Knows\n * nothing about what a \"row\" means — callers own the data shape entirely.\n *\n * Optional `rowHref` makes whole rows clickable (navigating via `location.hash`),\n * without hijacking clicks on nested interactive elements (links/buttons) a\n * cell's rendered content might contain.\n *\n * @element data-table\n */\n@customElement(\"data-table\")\nexport class DataTable extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\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 table {\n width: 100%;\n border-collapse: collapse;\n }\n th {\n text-align: left;\n font-weight: 600;\n color: var(--ui-text-muted, #64748b);\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n }\n td {\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n color: var(--ui-text, #0f172a);\n }\n td:first-child {\n position: relative;\n }\n .row-link {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n }\n tbody tr.clickable {\n cursor: pointer;\n }\n tbody tr.clickable:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n tbody tr.clickable:has(.row-link:focus-visible) {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35)) inset;\n }\n @media (forced-colors: active) {\n tbody tr.clickable:has(.row-link:focus-visible) {\n outline: 2px solid CanvasText;\n outline-offset: -2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n /** Column headers, in display order. */\n @property({ attribute: false }) columns: DataTableColumn[] = [];\n /** Row data; opaque to this component beyond what `renderCell` does with it. */\n @property({ attribute: false }) rows: unknown[] = [];\n /** Stable identity for `rows[i]`, used as the repeat-directive key. Defaults to the row's index. */\n @property({ attribute: false }) rowKey: (row: unknown, index: number) => string | number = (\n _row,\n index,\n ) => index;\n /** Produces a cell's rendered content for `row`/`column.key`. Default: `row[key]`. */\n @property({ attribute: false }) renderCell: (row: unknown, key: string) => unknown = (\n row,\n key,\n ) => (row as Record<string, unknown>)[key];\n /** When set, clicking a row (outside any nested link/button) navigates to this hash. */\n @property({ attribute: false }) rowHref: ((row: unknown) => string | null) | null = null;\n /** Accessible label for a row's keyboard link; defaults to primitive cell values. */\n @property({ attribute: false }) rowLabel: ((row: unknown) => string) | null = null;\n\n #onRowClick(row: unknown, e: MouseEvent): void {\n if (!this.rowHref) return;\n if (this.#isNestedInteractive(e.composedPath(), e.currentTarget)) return;\n const href = this.rowHref(row);\n if (href) location.hash = href;\n }\n\n #isNestedInteractive(path: EventTarget[], row: EventTarget | null): boolean {\n const selector =\n \"a, button, input, select, textarea, summary, [contenteditable], [role='button'], [role='link'], [tabindex]\";\n for (const target of path) {\n if (target === row) return false;\n if (target instanceof HTMLElement && target.matches(selector)) return true;\n }\n return false;\n }\n\n #rowLinkLabel(row: unknown): string {\n const explicitLabel = this.rowLabel?.(row).trim();\n if (explicitLabel) return explicitLabel;\n const values = this.columns\n .map((column) => (row as Record<string, unknown>)[column.key])\n .filter((value) => typeof value === \"string\" || typeof value === \"number\");\n return values.length > 0 ? `Open ${values.join(\", \")}` : \"Open row\";\n }\n\n override render() {\n return html`\n <table>\n <thead>\n <tr>\n ${this.columns.map((c) => html`<th>${c.label}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${repeat(\n this.rows,\n (row, i) => this.rowKey(row, i),\n (row) => {\n const href = this.rowHref?.(row) ?? null;\n return html`\n <tr\n class=${href ? \"clickable\" : \"\"}\n @click=${(e: MouseEvent) => this.#onRowClick(row, e)}\n >\n ${this.columns.map(\n (c, columnIndex) => html`\n <td>\n ${href && columnIndex === 0\n ? html`\n <a\n class=\"row-link\"\n href=${href}\n aria-label=${this.#rowLinkLabel(row)}\n ></a>\n `\n : nothing}\n ${this.renderCell(row, c.key) ?? nothing}\n </td>\n `,\n )}\n </tr>\n `;\n },\n )}\n </tbody>\n </table>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"data-table\": DataTable;\n }\n}\n"]}
|
package/dist/distance-value.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { LitElement, nothing } from "lit";
|
|
|
9
9
|
* @element distance-value
|
|
10
10
|
*/
|
|
11
11
|
export declare class DistanceValue extends LitElement {
|
|
12
|
-
static styles: import("lit").CSSResult;
|
|
13
12
|
/** Distance in miles (imperial). Switches to feet below 0.25 mi. */
|
|
14
13
|
miles: number | null;
|
|
15
14
|
/** Distance in kilometers (metric, future). Switches to meters below 0.5 km. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distance-value.d.ts","sourceRoot":"","sources":["../src/distance-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"distance-value.d.ts","sourceRoot":"","sources":["../src/distance-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,OAAO,EAAE,MAAM,KAAK,CAAC;AAIhD;;;;;;;;GAQG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,oEAAoE;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExD,gFAAgF;IACpD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE5C,MAAM,0DAId;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,aAAa,CAAC;KACjC;CACF"}
|
package/dist/distance-value.js
CHANGED
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { LitElement,
|
|
7
|
+
import { LitElement, html, nothing } from "lit";
|
|
8
8
|
import { customElement, property } from "lit/decorators.js";
|
|
9
9
|
import { formatMiles, formatKm } from "./utils/distance.js";
|
|
10
10
|
/**
|
|
@@ -24,16 +24,11 @@ let DistanceValue = class DistanceValue extends LitElement {
|
|
|
24
24
|
/** Distance in kilometers (metric, future). Switches to meters below 0.5 km. */
|
|
25
25
|
this.km = null;
|
|
26
26
|
}
|
|
27
|
-
static { this.styles = css `
|
|
28
|
-
:host {
|
|
29
|
-
display: inline;
|
|
30
|
-
}
|
|
31
|
-
`; }
|
|
32
27
|
render() {
|
|
33
28
|
if (this.km != null)
|
|
34
|
-
return html `${formatKm(this.km)}
|
|
29
|
+
return Number.isFinite(this.km) ? html `${formatKm(this.km)}` : nothing;
|
|
35
30
|
if (this.miles != null)
|
|
36
|
-
return html `${formatMiles(this.miles)}
|
|
31
|
+
return Number.isFinite(this.miles) ? html `${formatMiles(this.miles)}` : nothing;
|
|
37
32
|
return nothing;
|
|
38
33
|
}
|
|
39
34
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distance-value.js","sourceRoot":"","sources":["../src/distance-value.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"distance-value.js","sourceRoot":"","sources":["../src/distance-value.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;;;;;;;GAQG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAAtC;;QACL,oEAAoE;QACxC,UAAK,GAAkB,IAAI,CAAC;QAExD,gFAAgF;QACpD,OAAE,GAAkB,IAAI,CAAC;IAOvD,CAAC;IALU,MAAM;QACb,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC5F,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACxG,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAA;AAV6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAA6B;AAG5B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAA0B;AAL1C,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAYzB","sourcesContent":["import { LitElement, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { formatMiles, formatKm } from \"./utils/distance.js\";\n\n/**\n * Inline distance display. Renders miles/feet or km/m, switching units at\n * sensible thresholds (< 0.25 mi → ft; < 0.5 km → m).\n *\n * Supply exactly one of `miles` or `km`; the other stays null.\n * km support is present but reserved for future use.\n *\n * @element distance-value\n */\n@customElement(\"distance-value\")\nexport class DistanceValue extends LitElement {\n /** Distance in miles (imperial). Switches to feet below 0.25 mi. */\n @property({ type: Number }) miles: number | null = null;\n\n /** Distance in kilometers (metric, future). Switches to meters below 0.5 km. */\n @property({ type: Number }) km: number | null = null;\n\n override render() {\n if (this.km != null) return Number.isFinite(this.km) ? html`${formatKm(this.km)}` : nothing;\n if (this.miles != null) return Number.isFinite(this.miles) ? html`${formatMiles(this.miles)}` : nothing;\n return nothing;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"distance-value\": DistanceValue;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distribution-chart.d.ts","sourceRoot":"","sources":["../src/distribution-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,OAAO,EAAO,MAAM,KAAK,CAAC;AAqB1D,MAAM,WAAW,iBAAiB;IAChC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AASD;;;;;;;;;;;GAWG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAC/C,OAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"distribution-chart.d.ts","sourceRoot":"","sources":["../src/distribution-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,OAAO,EAAO,MAAM,KAAK,CAAC;AAqB1D,MAAM,WAAW,iBAAiB;IAChC,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AASD;;;;;;;;;;;GAWG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAC/C,OAAgB,MAAM,4BA6FpB;IAEF,wEAAwE;IAC5D,MAAM,SAAM;IACxB,4DAA4D;IAC5B,MAAM,EAAE,iBAAiB,EAAE,CAAM;IACjE,oFAAoF;IACpD,YAAY,EAAE,MAAM,EAAE,CAAyB;IAC/E,8GAA8G;IAC1D,QAAQ,SAAM;IAEzD,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAuB;IAC9C,0EAA0E;IACjE,OAAO,CAAC,MAAM,CAAK;IAC5B,wFAAwF;IAC/E,OAAO,CAAC,OAAO,CAAuB;IAE/C,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,GAAG,CAA+B;IAEjC,iBAAiB,SAGzB;IAEQ,YAAY,SAMpB;IAEQ,oBAAoB,SAI5B;IAEQ,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,QAE7C;IAED,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,UAAU;IAiGlB,OAAO,CAAC,aAAa;IAmBZ,MAAM,0DAUd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,iBAAiB,CAAC;KACzC;CACF"}
|
|
@@ -56,27 +56,51 @@ let DistributionChart = class DistributionChart extends LitElement {
|
|
|
56
56
|
width: 100%;
|
|
57
57
|
}
|
|
58
58
|
.wrap {
|
|
59
|
-
padding:
|
|
59
|
+
padding: 0.25rem 0 0.5rem;
|
|
60
60
|
}
|
|
61
61
|
svg {
|
|
62
62
|
display: block;
|
|
63
63
|
overflow: visible;
|
|
64
|
+
font-family: var(
|
|
65
|
+
--ui-font,
|
|
66
|
+
ui-sans-serif,
|
|
67
|
+
system-ui,
|
|
68
|
+
sans-serif,
|
|
69
|
+
"Apple Color Emoji",
|
|
70
|
+
"Segoe UI Emoji",
|
|
71
|
+
"Segoe UI Symbol",
|
|
72
|
+
"Noto Color Emoji"
|
|
73
|
+
);
|
|
64
74
|
}
|
|
65
75
|
.curve {
|
|
66
76
|
fill: none;
|
|
67
|
-
stroke: #4f46e5;
|
|
77
|
+
stroke: var(--ui-primary, #4f46e5);
|
|
68
78
|
stroke-width: 1.5;
|
|
69
79
|
stroke-linejoin: round;
|
|
70
80
|
}
|
|
71
81
|
.fill {
|
|
72
82
|
fill: url(#dist-fill-grad);
|
|
73
83
|
}
|
|
84
|
+
.fill-start {
|
|
85
|
+
stop-color: var(--ui-primary, #4f46e5);
|
|
86
|
+
}
|
|
87
|
+
.crosshair {
|
|
88
|
+
stroke: var(--ui-text-muted, #64748b);
|
|
89
|
+
}
|
|
90
|
+
.chart-label {
|
|
91
|
+
fill: var(--ui-text-muted, #64748b);
|
|
92
|
+
}
|
|
74
93
|
.skeleton {
|
|
75
|
-
background: linear-gradient(
|
|
94
|
+
background: linear-gradient(
|
|
95
|
+
90deg,
|
|
96
|
+
var(--ui-surface-muted, #f8fafc) 25%,
|
|
97
|
+
var(--ui-border, #e2e8f0) 50%,
|
|
98
|
+
var(--ui-surface-muted, #f8fafc) 75%
|
|
99
|
+
);
|
|
76
100
|
background-size: 200% 100%;
|
|
77
101
|
animation: shimmer 1.4s infinite;
|
|
78
102
|
border-radius: var(--ui-radius-sm, 0.25rem);
|
|
79
|
-
height:
|
|
103
|
+
height: 6.25rem;
|
|
80
104
|
}
|
|
81
105
|
@keyframes shimmer {
|
|
82
106
|
0% {
|
|
@@ -89,28 +113,33 @@ let DistributionChart = class DistributionChart extends LitElement {
|
|
|
89
113
|
.error {
|
|
90
114
|
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
91
115
|
color: var(--ui-danger, #dc2626);
|
|
92
|
-
padding:
|
|
116
|
+
padding: 0.5rem 0;
|
|
93
117
|
}
|
|
94
118
|
.legend {
|
|
95
119
|
display: flex;
|
|
96
120
|
flex-wrap: wrap;
|
|
97
|
-
gap:
|
|
98
|
-
padding:
|
|
121
|
+
gap: 0.5rem 0.75rem;
|
|
122
|
+
padding: 0.25rem 0 0.25rem 0.5rem;
|
|
99
123
|
}
|
|
100
124
|
.legend-item {
|
|
101
125
|
display: inline-flex;
|
|
102
126
|
align-items: center;
|
|
103
|
-
gap:
|
|
127
|
+
gap: 0.25rem;
|
|
104
128
|
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
105
129
|
color: var(--ui-text-muted, #64748b);
|
|
106
130
|
}
|
|
107
131
|
.legend-dot {
|
|
108
132
|
display: inline-block;
|
|
109
|
-
width:
|
|
110
|
-
height:
|
|
133
|
+
width: 0.5rem;
|
|
134
|
+
height: 0.5rem;
|
|
111
135
|
border-radius: 50%;
|
|
112
136
|
flex: 0 0 auto;
|
|
113
137
|
}
|
|
138
|
+
@media (prefers-reduced-motion: reduce) {
|
|
139
|
+
.skeleton {
|
|
140
|
+
animation: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
114
143
|
`,
|
|
115
144
|
]; }
|
|
116
145
|
connectedCallback() {
|
|
@@ -200,13 +229,21 @@ let DistributionChart = class DistributionChart extends LitElement {
|
|
|
200
229
|
const anchor = hx < innerW * 0.2 ? "start" : hx > innerW * 0.8 ? "end" : "middle";
|
|
201
230
|
const lx = hx < innerW * 0.2 ? 0 : hx > innerW * 0.8 ? innerW : hx;
|
|
202
231
|
return svg `
|
|
203
|
-
<line
|
|
204
|
-
<text font-size=${fs}
|
|
232
|
+
<line class="crosshair" stroke-width="1" x1=${hx} y1=${0} x2=${hx} y2=${innerH} />
|
|
233
|
+
<text class="chart-label" font-size=${fs} font-weight="500"
|
|
205
234
|
text-anchor=${anchor} x=${lx} y=${-fs * 0.4}>${hLabel}</text>
|
|
206
235
|
`;
|
|
207
236
|
})() : nothing;
|
|
237
|
+
const markerSummary = this.values.length > 0
|
|
238
|
+
? ` Markers: ${this.values
|
|
239
|
+
.map((value) => `${value.label || "value"} ${value.value.toLocaleString("en-US")} ${data.unit}`)
|
|
240
|
+
.join(", ")}.`
|
|
241
|
+
: "";
|
|
242
|
+
const summary = `${data.label}: ${data.min.toLocaleString("en-US")} to ${data.max.toLocaleString("en-US")} ${data.unit}, ` +
|
|
243
|
+
`mean ${data.mean.toLocaleString("en-US")} ${data.unit}.${markerSummary}`;
|
|
208
244
|
return svg `
|
|
209
245
|
<svg viewBox="0 0 ${this._width} ${SVG_H}" width=${this._width} height=${SVG_H}
|
|
246
|
+
role="img" aria-label=${summary}
|
|
210
247
|
style="cursor:crosshair"
|
|
211
248
|
@mousemove=${(e) => {
|
|
212
249
|
const innerX = e.offsetX - PAD.left;
|
|
@@ -215,8 +252,8 @@ let DistributionChart = class DistributionChart extends LitElement {
|
|
|
215
252
|
@mouseleave=${() => { this._hoverX = null; }}>
|
|
216
253
|
<defs>
|
|
217
254
|
<linearGradient id="dist-fill-grad" x1="0" y1="0" x2="0" y2="1">
|
|
218
|
-
<stop
|
|
219
|
-
<stop
|
|
255
|
+
<stop class="fill-start" offset="0%" stop-opacity="0.28"/>
|
|
256
|
+
<stop class="fill-start" offset="100%" stop-opacity="0"/>
|
|
220
257
|
</linearGradient>
|
|
221
258
|
</defs>
|
|
222
259
|
<g transform="translate(${PAD.left},${PAD.top})">
|
|
@@ -224,9 +261,9 @@ let DistributionChart = class DistributionChart extends LitElement {
|
|
|
224
261
|
<path class="curve" d=${curvePath} />
|
|
225
262
|
${markers}
|
|
226
263
|
${crosshair}
|
|
227
|
-
<text font-size=${fs}
|
|
228
|
-
<text font-size=${fs}
|
|
229
|
-
<text font-size=${fs}
|
|
264
|
+
<text class="chart-label" font-size=${fs} text-anchor="start" x=${0} y=${innerH + fs * 1.4}>${minLabel}</text>
|
|
265
|
+
<text class="chart-label" font-size=${fs} text-anchor="end" x=${innerW} y=${innerH + fs * 1.4}>${maxLabel}</text>
|
|
266
|
+
<text class="chart-label" font-size=${fs} text-anchor="middle" x=${innerW / 2} y=${innerH + fs * 1.4}>${data.unit}</text>
|
|
230
267
|
</g>
|
|
231
268
|
</svg>
|
|
232
269
|
`;
|