diff --git a/docs/.eleventy.js b/docs/.eleventy.js index 1630652d7..22c8dc27b 100644 --- a/docs/.eleventy.js +++ b/docs/.eleventy.js @@ -10,7 +10,7 @@ import { replaceTextPlugin } from './_utils/replace-text.js'; import { searchPlugin } from './_utils/search.js'; import { readFile } from 'fs/promises'; import { outlinePlugin } from './_utils/outline.js'; -import { getComponents } from './_utils/manifest.js'; +import componentList from './_data/componentList.js'; import litPlugin from '@lit-labs/eleventy-plugin-lit'; import process from 'process'; @@ -46,16 +46,6 @@ export default function (eleventyConfig) { }); // Helpers - eleventyConfig.addNunjucksGlobal('getComponent', tagName => { - const component = getComponents().find(c => c.tagName === tagName); - - if (!component) { - throw new Error( - `Unable to find "<${tagName}>". Make sure the file name is the same as the tag name (without prefix).` - ); - } - return component; - }); // Use our own markdown instance eleventyConfig.setLibrary('md', markdown); @@ -115,8 +105,7 @@ export default function (eleventyConfig) { // mutation-observer (why SSR this?) // resize-observer (why SSR this?) // tooltip (why SSR this?) - - const componentModules = getComponents() + const componentModules = componentList // .filter(component => !omittedModules.includes(component.tagName.split(/wa-/)[1])) .map(component => { const name = component.tagName.split(/wa-/)[1]; diff --git a/docs/_data/componentList.js b/docs/_data/componentList.js new file mode 100644 index 000000000..11843d7da --- /dev/null +++ b/docs/_data/componentList.js @@ -0,0 +1,75 @@ +/** + * @module components Fetches components from custom-elements.json and exposes them in a saner format. + */ +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; +import { readFileSync } from 'fs'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const manifest = JSON.parse(readFileSync(resolve(__dirname, '../../dist/custom-elements.json'), 'utf-8')); + +const components = manifest.modules.flatMap(module => { + return module.declarations + .filter(c => c?.customElement) + .map(declaration => { + // Generate the dist path based on the src path and attach it to the component + declaration.path = module.path.replace(/^src\//, 'dist/').replace(/\.ts$/, '.js'); + + // Remove private members and those that lack a description + const members = declaration.members?.filter(member => member.description && member.privacy !== 'private'); + + const methods = members?.filter(prop => prop.kind === 'method' && prop.privacy !== 'private'); + const attributes = declaration.attributes ?? []; + const properties = members?.filter(prop => { + // Look for a corresponding attribute + const attribute = attributes?.find(attr => attr.fieldName === prop.name); + if (attribute) { + prop.attribute = attribute.name || attribute.fieldName; + } + + return prop.kind === 'field' && prop.privacy !== 'private'; + }); + + return { + ...declaration, + slug: declaration.tagName.replace(/^wa-/, ''), + methods, + attributes, + properties + }; + }); +}); + +// Build dependency graphs +components.forEach(component => { + const dependencies = []; + + // Recursively fetch sub-dependencies + function getDependencies(tag) { + const cmp = components.find(c => c.tagName === tag); + if (!cmp || !Array.isArray(component.dependencies)) { + return; + } + + cmp.dependencies?.forEach(dependentTag => { + if (!dependencies.includes(dependentTag)) { + dependencies.push(dependentTag); + } + getDependencies(dependentTag); + }); + } + + getDependencies(component.tagName); + + component.dependencies = dependencies.sort(); +}); + +// Sort by name +components.sort((a, b) => { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; +}); + +export default components; diff --git a/docs/_data/components.js b/docs/_data/components.js new file mode 100644 index 000000000..1dab4c111 --- /dev/null +++ b/docs/_data/components.js @@ -0,0 +1,3 @@ +import componentList from './componentList.js'; + +export default Object.fromEntries(componentList.map(component => [component.slug, component])); diff --git a/docs/_data/componentsBy.js b/docs/_data/componentsBy.js new file mode 100644 index 000000000..b116c0e88 --- /dev/null +++ b/docs/_data/componentsBy.js @@ -0,0 +1,43 @@ +import components from './components.js'; + +const by = { + attribute: {}, + slot: {}, + event: {}, + method: {}, + cssPart: {}, + cssProperty: {} +}; + +function getAll(component, type) { + let prop = type + 's'; + if (type === 'cssProperty') { + prop = 'cssProperties'; + } + + return component[prop] ?? []; +} + +for (const componentName in components) { + const component = components[componentName]; + + for (const type of ['attribute', 'slot', 'event', 'method', 'cssPart', 'cssProperty']) { + for (const item of getAll(component, type)) { + by[type][item.name] ??= []; + by[type][item.name].push(component); + } + } +} + +// Sort by descending number of components +const sortByLengthDesc = (a, b) => b[1].length - a[1].length; + +for (const key in by) { + by[key] = sortObject(by[key], sortByLengthDesc); +} + +export default by; + +function sortObject(obj, sorter) { + return Object.fromEntries(Object.entries(obj).sort(sorter)); +} diff --git a/docs/_layouts/component.njk b/docs/_layouts/component.njk index 8557cd8b9..f5253d477 100644 --- a/docs/_layouts/component.njk +++ b/docs/_layouts/component.njk @@ -1,6 +1,6 @@ {% set hasSidebar = true %} {% set hasOutline = true %} -{% set component = getComponent('wa-' + page.fileSlug) %} +{% set component = components[page.fileSlug] %} {% set description = component.summary %} {% extends '../_includes/base.njk' %} diff --git a/docs/_utils/manifest.js b/docs/_utils/manifest.js deleted file mode 100644 index 5ba3847f3..000000000 --- a/docs/_utils/manifest.js +++ /dev/null @@ -1,71 +0,0 @@ -import { fileURLToPath } from 'url'; -import { dirname, resolve } from 'path'; -import { readFileSync } from 'fs'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -const manifest = JSON.parse(readFileSync(resolve(__dirname, '../../dist/custom-elements.json'), 'utf-8')); -/** - * @returns Fetches components from custom-elements.json and returns them in more sane format. - */ -export function getComponents() { - const components = []; - - manifest.modules?.forEach(module => { - module.declarations?.forEach(declaration => { - if (declaration.customElement) { - // Generate the dist path based on the src path and attach it to the component - declaration.path = module.path.replace(/^src\//, 'dist/').replace(/\.ts$/, '.js'); - - // Remove private members and those that lack a description - const members = declaration.members?.filter(member => member.description && member.privacy !== 'private'); - const methods = members?.filter(prop => prop.kind === 'method' && prop.privacy !== 'private'); - const properties = members?.filter(prop => { - // Look for a corresponding attribute - const attribute = declaration.attributes?.find(attr => attr.fieldName === prop.name); - if (attribute) { - prop.attribute = attribute.name || attribute.fieldName; - } - - return prop.kind === 'field' && prop.privacy !== 'private'; - }); - components.push({ - ...declaration, - methods, - properties - }); - } - }); - }); - - // Build dependency graphs - components.forEach(component => { - const dependencies = []; - - // Recursively fetch sub-dependencies - function getDependencies(tag) { - const cmp = components.find(c => c.tagName === tag); - if (!cmp || !Array.isArray(component.dependencies)) { - return; - } - - cmp.dependencies?.forEach(dependentTag => { - if (!dependencies.includes(dependentTag)) { - dependencies.push(dependentTag); - } - getDependencies(dependentTag); - }); - } - - getDependencies(component.tagName); - - component.dependencies = dependencies.sort(); - }); - - // Sort by name - return components.sort((a, b) => { - if (a.name < b.name) return -1; - if (a.name > b.name) return 1; - return 0; - }); -} diff --git a/docs/docs/components/reference.njk b/docs/docs/components/reference.njk new file mode 100644 index 000000000..71c4fe7ff --- /dev/null +++ b/docs/docs/components/reference.njk @@ -0,0 +1,34 @@ +--- +title: Component Reference +layout: docs +--- + + + +{% for type, all in componentsBy -%} +
| Name | +Components | +
|---|---|
{{ name }}{{ "()" if type == "method" }} |
+
+ {% for component in thingComponents %}
+ <{{ component.tagName }}>
+ {%- endfor -%}
+ |
+