@f-ewald/components 0.5.0 → 0.7.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.
- package/README.md +61 -0
- package/custom-elements.json +3808 -930
- package/dist/chat-message.d.ts +39 -0
- package/dist/chat-message.d.ts.map +1 -0
- package/dist/chat-message.js +155 -0
- package/dist/chat-message.js.map +1 -0
- package/dist/data-table.d.ts +39 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +119 -0
- package/dist/data-table.js.map +1 -0
- package/dist/dropdown-button.d.ts +37 -0
- package/dist/dropdown-button.d.ts.map +1 -0
- package/dist/dropdown-button.js +219 -0
- package/dist/dropdown-button.js.map +1 -0
- package/dist/editable-text.d.ts +52 -0
- package/dist/editable-text.d.ts.map +1 -0
- package/dist/editable-text.js +224 -0
- package/dist/editable-text.js.map +1 -0
- package/dist/form-select.d.ts +46 -0
- package/dist/form-select.d.ts.map +1 -0
- package/dist/form-select.js +245 -0
- package/dist/form-select.js.map +1 -0
- package/dist/frame-box.d.ts +22 -0
- package/dist/frame-box.d.ts.map +1 -0
- package/dist/frame-box.js +68 -0
- package/dist/frame-box.js.map +1 -0
- package/dist/gallery-item-variant.d.ts +21 -0
- package/dist/gallery-item-variant.d.ts.map +1 -0
- package/dist/gallery-item-variant.js +44 -0
- package/dist/gallery-item-variant.js.map +1 -0
- package/dist/gallery-item.d.ts +28 -0
- package/dist/gallery-item.d.ts.map +1 -0
- package/dist/gallery-item.js +54 -0
- package/dist/gallery-item.js.map +1 -0
- package/dist/icon-button.d.ts +27 -0
- package/dist/icon-button.d.ts.map +1 -0
- package/dist/icon-button.js +83 -0
- package/dist/icon-button.js.map +1 -0
- package/dist/icons.d.ts +8 -0
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +8 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/live-timer.d.ts +31 -0
- package/dist/live-timer.d.ts.map +1 -0
- package/dist/live-timer.js +78 -0
- package/dist/live-timer.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +82 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/photo-gallery.d.ts +117 -0
- package/dist/photo-gallery.d.ts.map +1 -0
- package/dist/photo-gallery.js +620 -0
- package/dist/photo-gallery.js.map +1 -0
- package/dist/popover-panel.d.ts +37 -0
- package/dist/popover-panel.d.ts.map +1 -0
- package/dist/popover-panel.js +184 -0
- package/dist/popover-panel.js.map +1 -0
- package/dist/status-pill.d.ts +24 -0
- package/dist/status-pill.d.ts.map +1 -0
- package/dist/status-pill.js +101 -0
- package/dist/status-pill.js.map +1 -0
- package/dist/tile-grid.d.ts +32 -0
- package/dist/tile-grid.d.ts.map +1 -0
- package/dist/tile-grid.js +102 -0
- package/dist/tile-grid.js.map +1 -0
- package/dist/tokens.css +39 -0
- package/dist/tokens.d.ts +28 -3
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +42 -43
- package/dist/tokens.js.map +1 -1
- package/dist/user-avatar.d.ts +5 -2
- package/dist/user-avatar.d.ts.map +1 -1
- package/dist/user-avatar.js +22 -6
- package/dist/user-avatar.js.map +1 -1
- package/dist/utils/duration.d.ts +12 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/duration.js +27 -0
- package/dist/utils/duration.js.map +1 -0
- package/docs/chat-message.md +59 -0
- package/docs/data-table.md +63 -0
- package/docs/dropdown-button.md +61 -0
- package/docs/editable-text.md +51 -0
- package/docs/form-select.md +70 -0
- package/docs/frame-box.md +43 -0
- package/docs/gallery-item-variant.md +37 -0
- package/docs/gallery-item.md +47 -0
- package/docs/icon-button.md +52 -0
- package/docs/live-timer.md +39 -0
- package/docs/mcp-evaluation.md +18 -11
- package/docs/photo-gallery.md +77 -0
- package/docs/popover-panel.md +70 -0
- package/docs/status-pill.md +43 -0
- package/docs/tile-grid.md +58 -0
- package/docs/user-avatar.md +1 -1
- package/llms.txt +357 -1
- package/package.json +10 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photo-gallery.js","sourceRoot":"","sources":["../src/photo-gallery.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property, queryAssignedElements, state } from \"lit/decorators.js\";\nimport { ifDefined } from \"lit/directives/if-defined.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport type { GalleryItemVariant } from \"./gallery-item-variant.js\";\nimport { GalleryItem } from \"./gallery-item.js\";\nimport { iconChevronLeft, iconChevronRight } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\nexport type PhotoGalleryObjectFit = \"cover\" | \"contain\";\nexport type PhotoGalleryChangeReason =\n | \"autoplay\"\n | \"indicator\"\n | \"items\"\n | \"keyboard\"\n | \"next\"\n | \"previous\"\n | \"programmatic\"\n | \"swipe\";\n\nexport interface PhotoGallerySlideChangeDetail {\n previousIndex: number;\n currentIndex: number;\n item: GalleryItem;\n reason: PhotoGalleryChangeReason;\n}\n\nconst transitionDurationMs = 250;\nconst swipeThresholdPx = 40;\nconst booleanAttribute = {\n fromAttribute(value: string | null): boolean {\n return value !== null && value !== \"false\";\n },\n};\n\n/**\n * Responsive, accessible image carousel composed from declarative\n * `gallery-item` children.\n *\n * @element photo-gallery\n * @slot - `gallery-item` elements rendered as slides.\n * @fires slide-change - The active image changed.\n */\n@customElement(\"photo-gallery\")\nexport class PhotoGallery extends LitElement {\n /** Zero-based active image index. */\n @property({ type: Number, attribute: \"current-index\", reflect: true })\n currentIndex = 0;\n\n /** Autoplay interval in milliseconds. Set to zero to disable autoplay. */\n @property({ type: Number }) delay = 0;\n\n /** Whether previous and next buttons are shown. */\n @property({ attribute: \"show-controls\", converter: booleanAttribute })\n showControls = true;\n\n /** Whether a current/total counter is shown. */\n @property({ type: Boolean, attribute: \"show-counter\" })\n showCounter = false;\n\n /** Whether clickable slide indicators are shown. */\n @property({ type: Boolean, attribute: \"show-indicators\" })\n showIndicators = false;\n\n /** Whether autoplay includes a built-in pause/play control. */\n @property({ attribute: \"show-autoplay-control\", converter: booleanAttribute })\n showAutoplayControl = true;\n\n /** Whether autoplay is explicitly paused. */\n @property({ type: Boolean, reflect: true })\n paused = false;\n\n /** CSS aspect ratio used by the image viewport. */\n @property({ attribute: \"aspect-ratio\" })\n aspectRatio = \"16 / 9\";\n\n /** How images fit within the stable viewport. */\n @property({ attribute: \"object-fit\" })\n objectFit: PhotoGalleryObjectFit = \"cover\";\n\n @queryAssignedElements({ selector: \"gallery-item\" })\n private readonly _galleryItems!: GalleryItem[];\n\n @state()\n private _previousIndex: number | null = null;\n\n @state()\n private _itemsVersion = 0;\n\n private _autoplayTimer?: number;\n private _transitionTimer?: number;\n private _metadataObserver?: MutationObserver;\n private _hovered = false;\n private _focusWithin = false;\n private _nextChangeReason: PhotoGalleryChangeReason | null = null;\n private _pendingChange?: PhotoGallerySlideChangeDetail;\n private _pointerStart?: { id: number; x: number; y: number };\n private _itemsChanged = false;\n private _activeItem?: GalleryItem;\n private _renderedIndex = 0;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\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 }\n .gallery {\n outline: none;\n }\n figure {\n margin: 0;\n }\n .viewport {\n position: relative;\n overflow: hidden;\n aspect-ratio: var(--photo-gallery-aspect-ratio, 16 / 9);\n border-radius: var(--ui-radius, 0.5rem);\n background: var(--ui-surface-muted, #f8fafc);\n touch-action: pan-y;\n user-select: none;\n }\n .gallery:focus-visible .viewport {\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .slides {\n display: grid;\n width: 100%;\n height: 100%;\n }\n picture {\n grid-area: 1 / 1;\n display: block;\n width: 100%;\n height: 100%;\n }\n picture img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: var(--photo-gallery-object-fit, cover);\n }\n .entering {\n z-index: 2;\n animation: gallery-fade-in 250ms ease both;\n }\n .leaving {\n z-index: 1;\n pointer-events: none;\n animation: gallery-fade-out 250ms ease both;\n }\n .arrow-controls {\n position: absolute;\n z-index: 3;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem;\n pointer-events: none;\n }\n button {\n border: 0;\n font: inherit;\n cursor: pointer;\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 .arrow-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n padding: 0;\n color: var(--ui-surface, #fff);\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n border-radius: 9999px;\n pointer-events: auto;\n }\n .arrow-button:hover {\n background: color-mix(in srgb, var(--ui-text, #0f172a) 70%, transparent);\n }\n figcaption {\n padding: 0.5rem 0.25rem 0;\n color: var(--ui-text-muted, #64748b);\n }\n .footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n min-height: 2rem;\n padding-top: 0.5rem;\n }\n .counter {\n color: var(--ui-text-muted, #64748b);\n font-size: var(--ui-font-size-sm, 0.75rem);\n white-space: nowrap;\n }\n .indicators {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n }\n .indicator {\n width: 0.625rem;\n height: 0.625rem;\n padding: 0;\n background: var(--ui-border, #e2e8f0);\n border-radius: 9999px;\n }\n .indicator[aria-current=\"true\"] {\n background: var(--ui-primary, #4f46e5);\n }\n .autoplay-button {\n padding: 0.25rem 0.625rem;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface-muted, #f8fafc);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n font-size: var(--ui-font-size-sm, 0.75rem);\n white-space: nowrap;\n }\n .autoplay-button:hover {\n background: var(--ui-surface, #fff);\n }\n slot {\n display: none;\n }\n @keyframes gallery-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n @keyframes gallery-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .entering,\n .leaving {\n animation: none;\n }\n }\n `,\n ];\n\n /** Starts observers and autoplay integration when the element connects. */\n override connectedCallback(): void {\n super.connectedCallback();\n this._metadataObserver ??= new MutationObserver(() => this._handleMetadataChange());\n this._metadataObserver.observe(this, {\n attributes: true,\n attributeFilter: [\"alt\", \"caption\", \"media\", \"src\", \"srcset\"],\n childList: true,\n subtree: true,\n });\n document.addEventListener(\"visibilitychange\", this._handleVisibilityChange);\n }\n\n /** Releases timers and observers when the element disconnects. */\n override disconnectedCallback(): void {\n this._clearAutoplay();\n this._clearTransition();\n this._metadataObserver?.disconnect();\n document.removeEventListener(\"visibilitychange\", this._handleVisibilityChange);\n super.disconnectedCallback();\n }\n\n /** Normalizes external index changes before rendering. */\n protected override willUpdate(changed: PropertyValues<this>): void {\n if (!changed.has(\"currentIndex\")) return;\n\n const normalized = this._normalizeIndex(this.currentIndex);\n if (normalized !== this.currentIndex) {\n this.currentIndex = normalized;\n }\n\n const previousValue = changed.get(\"currentIndex\");\n if (previousValue === undefined || this._galleryItems.length === 0) {\n this._nextChangeReason = null;\n return;\n }\n\n const previousIndex = this._normalizeIndex(Number(previousValue));\n if (previousIndex === normalized) {\n this._nextChangeReason = null;\n return;\n }\n\n const reason = this._nextChangeReason ?? \"programmatic\";\n this._previousIndex = reason === \"items\" ? null : previousIndex;\n this._pendingChange = {\n previousIndex,\n currentIndex: normalized,\n item: this._galleryItems[normalized],\n reason,\n };\n this._nextChangeReason = null;\n }\n\n /** Emits completed changes and keeps autoplay synchronized with properties. */\n protected override updated(changed: PropertyValues<this>): void {\n if (this._pendingChange) {\n this.dispatchEvent(\n new CustomEvent<PhotoGallerySlideChangeDetail>(\"slide-change\", {\n bubbles: true,\n composed: true,\n detail: this._pendingChange,\n }),\n );\n this._pendingChange = undefined;\n this._scheduleTransitionCleanup();\n }\n\n if (changed.has(\"currentIndex\") || changed.has(\"delay\") || changed.has(\"paused\") || this._itemsChanged) {\n this._itemsChanged = false;\n this._restartAutoplay();\n }\n this._activeItem = this._galleryItems[this.currentIndex];\n this._renderedIndex = this.currentIndex;\n }\n\n /** Wraps any requested index into the current item range. */\n private _normalizeIndex(index: number): number {\n const count = this._galleryItems.length;\n if (count === 0 || !Number.isFinite(index)) return 0;\n return ((Math.trunc(index) % count) + count) % count;\n }\n\n /** Returns responsive variants declared directly under an item. */\n private _variantsFor(item: GalleryItem): GalleryItemVariant[] {\n return Array.from(item.children).filter(\n (child): child is GalleryItemVariant => child.tagName.toLowerCase() === \"gallery-item-variant\",\n );\n }\n\n /** Changes slides through the shared state and event path. */\n private _goTo(index: number, reason: PhotoGalleryChangeReason): void {\n const normalized = this._normalizeIndex(index);\n if (this._galleryItems.length < 2 || normalized === this.currentIndex) {\n this._restartAutoplay();\n return;\n }\n\n this._nextChangeReason = reason;\n this.currentIndex = normalized;\n }\n\n /** Moves to the previous image. */\n private _showPrevious(reason: PhotoGalleryChangeReason = \"previous\"): void {\n this._goTo(this.currentIndex - 1, reason);\n }\n\n /** Moves to the next image. */\n private _showNext(reason: PhotoGalleryChangeReason = \"next\"): void {\n this._goTo(this.currentIndex + 1, reason);\n }\n\n /** Toggles explicit autoplay pause state. */\n private _togglePaused(): void {\n this.paused = !this.paused;\n }\n\n /** Clears and conditionally schedules the next autoplay advance. */\n private _restartAutoplay(): void {\n this._clearAutoplay();\n if (!this._canAutoplay()) return;\n\n this._autoplayTimer = window.setTimeout(() => {\n this._showNext(\"autoplay\");\n }, this.delay);\n }\n\n /** Reports whether autoplay may currently schedule a transition. */\n private _canAutoplay(): boolean {\n return (\n this.delay > 0 &&\n this._galleryItems.length > 1 &&\n !this.paused &&\n !this._hovered &&\n !this._focusWithin &&\n !document.hidden\n );\n }\n\n /** Clears the pending autoplay timeout. */\n private _clearAutoplay(): void {\n if (this._autoplayTimer === undefined) return;\n window.clearTimeout(this._autoplayTimer);\n this._autoplayTimer = undefined;\n }\n\n /** Removes the outgoing crossfade layer after the animation completes. */\n private _scheduleTransitionCleanup(): void {\n this._clearTransition();\n this._transitionTimer = window.setTimeout(() => {\n this._previousIndex = null;\n this._transitionTimer = undefined;\n }, transitionDurationMs);\n }\n\n /** Clears pending transition cleanup. */\n private _clearTransition(): void {\n if (this._transitionTimer === undefined) return;\n window.clearTimeout(this._transitionTimer);\n this._transitionTimer = undefined;\n }\n\n /** Refreshes item metadata and clamps the active index after light-DOM changes. */\n private _handleMetadataChange(): void {\n this._itemsChanged = true;\n this._itemsVersion += 1;\n const preserveActiveItem = this.currentIndex === this._renderedIndex;\n const preservedIndex =\n preserveActiveItem && this._activeItem ? this._galleryItems.indexOf(this._activeItem) : -1;\n const normalized = preservedIndex >= 0 ? preservedIndex : this._normalizeIndex(this.currentIndex);\n if (normalized === this.currentIndex) {\n const item = this._galleryItems[normalized];\n const activeItemRemoved = Boolean(this._activeItem && !this._galleryItems.includes(this._activeItem));\n if (item && activeItemRemoved) {\n this._previousIndex = null;\n this._pendingChange = {\n previousIndex: this._renderedIndex,\n currentIndex: normalized,\n item,\n reason: \"items\",\n };\n }\n return;\n }\n this._nextChangeReason = \"items\";\n this.currentIndex = normalized;\n }\n\n /** Refreshes item state after the default slot changes. */\n private _handleSlotChange(): void {\n this._handleMetadataChange();\n }\n\n /** Temporarily pauses autoplay while the pointer is over the gallery. */\n private _handleMouseEnter(): void {\n this._hovered = true;\n this._restartAutoplay();\n }\n\n /** Resumes autoplay with a fresh delay after hover ends. */\n private _handleMouseLeave(): void {\n this._hovered = false;\n this._restartAutoplay();\n }\n\n /** Temporarily pauses autoplay while focus is inside the gallery. */\n private _handleFocusIn(): void {\n this._focusWithin = true;\n this._restartAutoplay();\n }\n\n /** Resumes autoplay with a fresh delay after focus leaves the gallery. */\n private _handleFocusOut(): void {\n queueMicrotask(() => {\n this._focusWithin = this.matches(\":focus-within\");\n this._restartAutoplay();\n });\n }\n\n /** Pauses or resumes scheduling when page visibility changes. */\n private readonly _handleVisibilityChange = (): void => {\n this._restartAutoplay();\n };\n\n /** Handles Left and Right arrow keyboard navigation. */\n private _handleKeyDown(event: KeyboardEvent): void {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n this._showPrevious(\"keyboard\");\n return;\n }\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n this._showNext(\"keyboard\");\n }\n }\n\n /** Records the starting point of a primary pointer gesture. */\n private _handlePointerDown(event: PointerEvent): void {\n if (!event.isPrimary || event.button !== 0) return;\n if (event.composedPath().some((target) => target instanceof HTMLButtonElement)) return;\n this._pointerStart = { id: event.pointerId, x: event.clientX, y: event.clientY };\n (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);\n }\n\n /** Converts a sufficiently horizontal pointer gesture into navigation. */\n private _handlePointerUp(event: PointerEvent): void {\n const start = this._pointerStart;\n this._pointerStart = undefined;\n if (!start || start.id !== event.pointerId) return;\n\n const deltaX = event.clientX - start.x;\n const deltaY = event.clientY - start.y;\n if (Math.abs(deltaX) < swipeThresholdPx || Math.abs(deltaX) <= Math.abs(deltaY)) return;\n\n event.preventDefault();\n if (deltaX < 0) {\n this._showNext(\"swipe\");\n return;\n }\n this._showPrevious(\"swipe\");\n }\n\n /** Cancels an incomplete pointer gesture. */\n private _handlePointerCancel(): void {\n this._pointerStart = undefined;\n }\n\n /** Renders one responsive image layer for the crossfade stack. */\n private _renderPicture(index: number, state: \"current\" | \"previous\") {\n const item = this._galleryItems[index];\n if (!item) return nothing;\n\n const isPrevious = state === \"previous\";\n const transitionClass = this._previousIndex === null ? \"\" : isPrevious ? \"leaving\" : \"entering\";\n return html`\n <picture class=${transitionClass} aria-hidden=${isPrevious ? \"true\" : nothing}>\n ${this._variantsFor(item)\n .filter((variant) => variant.srcset)\n .map(\n (variant) =>\n html`<source media=${ifDefined(variant.media || undefined)} srcset=${variant.srcset} />`,\n )}\n <img src=${item.src} alt=${isPrevious ? \"\" : item.alt} draggable=\"false\" />\n </picture>\n `;\n }\n\n /** Renders enabled counter, indicator, and autoplay controls. */\n private _renderFooter(itemCount: number) {\n const showIndicators = this.showIndicators && itemCount > 1;\n const showAutoplay = this.showAutoplayControl && this.delay > 0 && itemCount > 1;\n if (!this.showCounter && !showIndicators && !showAutoplay) return nothing;\n\n return html`\n <div class=\"footer\">\n ${this.showCounter\n ? html`<span class=\"counter\">${this.currentIndex + 1} / ${itemCount}</span>`\n : nothing}\n ${showIndicators\n ? html`\n <div class=\"indicators\" role=\"group\" aria-label=\"Choose image\">\n ${this._galleryItems.map(\n (_item, index) => html`\n <button\n class=\"indicator\"\n type=\"button\"\n aria-label=\"Show image ${index + 1} of ${itemCount}\"\n aria-current=${String(index === this.currentIndex)}\n @click=${() => this._goTo(index, \"indicator\")}\n ></button>\n `,\n )}\n </div>\n `\n : nothing}\n ${showAutoplay\n ? html`\n <button\n class=\"autoplay-button\"\n type=\"button\"\n aria-label=${this.paused ? \"Resume slideshow\" : \"Pause slideshow\"}\n @click=${this._togglePaused}\n >\n ${this.paused ? \"Play\" : \"Pause\"}\n </button>\n `\n : nothing}\n </div>\n `;\n }\n\n /** Renders the active image, navigation, caption, and hidden metadata slot. */\n protected override render() {\n const itemCount = this._galleryItems.length;\n const currentItem = this._galleryItems[this.currentIndex];\n const objectFit: PhotoGalleryObjectFit = this.objectFit === \"contain\" ? \"contain\" : \"cover\";\n const viewportStyles = {\n \"--photo-gallery-aspect-ratio\": this.aspectRatio.trim() || \"16 / 9\",\n \"--photo-gallery-object-fit\": objectFit,\n };\n\n return html`\n <div\n class=\"gallery\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n aria-label=\"Photo gallery\"\n tabindex=\"0\"\n @keydown=${this._handleKeyDown}\n @mouseenter=${this._handleMouseEnter}\n @mouseleave=${this._handleMouseLeave}\n @focusin=${this._handleFocusIn}\n @focusout=${this._handleFocusOut}\n >\n ${currentItem\n ? html`\n <figure>\n <div\n class=\"viewport\"\n style=${styleMap(viewportStyles)}\n @pointerdown=${this._handlePointerDown}\n @pointerup=${this._handlePointerUp}\n @pointercancel=${this._handlePointerCancel}\n >\n <div class=\"slides\">\n ${this._previousIndex === null\n ? nothing\n : this._renderPicture(this._previousIndex, \"previous\")}\n ${this._renderPicture(this.currentIndex, \"current\")}\n </div>\n ${this.showControls && itemCount > 1\n ? html`\n <div class=\"arrow-controls\">\n <button\n class=\"arrow-button previous\"\n type=\"button\"\n aria-label=\"Previous image\"\n @click=${() => this._showPrevious()}\n >\n ${iconChevronLeft(24)}\n </button>\n <button\n class=\"arrow-button next\"\n type=\"button\"\n aria-label=\"Next image\"\n @click=${() => this._showNext()}\n >\n ${iconChevronRight(24)}\n </button>\n </div>\n `\n : nothing}\n </div>\n ${currentItem.caption ? html`<figcaption>${currentItem.caption}</figcaption>` : nothing}\n </figure>\n ${this._renderFooter(itemCount)}\n `\n : nothing}\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"photo-gallery\": PhotoGallery;\n }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LitElement, type PropertyValues } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* Generic anchored popover shell: a floating card positioned relative to its
|
|
4
|
+
* nearest `position: relative` ancestor (place it next to its trigger button
|
|
5
|
+
* inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge
|
|
6
|
+
* drawer. Closes on outside click or Escape. Header chrome and close button
|
|
7
|
+
* match `slide-panel`'s API (`heading`, `panel-close`) so either can be
|
|
8
|
+
* swapped in for the other with no consumer-side changes beyond the wrapper.
|
|
9
|
+
*
|
|
10
|
+
* Set `centered` to render as a screen-centered modal with a translucent
|
|
11
|
+
* backdrop instead of the default anchored placement.
|
|
12
|
+
*
|
|
13
|
+
* @element popover-panel
|
|
14
|
+
* @fires panel-close - User clicked the close (✕) button, pressed Escape, or clicked outside/the backdrop.
|
|
15
|
+
* @slot title - Overrides the plain `heading` text with custom markup.
|
|
16
|
+
* @slot actions - Extra header controls (e.g. an icon+label link) rendered between the title and the close button.
|
|
17
|
+
* @slot - Popover body content.
|
|
18
|
+
*/
|
|
19
|
+
export declare class PopoverPanel extends LitElement {
|
|
20
|
+
#private;
|
|
21
|
+
/** Whether the popover is currently visible. */
|
|
22
|
+
open: boolean;
|
|
23
|
+
/** Title text shown in the popover header. */
|
|
24
|
+
heading: string;
|
|
25
|
+
/** Render as a screen-centered modal with a backdrop instead of anchored placement. */
|
|
26
|
+
centered: boolean;
|
|
27
|
+
static styles: import("lit").CSSResult[];
|
|
28
|
+
disconnectedCallback(): void;
|
|
29
|
+
protected updated(changed: PropertyValues): void;
|
|
30
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
31
|
+
}
|
|
32
|
+
declare global {
|
|
33
|
+
interface HTMLElementTagNameMap {
|
|
34
|
+
"popover-panel": PopoverPanel;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=popover-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover-panel.d.ts","sourceRoot":"","sources":["../src/popover-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAKjE;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,YAAa,SAAQ,UAAU;;IAC1C,gDAAgD;IACJ,IAAI,UAAS;IACzD,8CAA8C;IAClC,OAAO,SAAM;IACzB,uFAAuF;IAC3C,QAAQ,UAAS;IAE7D,OAAgB,MAAM,4BA8EpB;IAEO,oBAAoB,IAAI,IAAI,CAIpC;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CASxD;IAqBQ,MAAM,yCAed;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from "lit";
|
|
8
|
+
import { customElement, property } from "lit/decorators.js";
|
|
9
|
+
import { iconX } from "./icons.js";
|
|
10
|
+
import { tokens } from "./tokens.js";
|
|
11
|
+
/**
|
|
12
|
+
* Generic anchored popover shell: a floating card positioned relative to its
|
|
13
|
+
* nearest `position: relative` ancestor (place it next to its trigger button
|
|
14
|
+
* inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge
|
|
15
|
+
* drawer. Closes on outside click or Escape. Header chrome and close button
|
|
16
|
+
* match `slide-panel`'s API (`heading`, `panel-close`) so either can be
|
|
17
|
+
* swapped in for the other with no consumer-side changes beyond the wrapper.
|
|
18
|
+
*
|
|
19
|
+
* Set `centered` to render as a screen-centered modal with a translucent
|
|
20
|
+
* backdrop instead of the default anchored placement.
|
|
21
|
+
*
|
|
22
|
+
* @element popover-panel
|
|
23
|
+
* @fires panel-close - User clicked the close (✕) button, pressed Escape, or clicked outside/the backdrop.
|
|
24
|
+
* @slot title - Overrides the plain `heading` text with custom markup.
|
|
25
|
+
* @slot actions - Extra header controls (e.g. an icon+label link) rendered between the title and the close button.
|
|
26
|
+
* @slot - Popover body content.
|
|
27
|
+
*/
|
|
28
|
+
let PopoverPanel = class PopoverPanel extends LitElement {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
/** Whether the popover is currently visible. */
|
|
32
|
+
this.open = false;
|
|
33
|
+
/** Title text shown in the popover header. */
|
|
34
|
+
this.heading = "";
|
|
35
|
+
/** Render as a screen-centered modal with a backdrop instead of anchored placement. */
|
|
36
|
+
this.centered = false;
|
|
37
|
+
this.#onWindowMousedown = (e) => {
|
|
38
|
+
// In centered mode the host itself renders the backdrop, so a mousedown
|
|
39
|
+
// landing directly on the host (not on .panel or its content) is a
|
|
40
|
+
// backdrop click and must close like an outside click would.
|
|
41
|
+
if (this.centered && e.target === this) {
|
|
42
|
+
this.#close();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!e.composedPath().includes(this))
|
|
46
|
+
this.#close();
|
|
47
|
+
};
|
|
48
|
+
this.#onWindowKeydown = (e) => {
|
|
49
|
+
if (e.key === "Escape")
|
|
50
|
+
this.#close();
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
static { this.styles = [
|
|
54
|
+
tokens,
|
|
55
|
+
css `
|
|
56
|
+
:host {
|
|
57
|
+
display: none;
|
|
58
|
+
position: absolute;
|
|
59
|
+
top: calc(100% + 0.5rem);
|
|
60
|
+
right: 0;
|
|
61
|
+
z-index: 20;
|
|
62
|
+
}
|
|
63
|
+
:host([open]) {
|
|
64
|
+
display: block;
|
|
65
|
+
}
|
|
66
|
+
:host([centered][open]) {
|
|
67
|
+
position: fixed;
|
|
68
|
+
inset: 0;
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: center;
|
|
72
|
+
background: rgb(0 0 0 / 0.35);
|
|
73
|
+
z-index: 30;
|
|
74
|
+
}
|
|
75
|
+
:host([centered]) .panel {
|
|
76
|
+
width: 400px;
|
|
77
|
+
}
|
|
78
|
+
.panel {
|
|
79
|
+
width: 320px;
|
|
80
|
+
max-width: calc(100vw - 2rem);
|
|
81
|
+
background: var(--ui-surface, #fff);
|
|
82
|
+
border: 1px solid var(--ui-border, #e2e8f0);
|
|
83
|
+
border-radius: var(--ui-radius, 0.5rem);
|
|
84
|
+
box-shadow: var(--ui-shadow-lg, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: column;
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
}
|
|
89
|
+
.panel-header {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: space-between;
|
|
93
|
+
padding: 0.5rem 0.625rem;
|
|
94
|
+
border-bottom: 1px solid var(--ui-border, #e2e8f0);
|
|
95
|
+
flex: 0 0 auto;
|
|
96
|
+
}
|
|
97
|
+
.panel-title {
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
font-size: var(--ui-font-size, 0.875rem);
|
|
100
|
+
font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
|
|
101
|
+
color: var(--ui-text, #0f172a);
|
|
102
|
+
flex: 1 1 auto;
|
|
103
|
+
overflow: hidden;
|
|
104
|
+
white-space: nowrap;
|
|
105
|
+
text-overflow: ellipsis;
|
|
106
|
+
padding-right: 0.5rem;
|
|
107
|
+
}
|
|
108
|
+
.panel-actions {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
gap: 0.5rem;
|
|
112
|
+
flex: 0 0 auto;
|
|
113
|
+
margin-right: 0.25rem;
|
|
114
|
+
}
|
|
115
|
+
.close-btn {
|
|
116
|
+
background: none;
|
|
117
|
+
border: none;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
padding: 0.25rem 0.5rem;
|
|
120
|
+
color: var(--ui-text-muted, #64748b);
|
|
121
|
+
border-radius: var(--ui-radius-sm, 0.25rem);
|
|
122
|
+
flex: 0 0 auto;
|
|
123
|
+
display: inline-flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: center;
|
|
126
|
+
}
|
|
127
|
+
.close-btn:hover {
|
|
128
|
+
background: var(--ui-surface-muted, #f8fafc);
|
|
129
|
+
}
|
|
130
|
+
`,
|
|
131
|
+
]; }
|
|
132
|
+
disconnectedCallback() {
|
|
133
|
+
super.disconnectedCallback();
|
|
134
|
+
window.removeEventListener("mousedown", this.#onWindowMousedown, true);
|
|
135
|
+
window.removeEventListener("keydown", this.#onWindowKeydown);
|
|
136
|
+
}
|
|
137
|
+
updated(changed) {
|
|
138
|
+
if (!changed.has("open"))
|
|
139
|
+
return;
|
|
140
|
+
if (this.open) {
|
|
141
|
+
window.addEventListener("mousedown", this.#onWindowMousedown, true);
|
|
142
|
+
window.addEventListener("keydown", this.#onWindowKeydown);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
window.removeEventListener("mousedown", this.#onWindowMousedown, true);
|
|
146
|
+
window.removeEventListener("keydown", this.#onWindowKeydown);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
#onWindowMousedown;
|
|
150
|
+
#onWindowKeydown;
|
|
151
|
+
#close() {
|
|
152
|
+
this.dispatchEvent(new CustomEvent("panel-close", { bubbles: true, composed: true }));
|
|
153
|
+
}
|
|
154
|
+
render() {
|
|
155
|
+
return html `
|
|
156
|
+
<div class="panel">
|
|
157
|
+
<div class="panel-header">
|
|
158
|
+
<slot name="title">
|
|
159
|
+
${this.heading ? html `<span class="panel-title">${this.heading}</span>` : null}
|
|
160
|
+
</slot>
|
|
161
|
+
<span class="panel-actions"><slot name="actions"></slot></span>
|
|
162
|
+
<button class="close-btn" aria-label="Close popover" @click=${() => this.#close()}>
|
|
163
|
+
${iconX(18)}
|
|
164
|
+
</button>
|
|
165
|
+
</div>
|
|
166
|
+
<slot></slot>
|
|
167
|
+
</div>
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
__decorate([
|
|
172
|
+
property({ type: Boolean, reflect: true })
|
|
173
|
+
], PopoverPanel.prototype, "open", void 0);
|
|
174
|
+
__decorate([
|
|
175
|
+
property()
|
|
176
|
+
], PopoverPanel.prototype, "heading", void 0);
|
|
177
|
+
__decorate([
|
|
178
|
+
property({ type: Boolean, reflect: true })
|
|
179
|
+
], PopoverPanel.prototype, "centered", void 0);
|
|
180
|
+
PopoverPanel = __decorate([
|
|
181
|
+
customElement("popover-panel")
|
|
182
|
+
], PopoverPanel);
|
|
183
|
+
export { PopoverPanel };
|
|
184
|
+
//# sourceMappingURL=popover-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover-panel.js","sourceRoot":"","sources":["../src/popover-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconX } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Generic anchored popover shell: a floating card positioned relative to its\n * nearest `position: relative` ancestor (place it next to its trigger button\n * inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge\n * drawer. Closes on outside click or Escape. Header chrome and close button\n * match `slide-panel`'s API (`heading`, `panel-close`) so either can be\n * swapped in for the other with no consumer-side changes beyond the wrapper.\n *\n * Set `centered` to render as a screen-centered modal with a translucent\n * backdrop instead of the default anchored placement.\n *\n * @element popover-panel\n * @fires panel-close - User clicked the close (✕) button, pressed Escape, or clicked outside/the backdrop.\n * @slot title - Overrides the plain `heading` text with custom markup.\n * @slot actions - Extra header controls (e.g. an icon+label link) rendered between the title and the close button.\n * @slot - Popover body content.\n */\n@customElement(\"popover-panel\")\nexport class PopoverPanel extends LitElement {\n /** Whether the popover is currently visible. */\n @property({ type: Boolean, reflect: true }) open = false;\n /** Title text shown in the popover header. */\n @property() heading = \"\";\n /** Render as a screen-centered modal with a backdrop instead of anchored placement. */\n @property({ type: Boolean, reflect: true }) centered = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: none;\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n z-index: 20;\n }\n :host([open]) {\n display: block;\n }\n :host([centered][open]) {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgb(0 0 0 / 0.35);\n z-index: 30;\n }\n :host([centered]) .panel {\n width: 400px;\n }\n .panel {\n width: 320px;\n max-width: calc(100vw - 2rem);\n background: var(--ui-surface, #fff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: var(--ui-shadow-lg, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.625rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n flex: 0 0 auto;\n }\n .panel-title {\n font-weight: 600;\n font-size: var(--ui-font-size, 0.875rem);\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n color: var(--ui-text, #0f172a);\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n padding-right: 0.5rem;\n }\n .panel-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 0 0 auto;\n margin-right: 0.25rem;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem 0.5rem;\n color: var(--ui-text-muted, #64748b);\n border-radius: var(--ui-radius-sm, 0.25rem);\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n .close-btn:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n `,\n ];\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n }\n\n protected override updated(changed: PropertyValues): void {\n if (!changed.has(\"open\")) return;\n if (this.open) {\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.addEventListener(\"keydown\", this.#onWindowKeydown);\n } else {\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n }\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n // In centered mode the host itself renders the backdrop, so a mousedown\n // landing directly on the host (not on .panel or its content) is a\n // backdrop click and must close like an outside click would.\n if (this.centered && e.target === this) {\n this.#close();\n return;\n }\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #onWindowKeydown = (e: KeyboardEvent): void => {\n if (e.key === \"Escape\") this.#close();\n };\n\n #close(): void {\n this.dispatchEvent(new CustomEvent(\"panel-close\", { bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <div class=\"panel\">\n <div class=\"panel-header\">\n <slot name=\"title\">\n ${this.heading ? html`<span class=\"panel-title\">${this.heading}</span>` : null}\n </slot>\n <span class=\"panel-actions\"><slot name=\"actions\"></slot></span>\n <button class=\"close-btn\" aria-label=\"Close popover\" @click=${() => this.#close()}>\n ${iconX(18)}\n </button>\n </div>\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"popover-panel\": PopoverPanel;\n }\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
export type StatusPillColor = "neutral" | "info" | "primary" | "success" | "warning" | "danger";
|
|
3
|
+
/**
|
|
4
|
+
* Small colored status pill, optionally with a spinning icon — for task/run
|
|
5
|
+
* states ("Open", "Blocked", "Done") and live-activity indicators ("Running").
|
|
6
|
+
*
|
|
7
|
+
* @element status-pill
|
|
8
|
+
*/
|
|
9
|
+
export declare class StatusPill extends LitElement {
|
|
10
|
+
static styles: import("lit").CSSResult[];
|
|
11
|
+
/** Text shown inside the pill. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Color variant. */
|
|
14
|
+
color: StatusPillColor;
|
|
15
|
+
/** Renders a small spinning icon before the label. */
|
|
16
|
+
spinner: boolean;
|
|
17
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
18
|
+
}
|
|
19
|
+
declare global {
|
|
20
|
+
interface HTMLElementTagNameMap {
|
|
21
|
+
"status-pill": StatusPill;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=status-pill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-pill.d.ts","sourceRoot":"","sources":["../src/status-pill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhG;;;;;GAKG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,OAAgB,MAAM,4BAmDpB;IAEF,kCAAkC;IACtB,KAAK,SAAM;IACvB,qBAAqB;IACT,KAAK,EAAE,eAAe,CAAa;IAC/C,sDAAsD;IACzB,OAAO,UAAS;IAEpC,MAAM,yCAOd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html, nothing } from "lit";
|
|
8
|
+
import { customElement, property } from "lit/decorators.js";
|
|
9
|
+
import { iconArrowPath } from "./icons.js";
|
|
10
|
+
import { tokens } from "./tokens.js";
|
|
11
|
+
/**
|
|
12
|
+
* Small colored status pill, optionally with a spinning icon — for task/run
|
|
13
|
+
* states ("Open", "Blocked", "Done") and live-activity indicators ("Running").
|
|
14
|
+
*
|
|
15
|
+
* @element status-pill
|
|
16
|
+
*/
|
|
17
|
+
let StatusPill = class StatusPill extends LitElement {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
/** Text shown inside the pill. */
|
|
21
|
+
this.label = "";
|
|
22
|
+
/** Color variant. */
|
|
23
|
+
this.color = "neutral";
|
|
24
|
+
/** Renders a small spinning icon before the label. */
|
|
25
|
+
this.spinner = false;
|
|
26
|
+
}
|
|
27
|
+
static { this.styles = [
|
|
28
|
+
tokens,
|
|
29
|
+
css `
|
|
30
|
+
:host {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
}
|
|
33
|
+
.pill {
|
|
34
|
+
display: inline-flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 0.3rem;
|
|
37
|
+
border-radius: 999px;
|
|
38
|
+
padding: 0.15rem 0.55rem;
|
|
39
|
+
font-size: 0.75rem;
|
|
40
|
+
font-weight: 500;
|
|
41
|
+
font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
}
|
|
44
|
+
.pill.neutral {
|
|
45
|
+
background: color-mix(in srgb, var(--ui-text-muted, #71717a) 15%, transparent);
|
|
46
|
+
color: var(--ui-text-muted, #71717a);
|
|
47
|
+
}
|
|
48
|
+
.pill.info {
|
|
49
|
+
background: color-mix(in srgb, #0ea5e9 15%, transparent);
|
|
50
|
+
color: #0ea5e9;
|
|
51
|
+
}
|
|
52
|
+
.pill.primary {
|
|
53
|
+
background: color-mix(in srgb, var(--ui-primary, #4f46e5) 15%, transparent);
|
|
54
|
+
color: var(--ui-primary, #4f46e5);
|
|
55
|
+
}
|
|
56
|
+
.pill.success {
|
|
57
|
+
background: color-mix(in srgb, var(--ui-success, #16a34a) 15%, transparent);
|
|
58
|
+
color: var(--ui-success, #16a34a);
|
|
59
|
+
}
|
|
60
|
+
.pill.warning {
|
|
61
|
+
background: color-mix(in srgb, #d97706 15%, transparent);
|
|
62
|
+
color: #d97706;
|
|
63
|
+
}
|
|
64
|
+
.pill.danger {
|
|
65
|
+
background: color-mix(in srgb, var(--ui-danger, #dc2626) 15%, transparent);
|
|
66
|
+
color: var(--ui-danger, #dc2626);
|
|
67
|
+
}
|
|
68
|
+
.spin {
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
animation: spin 0.8s linear infinite;
|
|
71
|
+
}
|
|
72
|
+
@keyframes spin {
|
|
73
|
+
to {
|
|
74
|
+
transform: rotate(360deg);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
`,
|
|
78
|
+
]; }
|
|
79
|
+
render() {
|
|
80
|
+
return html `
|
|
81
|
+
<span class="pill ${this.color}">
|
|
82
|
+
${this.spinner ? html `<span class="spin">${iconArrowPath(11)}</span>` : nothing}
|
|
83
|
+
${this.label}
|
|
84
|
+
</span>
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
__decorate([
|
|
89
|
+
property()
|
|
90
|
+
], StatusPill.prototype, "label", void 0);
|
|
91
|
+
__decorate([
|
|
92
|
+
property()
|
|
93
|
+
], StatusPill.prototype, "color", void 0);
|
|
94
|
+
__decorate([
|
|
95
|
+
property({ type: Boolean })
|
|
96
|
+
], StatusPill.prototype, "spinner", void 0);
|
|
97
|
+
StatusPill = __decorate([
|
|
98
|
+
customElement("status-pill")
|
|
99
|
+
], StatusPill);
|
|
100
|
+
export { StatusPill };
|
|
101
|
+
//# sourceMappingURL=status-pill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-pill.js","sourceRoot":"","sources":["../src/status-pill.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;AAIrC;;;;;GAKG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QAsDL,kCAAkC;QACtB,UAAK,GAAG,EAAE,CAAC;QACvB,qBAAqB;QACT,UAAK,GAAoB,SAAS,CAAC;QAC/C,sDAAsD;QACzB,YAAO,GAAG,KAAK,CAAC;IAU/C,CAAC;aApEiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgDF;KACF,AAnDqB,CAmDpB;IASO,MAAM;QACb,OAAO,IAAI,CAAA;0BACW,IAAI,CAAC,KAAK;UAC1B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,sBAAsB,aAAa,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;UAC7E,IAAI,CAAC,KAAK;;KAEf,CAAC;IACJ,CAAC;CACF,CAAA;AAda;IAAX,QAAQ,EAAE;yCAAY;AAEX;IAAX,QAAQ,EAAE;yCAAoC;AAElB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;2CAAiB;AA3DlC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAqEtB","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\nexport type StatusPillColor = \"neutral\" | \"info\" | \"primary\" | \"success\" | \"warning\" | \"danger\";\n\n/**\n * Small colored status pill, optionally with a spinning icon — for task/run\n * states (\"Open\", \"Blocked\", \"Done\") and live-activity indicators (\"Running\").\n *\n * @element status-pill\n */\n@customElement(\"status-pill\")\nexport class StatusPill extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-flex;\n }\n .pill {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n border-radius: 999px;\n padding: 0.15rem 0.55rem;\n font-size: 0.75rem;\n font-weight: 500;\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n white-space: nowrap;\n }\n .pill.neutral {\n background: color-mix(in srgb, var(--ui-text-muted, #71717a) 15%, transparent);\n color: var(--ui-text-muted, #71717a);\n }\n .pill.info {\n background: color-mix(in srgb, #0ea5e9 15%, transparent);\n color: #0ea5e9;\n }\n .pill.primary {\n background: color-mix(in srgb, var(--ui-primary, #4f46e5) 15%, transparent);\n color: var(--ui-primary, #4f46e5);\n }\n .pill.success {\n background: color-mix(in srgb, var(--ui-success, #16a34a) 15%, transparent);\n color: var(--ui-success, #16a34a);\n }\n .pill.warning {\n background: color-mix(in srgb, #d97706 15%, transparent);\n color: #d97706;\n }\n .pill.danger {\n background: color-mix(in srgb, var(--ui-danger, #dc2626) 15%, transparent);\n color: var(--ui-danger, #dc2626);\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 `,\n ];\n\n /** Text shown inside the pill. */\n @property() label = \"\";\n /** Color variant. */\n @property() color: StatusPillColor = \"neutral\";\n /** Renders a small spinning icon before the label. */\n @property({ type: Boolean }) spinner = false;\n\n override render() {\n return html`\n <span class=\"pill ${this.color}\">\n ${this.spinner ? html`<span class=\"spin\">${iconArrowPath(11)}</span>` : nothing}\n ${this.label}\n </span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"status-pill\": StatusPill;\n }\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* A generic, presentational grid shell: renders one bordered card per entry
|
|
4
|
+
* in `items`, with each tile's content produced by `renderTile` (default:
|
|
5
|
+
* stringify). Knows nothing about what an "item" means — callers own the
|
|
6
|
+
* data shape entirely. Modeled directly on `data-table`'s headless pattern.
|
|
7
|
+
*
|
|
8
|
+
* Optional `itemHref` makes whole tiles clickable (navigating via
|
|
9
|
+
* `location.hash`), without hijacking clicks on nested interactive elements
|
|
10
|
+
* (links/buttons) a tile's rendered content might contain.
|
|
11
|
+
*
|
|
12
|
+
* @element tile-grid
|
|
13
|
+
*/
|
|
14
|
+
export declare class TileGrid extends LitElement {
|
|
15
|
+
#private;
|
|
16
|
+
static styles: import("lit").CSSResult[];
|
|
17
|
+
/** Tile data; opaque to this component beyond what `renderTile` does with it. */
|
|
18
|
+
items: unknown[];
|
|
19
|
+
/** Stable identity for `items[i]`, used as the repeat-directive key. Defaults to the item's index. */
|
|
20
|
+
itemKey: (item: unknown, index: number) => string | number;
|
|
21
|
+
/** Produces a tile's rendered content for `item`. Default: stringify. */
|
|
22
|
+
renderTile: (item: unknown) => unknown;
|
|
23
|
+
/** When set, clicking a tile (outside any nested link/button) navigates to this hash. */
|
|
24
|
+
itemHref: ((item: unknown) => string | null) | null;
|
|
25
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
26
|
+
}
|
|
27
|
+
declare global {
|
|
28
|
+
interface HTMLElementTagNameMap {
|
|
29
|
+
"tile-grid": TileGrid;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=tile-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-grid.d.ts","sourceRoot":"","sources":["../src/tile-grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C;;;;;;;;;;;GAWG;AACH,qBACa,QAAS,SAAQ,UAAU;;IACtC,OAAgB,MAAM,4BA0BpB;IAEF,iFAAiF;IACjD,KAAK,EAAE,OAAO,EAAE,CAAM;IACtD,sGAAsG;IACtE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAG/E;IACX,yEAAyE;IACzC,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAA0B;IAChG,yFAAyF;IACzD,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAQ;IASlF,MAAM,yCAiBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from "lit";
|
|
8
|
+
import { customElement, property } from "lit/decorators.js";
|
|
9
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
10
|
+
import { tokens } from "./tokens.js";
|
|
11
|
+
/**
|
|
12
|
+
* A generic, presentational grid shell: renders one bordered card per entry
|
|
13
|
+
* in `items`, with each tile's content produced by `renderTile` (default:
|
|
14
|
+
* stringify). Knows nothing about what an "item" means — callers own the
|
|
15
|
+
* data shape entirely. Modeled directly on `data-table`'s headless pattern.
|
|
16
|
+
*
|
|
17
|
+
* Optional `itemHref` makes whole tiles clickable (navigating via
|
|
18
|
+
* `location.hash`), without hijacking clicks on nested interactive elements
|
|
19
|
+
* (links/buttons) a tile's rendered content might contain.
|
|
20
|
+
*
|
|
21
|
+
* @element tile-grid
|
|
22
|
+
*/
|
|
23
|
+
let TileGrid = class TileGrid extends LitElement {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
/** Tile data; opaque to this component beyond what `renderTile` does with it. */
|
|
27
|
+
this.items = [];
|
|
28
|
+
/** Stable identity for `items[i]`, used as the repeat-directive key. Defaults to the item's index. */
|
|
29
|
+
this.itemKey = (_item, index) => index;
|
|
30
|
+
/** Produces a tile's rendered content for `item`. Default: stringify. */
|
|
31
|
+
this.renderTile = (item) => String(item);
|
|
32
|
+
/** When set, clicking a tile (outside any nested link/button) navigates to this hash. */
|
|
33
|
+
this.itemHref = null;
|
|
34
|
+
}
|
|
35
|
+
static { this.styles = [
|
|
36
|
+
tokens,
|
|
37
|
+
css `
|
|
38
|
+
:host {
|
|
39
|
+
display: block;
|
|
40
|
+
font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
|
|
41
|
+
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
42
|
+
}
|
|
43
|
+
.grid {
|
|
44
|
+
display: grid;
|
|
45
|
+
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
|
46
|
+
gap: 0.75rem;
|
|
47
|
+
}
|
|
48
|
+
.tile {
|
|
49
|
+
border: 1px solid var(--ui-border, #e2e8f0);
|
|
50
|
+
border-radius: var(--ui-radius, 0.5rem);
|
|
51
|
+
padding: 0.75rem;
|
|
52
|
+
color: var(--ui-text, #0f172a);
|
|
53
|
+
}
|
|
54
|
+
.tile.clickable {
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
}
|
|
57
|
+
.tile.clickable:hover {
|
|
58
|
+
background: var(--ui-surface-muted, #f8fafc);
|
|
59
|
+
}
|
|
60
|
+
`,
|
|
61
|
+
]; }
|
|
62
|
+
#onTileClick(item, e) {
|
|
63
|
+
if (!this.itemHref)
|
|
64
|
+
return;
|
|
65
|
+
if (e.target.closest("a, button"))
|
|
66
|
+
return;
|
|
67
|
+
const href = this.itemHref(item);
|
|
68
|
+
if (href)
|
|
69
|
+
location.hash = href;
|
|
70
|
+
}
|
|
71
|
+
render() {
|
|
72
|
+
return html `
|
|
73
|
+
<div class="grid">
|
|
74
|
+
${repeat(this.items, (item, i) => this.itemKey(item, i), (item) => html `
|
|
75
|
+
<div
|
|
76
|
+
class=${this.itemHref ? "tile clickable" : "tile"}
|
|
77
|
+
@click=${(e) => this.#onTileClick(item, e)}
|
|
78
|
+
>
|
|
79
|
+
${this.renderTile(item)}
|
|
80
|
+
</div>
|
|
81
|
+
`)}
|
|
82
|
+
</div>
|
|
83
|
+
`;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
__decorate([
|
|
87
|
+
property({ attribute: false })
|
|
88
|
+
], TileGrid.prototype, "items", void 0);
|
|
89
|
+
__decorate([
|
|
90
|
+
property({ attribute: false })
|
|
91
|
+
], TileGrid.prototype, "itemKey", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
property({ attribute: false })
|
|
94
|
+
], TileGrid.prototype, "renderTile", void 0);
|
|
95
|
+
__decorate([
|
|
96
|
+
property({ attribute: false })
|
|
97
|
+
], TileGrid.prototype, "itemHref", void 0);
|
|
98
|
+
TileGrid = __decorate([
|
|
99
|
+
customElement("tile-grid")
|
|
100
|
+
], TileGrid);
|
|
101
|
+
export { TileGrid };
|
|
102
|
+
//# sourceMappingURL=tile-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-grid.js","sourceRoot":"","sources":["../src/tile-grid.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,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;GAWG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,UAAU;IAAjC;;QA6BL,iFAAiF;QACjD,UAAK,GAAc,EAAE,CAAC;QACtD,sGAAsG;QACtE,YAAO,GAAsD,CAC3F,KAAK,EACL,KAAK,EACL,EAAE,CAAC,KAAK,CAAC;QACX,yEAAyE;QACzC,eAAU,GAA+B,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChG,yFAAyF;QACzD,aAAQ,GAA8C,IAAI,CAAC;IA2B7F,CAAC;aAjEiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;KAuBF;KACF,AA1BqB,CA0BpB;IAcF,YAAY,CAAC,IAAa,EAAE,CAAa;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAK,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,WAAW,CAAC;YAAE,OAAO;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,IAAI;YAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;IACjC,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;UAEL,MAAM,CACN,IAAI,CAAC,KAAK,EACV,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAClC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;;sBAEF,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM;uBACxC,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;;gBAEpD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;;WAE1B,CACF;;KAEJ,CAAC;IACJ,CAAC;CACF,CAAA;AApCiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;uCAAuB;AAEtB;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;yCAGpB;AAEqB;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;4CAAiE;AAEhE;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;0CAA4D;AAvChF,QAAQ;IADpB,aAAa,CAAC,WAAW,CAAC;GACd,QAAQ,CAkEpB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A generic, presentational grid shell: renders one bordered card per entry\n * in `items`, with each tile's content produced by `renderTile` (default:\n * stringify). Knows nothing about what an \"item\" means — callers own the\n * data shape entirely. Modeled directly on `data-table`'s headless pattern.\n *\n * Optional `itemHref` makes whole tiles clickable (navigating via\n * `location.hash`), without hijacking clicks on nested interactive elements\n * (links/buttons) a tile's rendered content might contain.\n *\n * @element tile-grid\n */\n@customElement(\"tile-grid\")\nexport class TileGrid extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n .grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n gap: 0.75rem;\n }\n .tile {\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n padding: 0.75rem;\n color: var(--ui-text, #0f172a);\n }\n .tile.clickable {\n cursor: pointer;\n }\n .tile.clickable:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n `,\n ];\n\n /** Tile data; opaque to this component beyond what `renderTile` does with it. */\n @property({ attribute: false }) items: unknown[] = [];\n /** Stable identity for `items[i]`, used as the repeat-directive key. Defaults to the item's index. */\n @property({ attribute: false }) itemKey: (item: unknown, index: number) => string | number = (\n _item,\n index,\n ) => index;\n /** Produces a tile's rendered content for `item`. Default: stringify. */\n @property({ attribute: false }) renderTile: (item: unknown) => unknown = (item) => String(item);\n /** When set, clicking a tile (outside any nested link/button) navigates to this hash. */\n @property({ attribute: false }) itemHref: ((item: unknown) => string | null) | null = null;\n\n #onTileClick(item: unknown, e: MouseEvent): void {\n if (!this.itemHref) return;\n if ((e.target as HTMLElement).closest(\"a, button\")) return;\n const href = this.itemHref(item);\n if (href) location.hash = href;\n }\n\n override render() {\n return html`\n <div class=\"grid\">\n ${repeat(\n this.items,\n (item, i) => this.itemKey(item, i),\n (item) => html`\n <div\n class=${this.itemHref ? \"tile clickable\" : \"tile\"}\n @click=${(e: MouseEvent) => this.#onTileClick(item, e)}\n >\n ${this.renderTile(item)}\n </div>\n `,\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"tile-grid\": TileGrid;\n }\n}\n"]}
|