@kit-data-manager/pid-component
Version:
The PID-Component is a web component that can be used to evaluate and display FAIR Digital Objects, PIDs, ORCiDs, and possibly other identifiers in a user-friendly way. It is easily extensible to support other identifier types.
1,075 lines (1,066 loc) • 104 kB
JavaScript
/*!
*
* Copyright 2024-2026 Karlsruhe Institute of Technology.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { r as registerInstance, h, H as Host, c as getElement, d as createEvent } from './index-BeCqCMz1.js';
import { r as renderers, c as clearCache } from './PID-CeLI8GZT.js';
import './json-viewer.entry.js';
const CopyButton = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.copied = false;
this.darkMode = 'light';
this.copyValue = (event) => {
event.stopPropagation();
event.preventDefault();
const textArea = document.createElement('textarea');
textArea.value = this.value;
textArea.setAttribute('aria-hidden', 'true');
textArea.setAttribute('readonly', 'readonly');
textArea.style.cssText = 'position:fixed;top:0;left:0;width:2em;height:2em;padding:0;border:none;outline:none;box-shadow:none;opacity:0;';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
textArea.setSelectionRange(0, textArea.value.length);
let copied = false;
try {
copied = document.execCommand('copy');
}
catch (_) {
}
document.body.removeChild(textArea);
if (copied) {
this.showSuccess();
return;
}
if ('clipboard' in navigator) {
navigator.clipboard.writeText(this.value).then(() => this.showSuccess(), () => {
});
}
};
}
getIsDarkMode() {
if (this.darkMode === 'dark') {
return true;
}
if (this.darkMode === 'light') {
return false;
}
const parentComponent = this.el.closest('pid-component');
if (parentComponent === null || parentComponent === void 0 ? void 0 : parentComponent.classList.contains('bg-gray-800')) {
return true;
}
if (this.darkMode === 'system') {
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return false;
}
render() {
const buttonText = this.copied ? '✓ Copied!' : 'Copy';
const ariaLabel = this.getAriaLabel();
const isDarkMode = this.getIsDarkMode();
return (h(Host, { key: 'c5c3499428ec7ab4b306458dc25af78c26e1b91d', class: 'inline-block align-baseline text-xs' }, this.copied && (h("span", { key: 'eab38ff718680f01488fb1a3fe0cf36547a09daa', class: "sr-only", "aria-live": "assertive" }, "Content copied to clipboard")), h("button", { key: 'ac8d35bc7e2cb5038846adc8134b20ca31ac09e0', class: `${this.copied ? (isDarkMode ? 'bg-green-700' : 'bg-green-200') : isDarkMode ? 'bg-gray-700 hover:bg-gray-600' : 'bg-white hover:bg-blue-200'} relative z-30 max-h-min flex-none items-center rounded-md border ${isDarkMode ? 'border-gray-600 text-gray-200 hover:text-white' : 'border-slate-500 text-slate-800 hover:text-slate-900'} px-2 py-0.5 font-mono font-medium transition-colors duration-200 focus:ring-2 focus:ring-blue-500 focus:ring-offset-1 focus:outline-hidden`, onClick: e => this.copyValue(e), "aria-label": ariaLabel, title: ariaLabel, type: "button" }, buttonText)));
}
showSuccess() {
this.copied = true;
setTimeout(() => {
this.copied = false;
}, 1500);
}
getAriaLabel() {
const baseLabel = this.label || 'content';
return this.copied ? `${baseLabel} copied to clipboard` : `Copy ${baseLabel} to clipboard`;
}
get el() { return getElement(this); }
};
const PidActions = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.actions = [];
this.darkMode = 'system';
}
render() {
if (this.actions.length === 0) {
return null;
}
const isDarkMode = this.darkMode === 'dark' || (this.darkMode === 'system' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
const containerId = this.actionsId || `actions-${Math.random().toString(36).substring(2, 11)}`;
return (h("div", { id: containerId, class: `actions-container sticky right-0 bottom-0 left-0 z-20 w-full ${isDarkMode ? 'bg-gray-800' : 'bg-white'}`, role: "toolbar", "aria-label": "Available actions" }, h("span", { id: `${containerId}-desc`, class: "sr-only" }, "The following links open related resources in new tabs"), h("div", { class: "flex flex-wrap justify-between gap-1", "aria-describedby": `${containerId}-desc` }, this.actions.map((action, index) => {
const baseClasses = 'p-1 font-semibold text-sm rounded-sm border transition-colors duration-200';
const focusClasses = 'focus:outline-hidden focus:ring-2 focus:ring-offset-1 focus:ring-blue-500';
let styleClasses;
if (isDarkMode) {
switch (action.style) {
case 'primary':
styleClasses = 'bg-blue-700 text-white hover:bg-blue-600 border-blue-600';
break;
case 'secondary':
styleClasses = 'bg-slate-700 text-blue-300 hover:bg-slate-600 border-slate-600';
break;
case 'danger':
styleClasses = 'bg-red-700 text-white hover:bg-red-600 border-red-600';
break;
default:
styleClasses = 'bg-gray-700 text-gray-200 hover:bg-gray-600 border-gray-600';
}
}
else {
switch (action.style) {
case 'primary':
styleClasses = 'bg-blue-500 text-white hover:bg-blue-600 border-blue-400';
break;
case 'secondary':
styleClasses = 'bg-slate-200 text-blue-500 hover:bg-slate-300 border-slate-300';
break;
case 'danger':
styleClasses = 'bg-red-500 text-white hover:bg-red-600 border-red-400';
break;
default:
styleClasses = 'bg-gray-200 text-gray-700 hover:bg-gray-300 border-gray-300';
}
}
return (h("a", { key: `action-${action.title}-${index}`, href: action.link, class: `${baseClasses} ${styleClasses} ${focusClasses}`, rel: "noopener noreferrer", target: "_blank", "aria-label": `${action.title} (opens in new tab)`, title: `${action.title} - Opens in a new tab` }, h("span", null, action.title), h("span", { class: "sr-only" }, "(opens in new tab)")));
}))));
}
};
const collapsibleCss = () => `details summary::-webkit-details-marker{display:none}pid-collapsible.resize-both{resize:both!important;overflow:auto!important;max-width:100%!important;will-change:width,height;transition:none!important}pid-collapsible[expanded]{position:absolute;z-index:50;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1)}@media not all and (min-resolution:.001dpcm){@supports (-webkit-appearance:none){pid-collapsible details{display:flex!important;flex-direction:column!important}pid-collapsible details summary{display:block!important}pid-collapsible.resize-both{-webkit-resize:both!important;resize:both!important;overflow:auto!important;position:relative!important}pid-collapsible.resize-both:after{content:"";position:absolute;bottom:0;right:0;width:15px;height:15px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='currentColor' stroke-linecap='round' stroke-width='2' d='M22 2 2 22M22 8 8 22M22 14l-8 8'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:100% 100%;cursor:nwse-resize;z-index:10;pointer-events:none}}}pid-collapsible.resize-both:after{content:"";position:absolute;bottom:0;right:0;width:15px;height:15px;cursor:nwse-resize;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='currentColor' stroke-linecap='round' stroke-width='2' d='M22 2 2 22M22 8 8 22M22 14l-8 8'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:100% 100%;z-index:10;pointer-events:none}@supports (-webkit-appearance:none) and (not (display:-webkit-box)){pid-collapsible.resize-both{resize:both!important;overflow:auto!important;display:block!important;position:relative!important}pid-collapsible.resize-both:before{content:"";display:block;width:100%;height:100%;position:absolute;top:0;left:0;pointer-events:none;z-index:-1}}@supports (-webkit-appearance:none){pid-collapsible details{display:-webkit-box!important;display:-webkit-flex!important;display:flex!important;-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-webkit-flex-direction:column!important;flex-direction:column!important;min-height:100%}}@media (-webkit-min-device-pixel-ratio:0) and (min-resolution:.001dpcm){pid-collapsible{-webkit-transform:translateZ(0);transform:translateZ(0)}pid-collapsible.resizing{pointer-events:none;contain:layout size}pid-collapsible.resize-both{-webkit-resize:both!important}pid-collapsible.resize-both:after{content:"";position:absolute;bottom:0;right:0;width:15px;height:15px;cursor:nwse-resize;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='currentColor' stroke-linecap='round' stroke-width='2' d='M22 2 2 22M22 8 8 22M22 14l-8 8'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:100% 100%;z-index:10;pointer-events:none}}:root{--z-back:-1;--z-resize:10;--z-content:20;--z-footer:30;--z-header:50}:host{display:block;--initial-width:500px;--initial-height:300px;--min-width:300px;--min-height:200px}@media (max-width:768px){:host{--initial-width:400px;--min-width:250px}}@media (max-width:480px){:host{--initial-width:300px;--min-width:200px}}@media (prefers-contrast:more){pid-collapsible summary{border:1px solid}pid-collapsible.resize-both:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='currentColor' stroke-linecap='round' stroke-width='3' d='M22 2 2 22M22 8 8 22M22 14l-8 8'/%3E%3C/svg%3E");opacity:.9}}@media print{pid-collapsible.resize-both{resize:none!important}pid-collapsible.resize-both:after{display:none!important}}pid-collapsible summary:focus-visible{outline:2px solid #0ea5e9;outline-offset:2px}pid-collapsible .overflow-visible,pid-pagination .overflow-visible{overflow:visible!important}`;
const CONSTANTS = {
DEFAULT_WIDTH: '500px',
DEFAULT_HEIGHT: '300px',
MIN_WIDTH: 300,
MIN_HEIGHT: 200,
PADDING_WIDTH: 40,
PADDING_HEIGHT: 60,
FOOTER_HEIGHT: 60,
};
const Z_INDICES = {
RESIZE_HANDLE: 10,
FOOTER_CONTENT: 30,
STICKY_ELEMENTS: 50,
};
const RESIZE_INDICATOR_SVG = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22 2L2 22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M22 8L8 22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M22 14L14 22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
`;
const PidCollapsible = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.collapsibleToggle = createEvent(this, "collapsibleToggle");
this.contentHeightChange = createEvent(this, "contentHeightChange");
this.open = false;
this.emphasize = false;
this.darkMode = 'system';
this.lineHeight = 24;
this.showFooter = false;
this.expanded = false;
this.previewScrollable = false;
this.isDarkMode = false;
this.isToggling = false;
this.lastClickTime = 0;
this.pendingClickTimer = null;
this.resizeDebounceTimer = null;
this.lastResizeDimensions = { width: 0, height: 0 };
this.handleDarkModeChange = () => {
this.updateDarkMode();
};
this.handlePageChange = (event) => {
console.debug('Page changed to:', event.detail);
this.recalculateContentDimensions();
};
this.handleSafariCompatibility = (e) => {
if (!this.isSafari() || this.isToggling)
return;
const target = e.target;
if ((target === null || target === void 0 ? void 0 : target.closest('copy-button')) || (target === null || target === void 0 ? void 0 : target.closest('[slot="summary-actions"]')) ||
(target === null || target === void 0 ? void 0 : target.closest('button')) || (target === null || target === void 0 ? void 0 : target.closest('a'))) {
return;
}
e.preventDefault();
e.stopPropagation();
this.performToggle(!this.open);
};
this.handleToggle = (event) => {
event.preventDefault();
event.stopPropagation();
const details = this.el.querySelector('details');
if (details) {
details.open = this.open;
}
};
this.handleSummaryClick = (event) => {
const path = event.composedPath();
const clickedInteractive = path.some(el => {
var _a;
return el instanceof HTMLElement && (el.tagName === 'BUTTON' ||
el.tagName === 'A' ||
el.tagName === 'COPY-BUTTON' ||
el.tagName === 'PID-ACTIONS' ||
((_a = el.getAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'role')) === 'button');
});
if (clickedInteractive) {
return;
}
event.preventDefault();
event.stopPropagation();
if (this.isToggling)
return;
const now = Date.now();
const elapsed = now - this.lastClickTime;
this.lastClickTime = now;
if (this.pendingClickTimer !== null) {
clearTimeout(this.pendingClickTimer);
this.pendingClickTimer = null;
}
if (elapsed < 300 && this.open) {
this.performToggle(false);
}
else {
this.pendingClickTimer = setTimeout(() => {
this.pendingClickTimer = null;
this.performToggle(!this.open);
}, 200);
}
};
}
watchOpen() {
this.updateAppearance();
if (this.open)
this.recalculateContentDimensions();
}
watchDarkMode() {
this.updateDarkMode();
}
componentWillLoad() {
this.currentWidth = this.initialWidth || CONSTANTS.DEFAULT_WIDTH;
this.currentHeight = this.initialHeight || CONSTANTS.DEFAULT_HEIGHT;
this.initializeDarkMode();
}
componentDidLoad() {
this.setupResizeObserver();
this.updateAppearance();
this.addBrowserCompatibilityListeners();
this.addComponentEventListeners();
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
this.el.style.verticalAlign = 'top';
}
}
disconnectedCallback() {
this.cleanupResources();
this.cleanupDarkModeListener();
}
async recalculateContentDimensions() {
if (this.open) {
if (this.resizeDebounceTimer !== null) {
window.cancelAnimationFrame(this.resizeDebounceTimer);
}
return new Promise(resolve => {
this.resizeDebounceTimer = window.requestAnimationFrame(() => {
if (this.lastExpandedWidth) {
this.currentWidth = this.lastExpandedWidth;
}
else {
this.currentWidth = this.initialWidth || this.getResponsiveDefaultWidth();
}
this.el.style.width = this.currentWidth;
this.el.style.height = 'auto';
this.el.style.maxHeight = 'max-content';
requestAnimationFrame(() => {
if (this.open) {
const actualHeight = this.el.scrollHeight;
this.el.style.height = `${actualHeight}px`;
this.el.style.maxHeight = `${actualHeight}px`;
}
this.lastExpandedWidth = this.currentWidth;
const dimensions = this.calculateContentDimensions();
this.contentHeightChange.emit({ maxHeight: dimensions.maxHeight });
this.resizeDebounceTimer = null;
resolve(dimensions);
});
});
});
}
return null;
}
render() {
const hostClasses = this.getHostClasses();
const detailsClasses = this.getDetailsClasses();
const summaryClasses = this.getSummaryClasses();
const contentClasses = this.getContentClasses();
const footerClasses = this.getFooterClasses();
const footerActionsClasses = this.getFooterActionsClasses();
return (h(Host, { key: 'cbcf55c166323c79e344ead5bd5811d19088c6e4', class: hostClasses }, h("details", { key: '6b2e144d57340c7fc0637c62a1e618429ff423b4', class: detailsClasses, open: this.open, onToggle: this.handleToggle }, h("summary", { key: '4c053bf0b5a0609e7e5f37abf0892dc459dc08a5', class: summaryClasses, onClick: this.handleSummaryClick }, this.emphasize && (h("span", { key: '8a264bf2bd3223734bf3df20b244c987a02bb1dd' }, h("svg", { key: '2ea1c2df5db8316f4bdc14f3d1e1f2c8b3bb9403', class: `${this.isDarkMode ? 'text-gray-300' : 'text-gray-600'} transition-transform duration-200 group-open:rotate-180 mr-2 ml-1`, fill: "none", height: "12", width: "12", stroke: "currentColor", "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "1.5", viewBox: "0 0 12 12", "aria-hidden": "true" }, h("path", { key: '3c4e317acb12ea1ac020f5ea6fe654c0b154ce0e', d: "M 2 3 l 4 6 l 4 -6" })))), h("span", { key: '3cbead450cf92831327ff381033ebe4c499af442', class: `block ${this.previewScrollable ? 'shrink-0' : 'min-w-0 whitespace-nowrap overflow-hidden text-ellipsis'}` }, h("slot", { key: '5706002a1de3ed07ddf9f5fc21e9c223c36b3eb4', name: "summary" })), h("div", { key: 'ca8c041962942bb4eec5d713aa6ad34d4dbd021a', class: `ml-auto shrink-0 ${this.previewScrollable ? 'sticky right-0' : ''}` }, h("slot", { key: '6fc238f5b0b681da07e37ae57e3aa1d3146e1895', name: "summary-actions" }))), h("div", { key: '41d4b51f1e6fd78ed9ff8e1fa7f7bb3dcfc45a25', class: `${contentClasses}` }, h("slot", { key: 'ef9f60ae2c92cbae6d16b68b68aa9def3b9c806b' })), this.showFooter && this.open && (h("div", { key: '2dade649916ee68dd3fe367e485ad5bbacd644d9', class: footerClasses }, h("div", { key: 'db9ac1fe6b58291e6ccd4f214b2123832962ccd4', class: `z-50 overflow-visible border-b ${this.isDarkMode ? 'border-gray-700 bg-gray-800' : 'border-gray-100 bg-white'}` }, h("slot", { key: '36ee7ecacee44fdf2a1f2e8d92a83f7e980f1ea7', name: "footer" })), h("div", { key: '38969d3f4c65671dc51e66cfbc076094115cb38c', class: footerActionsClasses }, h("div", { key: '9666f30918d3c437211c33d351e0d3cdc9a9ffd6', class: "grow overflow-visible" }, h("slot", { key: 'fb9431b73a3d54bf2d85db2ce51565a161b67715', name: "footer-left" })), h("div", { key: 'a599293e40865c70bf9936a4e3c377cf833986cc', class: "flex shrink-0 items-center gap-2 overflow-visible" }, h("slot", { key: '57c7cfe3db67cc7706d32281b1b580bd705f5432', name: "footer-actions" }))))))));
}
initializeDarkMode() {
if (window.matchMedia) {
this.darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
this.updateDarkMode();
if (this.darkModeMediaQuery.addEventListener) {
this.darkModeMediaQuery.addEventListener('change', this.handleDarkModeChange);
}
else if (this.darkModeMediaQuery.addListener) {
this.darkModeMediaQuery.addListener(this.handleDarkModeChange);
}
}
else {
this.isDarkMode = this.darkMode === 'dark';
}
}
updateDarkMode() {
if (this.darkMode === 'dark') {
this.isDarkMode = true;
}
else if (this.darkMode === 'light') {
this.isDarkMode = false;
}
else if (this.darkMode === 'system' && this.darkModeMediaQuery) {
this.isDarkMode = this.darkModeMediaQuery.matches;
}
}
cleanupDarkModeListener() {
if (this.darkModeMediaQuery) {
if (this.darkModeMediaQuery.removeEventListener) {
this.darkModeMediaQuery.removeEventListener('change', this.handleDarkModeChange);
}
else if (this.darkModeMediaQuery.removeListener) {
this.darkModeMediaQuery.removeListener(this.handleDarkModeChange);
}
}
}
setupResizeObserver() {
if (!window.ResizeObserver) {
console.warn('ResizeObserver not supported in this browser');
return;
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
this.resizeObserver = new ResizeObserver(entries => {
if (!this.open)
return;
const entry = entries[0];
if (!entry)
return;
const width = entry.contentRect.width;
const height = entry.contentRect.height;
if (Math.abs(width - this.lastResizeDimensions.width) < 2 && Math.abs(height - this.lastResizeDimensions.height) < 2) {
return;
}
this.lastResizeDimensions = { width, height };
if (this.resizeDebounceTimer !== null) {
window.cancelAnimationFrame(this.resizeDebounceTimer);
}
this.resizeDebounceTimer = window.requestAnimationFrame(() => {
this.currentWidth = `${width}px`;
this.currentHeight = `${height}px`;
this.resizeDebounceTimer = null;
});
});
if (this.open) {
this.resizeObserver.observe(this.el);
}
}
addBrowserCompatibilityListeners() {
const details = this.el.querySelector('details');
if (!details)
return;
const summary = details.querySelector('summary');
if (!summary)
return;
summary.addEventListener('click', this.handleSafariCompatibility, { capture: true });
}
isSafari() {
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent) && !/CriOS|FxiOS|EdgiOS/i.test(navigator.userAgent);
}
addComponentEventListeners() {
const dataTables = this.el.querySelectorAll('pid-data-table');
dataTables.forEach(dataTable => {
dataTable.addEventListener('pageChange', this.handlePageChange);
});
}
removeComponentEventListeners() {
const dataTables = this.el.querySelectorAll('pid-data-table');
dataTables.forEach(dataTable => {
dataTable.removeEventListener('pageChange', this.handlePageChange);
});
}
cleanupResources() {
if (this.resizeDebounceTimer !== null) {
window.cancelAnimationFrame(this.resizeDebounceTimer);
this.resizeDebounceTimer = null;
}
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
this.removeComponentEventListeners();
const details = this.el.querySelector('details');
if (details) {
const summary = details.querySelector('summary');
if (summary) {
summary.removeEventListener('click', this.handleSafariCompatibility, { capture: true });
}
}
}
updateAppearance() {
this.resetStyles();
if (this.open) {
this.applyExpandedStyles();
}
else {
this.applyCollapsedStyles();
}
}
resetStyles() {
const classesToRemove = ['resize-both', 'overflow-auto', 'w-auto', 'inline-block', 'align-middle', 'align-top', 'overflow-hidden', 'py-0', 'my-0', 'float-left', 'bg-white', 'block'];
classesToRemove.forEach(cls => {
if (this.el.classList.contains(cls)) {
this.el.classList.remove(cls);
}
});
this.el.style.width = '';
this.el.style.height = '';
this.el.style.maxWidth = '';
this.el.style.maxHeight = '';
this.el.style.resize = '';
this.el.style.lineHeight = '';
this.el.style.overflow = '';
}
applyExpandedStyles() {
try {
this.el.classList.add('resize-both', 'relative', 'block');
if (this.emphasize) {
this.el.classList.add('bg-white');
}
if (this.lastExpandedWidth) {
this.currentWidth = this.lastExpandedWidth;
}
else if (this.initialWidth) {
this.currentWidth = this.initialWidth;
}
else {
this.currentWidth = this.getResponsiveDefaultWidth();
}
this.el.style.width = this.currentWidth;
this.el.style.height = 'auto';
this.el.style.maxHeight = 'max-content';
const summary = this.el.querySelector('summary');
if (summary) {
summary.style.height = `${this.lineHeight}px`;
summary.style.minHeight = `${this.lineHeight}px`;
summary.style.maxHeight = `${this.lineHeight}px`;
}
this.el.style.resize = 'both';
this.addResizeIndicator();
requestAnimationFrame(() => {
if (this.open) {
const actualHeight = this.el.scrollHeight;
this.el.style.height = `${actualHeight}px`;
this.el.style.maxHeight = `${actualHeight}px`;
}
});
if (this.resizeObserver) {
this.resizeObserver.observe(this.el);
}
}
catch (error) {
console.error('Failed to apply expanded styles:', error);
}
}
getResponsiveDefaultWidth() {
var _a;
let node = this.el;
while (node) {
const root = node.getRootNode();
if (root instanceof ShadowRoot) {
node = root.host;
continue;
}
if (node instanceof HTMLElement) {
const tag = node.tagName.toLowerCase();
if (tag === 'pid-component' || tag === 'pid-collapsible') {
node = node.parentElement;
continue;
}
}
break;
}
const container = node instanceof HTMLElement ? node : null;
const availableWidth = (_a = container === null || container === void 0 ? void 0 : container.clientWidth) !== null && _a !== void 0 ? _a : window.innerWidth;
if (availableWidth < 600) {
return '100%';
}
if (availableWidth <= 1024) {
return '70%';
}
return '50%';
}
calculateContentDimensions() {
const contentElement = this.el.querySelector('.grow');
const contentWidth = (contentElement === null || contentElement === void 0 ? void 0 : contentElement.scrollWidth) || CONSTANTS.MIN_WIDTH;
const contentHeight = (contentElement === null || contentElement === void 0 ? void 0 : contentElement.scrollHeight) || CONSTANTS.MIN_HEIGHT;
const footerHeight = this.showFooter ? CONSTANTS.FOOTER_HEIGHT : 0;
const maxWidth = contentWidth + CONSTANTS.PADDING_WIDTH;
const maxHeight = contentHeight + CONSTANTS.PADDING_HEIGHT + footerHeight;
return { contentWidth, contentHeight, maxWidth, maxHeight };
}
applyCollapsedStyles() {
if (this.el.style.width && this.el.style.width !== 'auto') {
this.lastExpandedWidth = this.el.style.width;
this.currentWidth = this.el.style.width;
}
if (this.el.style.height && this.el.style.height !== `${this.lineHeight}px`) {
this.lastExpandedHeight = this.el.style.height;
this.currentHeight = this.el.style.height;
}
if (this.lastExpandedWidth || this.lastExpandedHeight) {
console.debug('Storing dimensions for later restoration:', {
width: this.lastExpandedWidth,
height: this.lastExpandedHeight,
});
}
this.el.style.maxWidth = '';
this.el.style.maxHeight = '';
this.el.style.width = 'auto';
this.el.classList.add('w-auto', 'inline-block', 'py-0', 'my-0');
this.el.style.overflow = 'clip';
this.el.style.height = `${this.lineHeight}px`;
this.el.style.lineHeight = `${this.lineHeight}px`;
this.el.style.minHeight = `${this.lineHeight}px`;
this.el.style.maxHeight = `${this.lineHeight}px`;
if (this.isSafari()) {
this.el.style.marginBottom = '1px';
this.el.style.verticalAlign = 'top';
}
this.el.style.resize = 'none';
this.removeResizeIndicator();
if (this.resizeObserver) {
this.resizeObserver.unobserve(this.el);
}
}
addResizeIndicator() {
try {
this.removeResizeIndicator();
const resizeIndicator = document.createElement('div');
resizeIndicator.className = `absolute bottom-0 right-0 w-4 h-4 opacity-60 pointer-events-none resize-indicator cursor-nwse-resize text-slate-400 z-${Z_INDICES.RESIZE_HANDLE}`;
resizeIndicator.innerHTML = RESIZE_INDICATOR_SVG;
resizeIndicator.setAttribute('aria-hidden', 'true');
this.el.appendChild(resizeIndicator);
}
catch (error) {
console.error('Failed to add resize indicator:', error);
}
}
removeResizeIndicator() {
const resizeIndicators = this.el.querySelectorAll('.resize-indicator');
resizeIndicators.forEach(indicator => indicator.remove());
}
performToggle(newOpen) {
this.isToggling = true;
const details = this.el.querySelector('details');
this.open = newOpen;
if (details) {
details.open = newOpen;
}
this.collapsibleToggle.emit(this.open);
this.updateAppearance();
if (this.open && this.isSafari()) {
setTimeout(() => this.recalculateContentDimensions(), 50);
}
setTimeout(() => {
if (details)
details.open = this.open;
this.isToggling = false;
}, 50);
}
getHostClasses() {
const baseClasses = ['relative', 'font-sans', 'leading-normal'];
if (this.emphasize) {
baseClasses.push('box-border', 'border', 'rounded-md', 'shadow-xs');
if (this.isDarkMode) {
baseClasses.push('border-gray-600');
}
else {
baseClasses.push('border-gray-300');
}
}
if (this.open) {
baseClasses.push('mb-2', 'max-w-full', 'text-xs', 'block');
}
else {
baseClasses.push(this.initialWidth === '100%' ? 'max-w-full' : 'max-w-md');
baseClasses.push('my-0', 'text-sm', 'inline-block');
}
if (this.isDarkMode) {
baseClasses.push('text-white');
}
return baseClasses.join(' ');
}
getDetailsClasses() {
const baseClasses = ['group', 'w-full', 'font-sans', 'transition-all', 'duration-200', 'ease-in-out', 'flex', 'flex-col'];
if (this.open) ;
else {
baseClasses.push('text-clip', 'overflow-hidden');
}
if (this.isDarkMode) {
baseClasses.push('bg-gray-800', 'text-white');
}
return baseClasses.join(' ');
}
getSummaryClasses() {
const baseClasses = [
'font-bold',
'font-mono',
'cursor-pointer',
'list-none',
'flex',
'items-center',
'focus:outline-hidden',
'focus-visible:ring-2',
'focus-visible:ring-blue-400',
'focus-visible:ring-offset-1',
'rounded-lg',
'marker:hidden',
'[&::-webkit-details-marker]:hidden',
'select-none',
'py-0',
'min-w-1/10',
];
if (this.open) {
baseClasses.push('sticky', 'top-0', `z-${Z_INDICES.STICKY_ELEMENTS}`, 'overflow-x-auto', 'backdrop-blur-xs');
if (this.isDarkMode) {
baseClasses.push('bg-gray-800');
if (this.emphasize) {
baseClasses.push('border-b', 'box-border', 'border-gray-700');
}
}
else {
baseClasses.push('bg-white', 'text-ellipsis');
if (this.emphasize) {
baseClasses.push('border-b', 'box-border', 'border-gray-100');
}
}
}
else {
baseClasses.push('whitespace-nowrap', 'overflow-hidden', 'text-ellipsis', 'truncate', 'max-w-full');
}
baseClasses.push(`h-[${this.lineHeight}px]`);
return baseClasses.join(' ');
}
getContentClasses() {
const baseClasses = ['grow', 'flex', 'flex-col', 'min-h-0'];
if (this.open) ;
else {
baseClasses.push('overflow-hidden', 'p-0');
}
if (this.isDarkMode) {
baseClasses.push('bg-gray-800', 'text-white');
}
return baseClasses.join(' ');
}
getFooterClasses() {
const baseClasses = ['flex', 'flex-col', 'w-full', 'mt-auto', 'sticky', 'bottom-0', 'left-0', 'right-0', 'border-t', `z-${Z_INDICES.FOOTER_CONTENT}`, 'backdrop-blur-xs'];
if (this.isDarkMode) {
baseClasses.push('bg-gray-800', 'border-gray-700');
}
else {
baseClasses.push('bg-white', 'border-gray-200');
}
return baseClasses.join(' ');
}
getFooterActionsClasses() {
const baseClasses = ['flex', 'items-center', 'justify-between', 'gap-2', 'p-1', 'min-h-12', 'shrink-0', 'overflow-x-auto'];
if (this.isDarkMode) {
baseClasses.push('bg-gray-800');
}
else {
baseClasses.push('bg-white');
}
return baseClasses.join(' ');
}
get el() { return getElement(this); }
static get watchers() { return {
"open": [{
"watchOpen": 0
}],
"darkMode": [{
"watchDarkMode": 0
}]
}; }
};
PidCollapsible.style = collapsibleCss();
function getEffectiveRenderers(orderedRendererKeys) {
if (!orderedRendererKeys || orderedRendererKeys.length === 0) {
return renderers;
}
const result = [];
for (const key of orderedRendererKeys) {
const found = renderers.find(r => r.key === key);
if (found) {
result.push(found);
}
else {
console.warn(`Parser: Unknown renderer key "${key}" in ordered renderer list, skipping.`);
}
}
return result;
}
class Parser {
static async getEstimatedPriority(value) {
for (let i = 0; i < renderers.length; i++) {
const obj = new renderers[i].constructor(value);
const quickResult = obj.quickCheck();
if (quickResult === true) {
return i;
}
if (quickResult === undefined) {
const hasMeaningful = await obj.hasMeaningfulInformation();
if (hasMeaningful) {
return i;
}
}
}
return 0;
}
static getBestFitQuick(value, orderedRendererKeys) {
const effective = getEffectiveRenderers(orderedRendererKeys);
if (orderedRendererKeys && orderedRendererKeys.length > 0) {
for (const entry of effective) {
const obj = new entry.constructor(value);
if (obj.quickCheck()) {
return entry.key;
}
}
return null;
}
let bestKey = null;
for (let i = effective.length - 1; i >= 0; i--) {
const entry = effective[i];
const obj = new entry.constructor(value);
if (obj.quickCheck() && entry.key !== 'FallbackType') {
bestKey = entry.key;
}
}
return bestKey;
}
static async getBestFit(value, settings, orderedRendererKeys, fallbackToAll = true) {
const effective = getEffectiveRenderers(orderedRendererKeys);
const hasOrderedList = orderedRendererKeys && orderedRendererKeys.length > 0;
if (hasOrderedList) {
for (const entry of effective) {
const obj = new entry.constructor(value);
const quickResult = obj.quickCheck();
if (quickResult === true) {
Parser.applySettings(obj, settings);
await obj.init();
return obj;
}
if (quickResult === undefined || !quickResult) {
if (await obj.hasMeaningfulInformation()) {
Parser.applySettings(obj, settings);
await obj.init();
return obj;
}
}
}
if (fallbackToAll) {
return Parser.getBestFit(value, settings, undefined, false);
}
return null;
}
const candidates = [];
for (let i = 0; i < effective.length; i++) {
const obj = new effective[i].constructor(value);
const quickResult = obj.quickCheck();
if (quickResult === true || quickResult === undefined) {
candidates.push({ index: i, obj, uncertain: quickResult === undefined });
}
}
if (candidates.length === 0) {
return null;
}
const results = await Promise.all(candidates.map(async ({ index, obj }) => {
const meaningful = await obj.hasMeaningfulInformation();
const relevance = this.calculateRelevance(obj, index);
return { obj, meaningful, relevance, index };
}));
const validResults = results.filter(r => r.meaningful);
if (validResults.length === 0) {
return null;
}
validResults.sort((a, b) => {
if (b.relevance !== a.relevance) {
return b.relevance - a.relevance;
}
return a.index - b.index;
});
const best = validResults[0].obj;
Parser.applySettings(best, settings);
await best.init();
return best;
}
static calculateRelevance(obj, index) {
const priorityWeight = 1000;
const itemWeight = 1;
const actionWeight = 1;
const priorityScore = (renderers.length - index) * priorityWeight;
const itemScore = obj.items.length * itemWeight;
const actionScore = obj.actions.length * actionWeight;
return priorityScore + itemScore + actionScore;
}
static applySettings(obj, settings) {
var _a;
try {
const settingsKey = obj.getSettingsKey();
const settingsValues = (_a = settings.find(v => v.type === settingsKey)) === null || _a === void 0 ? void 0 : _a.values;
if (settingsValues)
obj.settings = settingsValues;
}
catch (e) {
console.warn('Error while adding settings to object:', e);
}
}
}
const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
let idbProxyableTypes;
let cursorAdvanceMethods;
// This is a function to prevent it throwing up in node environments.
function getIdbProxyableTypes() {
return (idbProxyableTypes ||
(idbProxyableTypes = [
IDBDatabase,
IDBObjectStore,
IDBIndex,
IDBCursor,
IDBTransaction,
]));
}
// This is a function to prevent it throwing up in node environments.
function getCursorAdvanceMethods() {
return (cursorAdvanceMethods ||
(cursorAdvanceMethods = [
IDBCursor.prototype.advance,
IDBCursor.prototype.continue,
IDBCursor.prototype.continuePrimaryKey,
]));
}
const transactionDoneMap = new WeakMap();
const transformCache = new WeakMap();
const reverseTransformCache = new WeakMap();
function promisifyRequest(request) {
const promise = new Promise((resolve, reject) => {
const unlisten = () => {
request.removeEventListener('success', success);
request.removeEventListener('error', error);
};
const success = () => {
resolve(wrap(request.result));
unlisten();
};
const error = () => {
reject(request.error);
unlisten();
};
request.addEventListener('success', success);
request.addEventListener('error', error);
});
// This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This
// is because we create many promises from a single IDBRequest.
reverseTransformCache.set(promise, request);
return promise;
}
function cacheDonePromiseForTransaction(tx) {
// Early bail if we've already created a done promise for this transaction.
if (transactionDoneMap.has(tx))
return;
const done = new Promise((resolve, reject) => {
const unlisten = () => {
tx.removeEventListener('complete', complete);
tx.removeEventListener('error', error);
tx.removeEventListener('abort', error);
};
const complete = () => {
resolve();
unlisten();
};
const error = () => {
reject(tx.error || new DOMException('AbortError', 'AbortError'));
unlisten();
};
tx.addEventListener('complete', complete);
tx.addEventListener('error', error);
tx.addEventListener('abort', error);
});
// Cache it for later retrieval.
transactionDoneMap.set(tx, done);
}
let idbProxyTraps = {
get(target, prop, receiver) {
if (target instanceof IDBTransaction) {
// Special handling for transaction.done.
if (prop === 'done')
return transactionDoneMap.get(target);
// Make tx.store return the only store in the transaction, or undefined if there are many.
if (prop === 'store') {
return receiver.objectStoreNames[1]
? undefined
: receiver.objectStore(receiver.objectStoreNames[0]);
}
}
// Else transform whatever we get back.
return wrap(target[prop]);
},
set(target, prop, value) {
target[prop] = value;
return true;
},
has(target, prop) {
if (target instanceof IDBTransaction &&
(prop === 'done' || prop === 'store')) {
return true;
}
return prop in target;
},
};
function replaceTraps(callback) {
idbProxyTraps = callback(idbProxyTraps);
}
function wrapFunction(func) {
// Due to expected object equality (which is enforced by the caching in `wrap`), we
// only create one new func per func.
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
// with real promises, so each advance methods returns a new promise for the cursor object, or
// undefined if the end of the cursor has been reached.
if (getCursorAdvanceMethods().includes(func)) {
return function (...args) {
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
// the original object.
func.apply(unwrap(this), args);
return wrap(this.request);
};
}
return function (...args) {
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
// the original object.
return wrap(func.apply(unwrap(this), args));
};
}
function transformCachableValue(value) {
if (typeof value === 'function')
return wrapFunction(value);
// This doesn't return, it just creates a 'done' promise for the transaction,
// which is later returned for transaction.done (see idbObjectHandler).
if (value instanceof IDBTransaction)
cacheDonePromiseForTransaction(value);
if (instanceOfAny(value, getIdbProxyableTypes()))
return new Proxy(value, idbProxyTraps);
// Return the same value back if we're not going to transform it.
return value;
}
function wrap(value) {
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
if (value instanceof IDBRequest)
return promisifyRequest(value);
// If we've already transformed this value before, reuse the transformed value.
// This is faster, but it also provides object equality.
if (transformCache.has(value))
return transformCache.get(value);
const newValue = transformCachableValue(value);
// Not all types are transformed.
// These may be primitive types, so they can't be WeakMap keys.
if (newValue !== value) {
transformCache.set(value, newValue);
reverseTransformCache.set(newValue, value);
}
return newValue;
}
const unwrap = (value) => reverseTransformCache.get(value);
/**
* Open a database.
*
* @param name Name of the database.
* @param version Schema version.
* @param callbacks Additional callbacks.
*/
function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
const request = indexedDB.open(name, version);
const openPromise = wrap(request);
if (upgrade) {
request.addEventListener('upgradeneeded', (event) => {
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
});
}
if (blocked) {
request.addEventListener('blocked', (event) => blocked(
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
event.oldVersion, event.newVersion, event));
}
openPromise
.then((db) => {
if (terminated)
db.addEventListener('close', () => terminated());
if (blocking) {
db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
}
})
.catch(() => { });
return openPromise;
}
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
const writeMethods = ['put', 'add', 'delete', 'clear'];
const cachedMethods = new Map();
function getMethod(target, prop) {
if (!(target instanceof IDBDatabase &&
!(prop in target) &&
typeof prop === 'string')) {
return;
}
if (cachedMethods.get(prop))
return cachedMethods.get(prop);
const targetFuncName = prop.replace(/FromIndex$/, '');
const useIndex = prop !== targetFuncName;
const isWrite = writeMethods.includes(targetFuncName);
if (
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
!(isWrite || readMethods.includes(targetFuncName))) {
return;
}
const method = async function (storeName, ...args) {
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
let target = tx.store;
if (useIndex)
target = target.index(args.shift());
// Must reject if op rejects.
// If it's a write operation, must reject if tx.done rejects.
// Must reject with op rejection first.
// Must resolve with op value.
// Must handle both promises (no unhandled rejections)
return (await Promise.all([
target[targetFuncName](...args),
isWrite && tx.done,
]))[0];
};
cachedMethods.set(prop, method);
return method;
}
replaceTraps((old