(() => { let metadataStore; function createPropsTable(props) { const table = document.createElement('table'); table.innerHTML = ` Property Attribute Description Type Default ${props .map(prop => { return ` ${escapeHtml(prop.name)} ${prop.attribute ? `${escapeHtml(prop.attribute)}` : '-'} ${escapeHtml(prop.description)} ${prop.type?.text ? `${escapeHtml(prop.type?.text || '')}` : '-'} ${prop.default ? `${escapeHtml(prop.default)}` : '-'} `; }) .join('')} `; return table.outerHTML; } function createEventsTable(events) { const table = document.createElement('table'); table.innerHTML = ` Event Description Event Detail ${events .map( event => ` ${escapeHtml(event.name)} ${escapeHtml(event.description)} ${event.type?.text ? `${escapeHtml(event.type?.text)}` : '-'} ` ) .join('')} `; return table.outerHTML; } function createMethodsTable(methods) { const table = document.createElement('table'); table.innerHTML = ` Method Description Arguments ${methods .map( method => ` ${escapeHtml(method.name)} ${escapeHtml(method.description)} ${ method.parameters?.length ? ` ${escapeHtml( method.parameters.map(param => `${param.name}: ${param.type.text}`).join(', ') )} ` : '-' } ` ) .join('')} `; return table.outerHTML; } function createSlotsTable(slots) { const table = document.createElement('table'); table.innerHTML = ` Slot Description ${slots .map( slot => ` ${slot.name ? `${escapeHtml(slot.name)}` : '(default)'} ${escapeHtml(slot.description)} ` ) .join('')} `; return table.outerHTML; } function createCustomPropertiesTable(styles) { const table = document.createElement('table'); table.innerHTML = ` Name Description ${styles .map( style => ` ${escapeHtml(style.name)} ${escapeHtml(style.description)} ` ) .join('')} `; return table.outerHTML; } function createPartsTable(parts) { const table = document.createElement('table'); table.innerHTML = ` Name Description ${parts .map( part => ` ${escapeHtml(part.name)} ${escapeHtml(part.description)} ` ) .join('')} `; return table.outerHTML; } function createAnimationsTable(animations) { const table = document.createElement('table'); table.innerHTML = ` Name Description ${animations .map( animation => ` ${escapeHtml(animation.name)} ${escapeHtml(animation.description)} ` ) .join('')} `; return table.outerHTML; } function createDependenciesList(targetComponent, allComponents) { const ul = document.createElement('ul'); const dependencies = []; // Recursively fetch subdependencies function getDependencies(tag) { const component = allComponents.find(c => c.tag === tag); if (!component || !Array.isArray(component.dependencies)) { return []; } component.dependencies?.map(tag => { if (!dependencies.includes(tag)) { dependencies.push(tag); } getDependencies(tag); }); } getDependencies(targetComponent); dependencies.sort().map(tag => { const li = document.createElement('li'); li.innerHTML = `<${tag}>`; ul.appendChild(li); }); return ul.outerHTML; } function escapeHtml(html) { return (html + '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/`(.*?)`/g, '$1'); } function getAllComponents(metadata) { const allComponents = []; metadata.modules.map(module => { module.exports.find(ex => { if (ex.kind === 'custom-element-definition') { allComponents.push(getComponent(metadata, ex.name)); } }); }); return allComponents; } function getComponent(metadata, tagName) { const module = metadata.modules.find(module => { return module.exports.find(ex => { return ex.kind === 'custom-element-definition' && ex.name === tagName; }); }); const component = module?.declarations.find(dec => dec.name === 'default'); const tag = module.exports.filter(ex => ex.kind === 'custom-element-definition' && ex.name === tagName)[0]?.name; return Object.assign({ tag }, component); } function getMetadata() { return new Promise((resolve, reject) => { // Simple caching to prevent multiple XHR requests if (metadataStore) { return resolve(metadataStore); } fetch('/dist/custom-elements.json') .then(res => res.json()) .then(data => { metadataStore = data; resolve(metadataStore); }) .catch(err => console.error(err)); }); } if (!window.$docsify) { throw new Error('Docsify must be loaded before installing this plugin.'); } window.$docsify.plugins.push((hook, vm) => { hook.mounted(function () { getMetadata().then(metadata => { const target = document.querySelector('.app-name'); // Add version const version = document.createElement('div'); version.classList.add('sidebar-version'); version.textContent = metadata.package.version; target.appendChild(version); // Add repo buttons const buttons = document.createElement('div'); buttons.classList.add('sidebar-buttons'); buttons.innerHTML = ` Sponsor Star Follow `; target.appendChild(buttons); }); }); hook.beforeEach(async function (content, next) { const metadata = await getMetadata(); // Replace %VERSION% placeholders content = content.replace(/%VERSION%/g, metadata.package.version); // Handle [component-header] tags content = content.replace(/\[component-header:([a-z-]+)\]/g, (match, tag) => { const component = getComponent(metadata, tag); let result = ''; if (!component) { console.error('Component not found in metadata: ' + tag); return next(content); } let badgeType = 'info'; if (component.status === 'stable') badgeType = 'primary'; if (component.status === 'experimental') badgeType = 'warning'; if (component.status === 'planned') badgeType = 'info'; if (component.status === 'deprecated') badgeType = 'danger'; result += `
${component.className} | <${component.tag}>
Since ${component.since || '?'} ${component.status}
`; return result.replace(/^ +| +$/gm, ''); }); // Handle [component-metadata] tags content = content.replace(/\[component-metadata:([a-z-]+)\]/g, (match, tag) => { const component = getComponent(metadata, tag); let result = ''; if (!component) { console.error('Component not found in metadata: ' + tag); return next(content); } // Remove members that don't have a description const members = component.members?.filter(member => member.description); const props = members?.filter(prop => { // Look for a corresponding attribute const attribute = component.attributes?.find(attr => attr.fieldName === prop.name); if (attribute) { prop.attribute = attribute.name; } return prop.kind === 'field' && prop.privacy !== 'private'; }); // .map(prop => { // const attribute = component.attributes?.find(attr => attr.fieldName === prop); // prop.attribute = attribute; // }); const methods = members?.filter(prop => prop.kind === 'method' && prop.privacy !== 'private'); if (props?.length) { result += ` ## Properties ${createPropsTable(props)} `; } if (component.events?.length) { result += ` ## Events ${createEventsTable(component.events)} `; } if (methods?.length) { result += ` ## Methods ${createMethodsTable(methods)} `; } if (component.slots?.length) { result += ` ## Slots ${createSlotsTable(component.slots)} `; } if (component.cssProperties?.length) { result += ` ## CSS Custom Properties ${createCustomPropertiesTable(component.cssProperties)} `; } if (component.cssParts?.length) { result += ` ## CSS Parts ${createPartsTable(component.cssParts)} `; } if (component.animations?.length) { result += ` ## Animations ${createAnimationsTable(component.animations)} Learn how to [customize animations](/getting-started/customizing#animations). `; } if (component.dependencies?.length) { result += ` ## Dependencies This component has the following dependencies so, if you're [cherry picking](/getting-started/installation#cherry-picking), be sure to import these components in addition to <${tag}>. ${createDependenciesList(component.tag, getAllComponents(metadata))} `; } // Strip whitespace so markdown doesn't process things as code blocks return result.replace(/^ +| +$/gm, ''); }); next(content); }); }); })();