├── .eslintignore ├── docs ├── .eleventyignore ├── _includes │ └── _joiningBlocks │ │ ├── header │ │ └── 30-collection-header.njk │ │ ├── head │ │ └── 45-stylesheets-custom.njk │ │ └── _layoutHome │ │ └── content │ │ ├── 20-reasons.njk │ │ └── 10-hero.njk ├── _assets │ ├── demo.png │ ├── docs.png │ ├── knobs.png │ ├── snippet.png │ ├── _static │ │ └── icons │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── maskable-icon.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ └── safari-pinned-tab.svg │ ├── home.css │ ├── webmanifest.json │ ├── style.css │ ├── logo.svg │ └── theme.css ├── docs │ ├── index.md │ ├── guide │ │ ├── index.md │ │ ├── intro.md │ │ ├── using-demo.md │ │ └── writing-jsdoc.md │ ├── api │ │ ├── index.md │ │ ├── properties.md │ │ ├── elements.md │ │ ├── templates.md │ │ └── styling.md │ └── examples │ │ ├── index.md │ │ ├── api-docs.md │ │ ├── theming.md │ │ ├── api-demo.md │ │ └── api-viewer.md ├── _data │ ├── site.cjs │ └── footer.json ├── index.md └── assets │ └── theme.css ├── .prettierrc ├── screenshot-demo.png ├── screenshot-docs.png ├── .changeset ├── fast-candles-beam.md ├── metal-games-tie.md ├── gorgeous-trees-smash.md ├── nice-brooms-tell.md ├── fifty-toes-confess.md ├── neat-poets-thank.md ├── rare-numbers-hide.md ├── old-days-kick.md ├── rich-berries-prove.md ├── smooth-avocados-move.md ├── stale-teachers-develop.md ├── warm-mails-fry.md ├── lazy-crabs-yell.md ├── wicked-lizards-mate.md ├── fresh-candles-rush.md ├── config.json └── pre.json ├── packages ├── api-common │ ├── src │ │ ├── index.ts │ │ ├── utils.ts │ │ ├── templates.ts │ │ ├── manifest-mixin.ts │ │ ├── shared-styles.ts │ │ └── manifest.ts │ ├── README.md │ ├── tsconfig.json │ ├── CHANGELOG.md │ └── package.json ├── api-tabs │ ├── README.md │ ├── tsconfig.json │ ├── src │ │ ├── api-viewer-panel.ts │ │ ├── api-viewer-tab.ts │ │ └── api-viewer-tabs.ts │ ├── package.json │ └── CHANGELOG.md ├── api-viewer │ ├── src │ │ ├── styles.ts │ │ ├── api-viewer.ts │ │ └── base.ts │ ├── tsconfig.json │ ├── package.json │ ├── README.md │ └── CHANGELOG.md ├── api-docs │ ├── src │ │ ├── api-docs.ts │ │ ├── utils │ │ │ └── markdown.ts │ │ ├── base.ts │ │ └── styles.ts │ ├── tsconfig.json │ ├── README.md │ ├── package.json │ └── CHANGELOG.md └── api-demo │ ├── tsconfig.json │ ├── src │ ├── ui │ │ ├── events.ts │ │ ├── highlight-css.ts │ │ ├── knobs.ts │ │ ├── controls.ts │ │ ├── snippet.ts │ │ └── renderer.ts │ ├── api-demo.ts │ ├── controllers │ │ ├── events-controller.ts │ │ ├── abstract-controller.ts │ │ ├── styles-controller.ts │ │ └── slots-controller.ts │ ├── types.ts │ ├── base.ts │ └── styles.ts │ ├── README.md │ ├── package.json │ └── CHANGELOG.md ├── scripts ├── workspaces-scripts-bin.js ├── runWorkspacesScripts.js └── generate-ts-configs.js ├── .gitignore ├── fixtures └── lit │ ├── package.json │ ├── tsconfig.json │ └── src │ ├── opened-mixin.ts │ ├── intl-currency.ts │ ├── progress-bar.ts │ └── fancy-accordion.ts ├── workspace-packages.js ├── rocket.config.js ├── .stylelintrc ├── tsconfig.json ├── .github └── workflows │ ├── verify.yml │ └── release.yml ├── tsconfig.base.json ├── LICENSE.md ├── .eslintrc.json ├── CONTRIBUTING.md ├── README.md ├── CODE_OF_CONDUCT.md └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | fixtures/**/lib 2 | packages/**/lib 3 | -------------------------------------------------------------------------------- /docs/.eleventyignore: -------------------------------------------------------------------------------- 1 | _assets 2 | _includes 3 | _data 4 | -------------------------------------------------------------------------------- /docs/_includes/_joiningBlocks/header/30-collection-header.njk: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "none" 4 | } 5 | -------------------------------------------------------------------------------- /screenshot-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/screenshot-demo.png -------------------------------------------------------------------------------- /screenshot-docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/screenshot-docs.png -------------------------------------------------------------------------------- /docs/_assets/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/demo.png -------------------------------------------------------------------------------- /docs/_assets/docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/docs.png -------------------------------------------------------------------------------- /docs/_assets/knobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/knobs.png -------------------------------------------------------------------------------- /docs/_assets/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/snippet.png -------------------------------------------------------------------------------- /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | - [Guide](./guide/) 4 | - [API](./api/) 5 | - [Examples](./examples/) 6 | -------------------------------------------------------------------------------- /.changeset/fast-candles-beam.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/docs': patch 3 | --- 4 | 5 | Show method params and return type 6 | -------------------------------------------------------------------------------- /.changeset/metal-games-tie.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | --- 4 | 5 | Adjust colors for dark color scheme 6 | -------------------------------------------------------------------------------- /.changeset/gorgeous-trees-smash.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/demo': patch 3 | --- 4 | 5 | Improve demo controllers, do not reset state 6 | -------------------------------------------------------------------------------- /packages/api-common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './manifest.js'; 2 | export * from './manifest-mixin.js'; 3 | export * from './utils.js'; 4 | -------------------------------------------------------------------------------- /docs/_assets/_static/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/favicon-16x16.png -------------------------------------------------------------------------------- /docs/_assets/_static/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/favicon-32x32.png -------------------------------------------------------------------------------- /docs/_assets/_static/icons/maskable-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/maskable-icon.png -------------------------------------------------------------------------------- /docs/_assets/_static/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/mstile-150x150.png -------------------------------------------------------------------------------- /docs/docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # Guide || 10 2 | 3 | - [Introduction](./intro/) 4 | - [Writing JSDoc](./writing-jsdoc/) 5 | - [Using demo](./using-demo/) 6 | -------------------------------------------------------------------------------- /docs/_assets/_static/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /.changeset/nice-brooms-tell.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/demo': patch 3 | 'api-viewer-element': patch 4 | --- 5 | 6 | Update slot knobs to render name properly 7 | -------------------------------------------------------------------------------- /docs/_assets/_static/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/_assets/_static/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-wc/api-viewer-element/HEAD/docs/_assets/_static/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/docs/api/index.md: -------------------------------------------------------------------------------- 1 | # API || 20 2 | 3 | - [Elements](./elements/) 4 | - [Properties](./properties/) 5 | - [Templates](./templates/) 6 | - [Styling](./styling/) 7 | -------------------------------------------------------------------------------- /docs/docs/examples/index.md: -------------------------------------------------------------------------------- 1 | # Examples || 30 2 | 3 | - [``](./api-viewer/) 4 | - [``](./api-docs/) 5 | - [``](./api-demo/) 6 | - [Theming](./theming/) 7 | -------------------------------------------------------------------------------- /packages/api-tabs/README.md: -------------------------------------------------------------------------------- 1 | # `@api-viewer/tabs` 2 | 3 | Tabs web component used by the API Viewer. 4 | 5 | See [website](https://api-viewer.open-wc.org/docs/guide/intro/) for full documentation. 6 | -------------------------------------------------------------------------------- /packages/api-common/README.md: -------------------------------------------------------------------------------- 1 | # `@api-viewer/common` 2 | 3 | Set of helpers and utilities used by the API Viewer. 4 | 5 | See [website](https://api-viewer.open-wc.org/docs/guide/intro/) for full documentation. 6 | -------------------------------------------------------------------------------- /scripts/workspaces-scripts-bin.js: -------------------------------------------------------------------------------- 1 | import { runWorkspacesScripts } from './runWorkspacesScripts.js'; 2 | 3 | const [script, folder] = process.argv.slice(2); 4 | 5 | runWorkspacesScripts({ script, concurrency: 5, folder }); 6 | -------------------------------------------------------------------------------- /.changeset/fifty-toes-confess.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Use vanilla custom elements for tabs 10 | -------------------------------------------------------------------------------- /.changeset/neat-poets-thank.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Move demo types to api-demo package 10 | -------------------------------------------------------------------------------- /.changeset/rare-numbers-hide.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | 'api-viewer-element': patch 6 | '@api-viewer/tabs': patch 7 | --- 8 | 9 | Add only property to filter elements 10 | -------------------------------------------------------------------------------- /.changeset/old-days-kick.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/docs': patch 4 | '@api-viewer/demo': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Show whether a property reflects to attribute 10 | -------------------------------------------------------------------------------- /.changeset/rich-berries-prove.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Convert api-viewer-element to monorepo 10 | -------------------------------------------------------------------------------- /.changeset/smooth-avocados-move.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/docs': patch 4 | 'api-viewer-element': patch 5 | '@api-viewer/demo': patch 6 | '@api-viewer/tabs': patch 7 | --- 8 | 9 | Add methods tab to API documentation 10 | -------------------------------------------------------------------------------- /.changeset/stale-teachers-develop.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/docs': patch 3 | '@api-viewer/common': patch 4 | '@api-viewer/demo': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Update marked dependency to 4.0.10 10 | -------------------------------------------------------------------------------- /.changeset/warm-mails-fry.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@api-viewer/demo": patch 3 | "@api-viewer/common": patch 4 | "@api-viewer/docs": patch 5 | "@api-viewer/tabs": patch 6 | "api-viewer-element": patch 7 | --- 8 | 9 | Use proper selector for demo copy button styles 10 | -------------------------------------------------------------------------------- /.changeset/lazy-crabs-yell.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Added the ability to show whether a property is static 10 | -------------------------------------------------------------------------------- /docs/_includes/_joiningBlocks/head/45-stylesheets-custom.njk: -------------------------------------------------------------------------------- 1 | 2 | {%- if layout === 'layout-home' -%} 3 | 4 | {%- endif -%} 5 | -------------------------------------------------------------------------------- /.changeset/wicked-lizards-mate.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | 'api-viewer-element': patch 6 | '@api-viewer/tabs': patch 7 | --- 8 | 9 | Respect filtered elements when determining selected 10 | -------------------------------------------------------------------------------- /.changeset/fresh-candles-rush.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@api-viewer/common': patch 3 | '@api-viewer/demo': patch 4 | '@api-viewer/docs': patch 5 | '@api-viewer/tabs': patch 6 | 'api-viewer-element': patch 7 | --- 8 | 9 | Update custom-elements-manifest to v2.0.0, add readonly support 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib 3 | /fixtures/*/lib 4 | /packages/*/lib 5 | /**/*.tsbuildinfo 6 | /dist 7 | custom-elements.json 8 | !/docs/assets/custom-elements.json 9 | docs/_merged_data/ 10 | docs/_merged_assets/ 11 | docs/_merged_includes/ 12 | _site-dev 13 | _site 14 | .wireit 15 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.3/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [], 6 | "access": "public", 7 | "baseBranch": "master", 8 | "updateInternalDependencies": "patch", 9 | "ignore": ["@api-viewer-fixtures/lit"] 10 | } 11 | -------------------------------------------------------------------------------- /fixtures/lit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@api-viewer-fixtures/lit", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "analyze": "cem analyze --litelement --globs 'src/*.ts'" 7 | }, 8 | "dependencies": { 9 | "lit": "^2.0.0", 10 | "tslib": "^2.3.1" 11 | }, 12 | "customElements": "custom-elements.json" 13 | } 14 | -------------------------------------------------------------------------------- /docs/docs/examples/api-docs.md: -------------------------------------------------------------------------------- 1 | # Examples >> api-docs || 20 2 | 3 | ```js script 4 | import { html } from '@mdjs/mdjs-preview'; 5 | import '../../../packages/api-docs/lib/api-docs.js'; 6 | ``` 7 | 8 | ```html preview-story 9 | 10 | 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/_includes/_joiningBlocks/_layoutHome/content/20-reasons.njk: -------------------------------------------------------------------------------- 1 |
2 | {% for reason in reasons %} 3 |
4 |

{{ reason.header }}

5 |
6 | 7 | {{ reason.alt or '' }} 8 | 9 |
10 |
11 | {% endfor %} 12 |
13 | -------------------------------------------------------------------------------- /fixtures/lit/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [], 12 | "include": [ 13 | "src" 14 | ], 15 | "exclude": [ 16 | "lib" 17 | ] 18 | } -------------------------------------------------------------------------------- /packages/api-common/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [], 12 | "include": [ 13 | "src" 14 | ], 15 | "exclude": [ 16 | "lib" 17 | ] 18 | } -------------------------------------------------------------------------------- /workspace-packages.js: -------------------------------------------------------------------------------- 1 | const packages = [ 2 | { name: 'api-common', type: 'ts', environment: 'browser' }, 3 | { name: 'api-demo', type: 'ts', environment: 'browser' }, 4 | { name: 'api-docs', type: 'ts', environment: 'browser' }, 5 | { name: 'api-tabs', type: 'ts', environment: 'browser' }, 6 | { name: 'api-viewer', type: 'ts', environment: 'browser' }, 7 | { name: 'lit', type: 'ts', environment: 'browser' } 8 | ]; 9 | 10 | export { packages }; 11 | -------------------------------------------------------------------------------- /docs/_assets/home.css: -------------------------------------------------------------------------------- 1 | .reasons article { 2 | display: flex; 3 | flex-flow: column; 4 | align-items: center; 5 | text-align: center; 6 | } 7 | 8 | .reasons figure { 9 | margin: 0; 10 | display: contents; 11 | } 12 | 13 | /* Override Rocket styles */ 14 | body[layout^='layout-home'] main { 15 | padding-top: 0; 16 | } 17 | 18 | @media (min-width: 480px) { 19 | body[layout^='layout-home'] .reasons { 20 | grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rocket.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | import { absoluteBaseUrlNetlify } from '@rocket/core/helpers'; 3 | import { rocketLaunch } from '@rocket/launch'; 4 | import { rocketSearch } from '@rocket/search'; 5 | 6 | export default { 7 | absoluteBaseUrl: absoluteBaseUrlNetlify('http://localhost:8080'), 8 | presets: [rocketLaunch(), rocketSearch()], 9 | eleventy(eleventyConfig) { 10 | eleventyConfig.addWatchTarget('docs/_assets/**/*.css'); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/api-tabs/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [ 12 | { 13 | "path": "../api-common/tsconfig.json" 14 | } 15 | ], 16 | "include": [ 17 | "src" 18 | ], 19 | "exclude": [ 20 | "lib" 21 | ] 22 | } -------------------------------------------------------------------------------- /packages/api-viewer/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | import sharedStyles from '@api-viewer/common/lib/shared-styles.js'; 3 | import demoStyles from '@api-viewer/demo/lib/styles.js'; 4 | import docsStyles from '@api-viewer/docs/lib/styles.js'; 5 | 6 | export default [ 7 | sharedStyles, 8 | docsStyles, 9 | demoStyles, 10 | css` 11 | [part='radio-label'] { 12 | margin: 0 0.75rem 0 0.25rem; 13 | color: var(--ave-header-color); 14 | font-size: 0.875rem; 15 | } 16 | ` 17 | ]; 18 | -------------------------------------------------------------------------------- /packages/api-docs/src/api-docs.ts: -------------------------------------------------------------------------------- 1 | import { CSSResultArray } from 'lit'; 2 | import sharedStyles from '@api-viewer/common/lib/shared-styles.js'; 3 | import { ApiDocsBase } from './base.js'; 4 | import docsStyles from './styles.js'; 5 | 6 | export class ApiDocs extends ApiDocsBase { 7 | static get styles(): CSSResultArray { 8 | return [sharedStyles, docsStyles]; 9 | } 10 | } 11 | 12 | customElements.define('api-docs', ApiDocs); 13 | 14 | declare global { 15 | interface HTMLElementTagNameMap { 16 | 'api-docs': ApiDocs; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/api-common/src/utils.ts: -------------------------------------------------------------------------------- 1 | export const unquote = (value?: string): string | undefined => 2 | typeof value === 'string' && value.startsWith("'") && value.endsWith("'") 3 | ? value.slice(1, value.length - 1) 4 | : value; 5 | 6 | export function html( 7 | strings: TemplateStringsArray, 8 | ...values: string[] 9 | ): HTMLTemplateElement { 10 | const template = document.createElement('template'); 11 | template.innerHTML = values.reduce( 12 | (acc, v, idx) => acc + v + strings[idx + 1], 13 | strings[0] 14 | ); 15 | return template; 16 | } 17 | -------------------------------------------------------------------------------- /packages/api-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [ 12 | { 13 | "path": "../api-common/tsconfig.json" 14 | }, 15 | { 16 | "path": "../api-tabs/tsconfig.json" 17 | } 18 | ], 19 | "include": [ 20 | "src" 21 | ], 22 | "exclude": [ 23 | "lib" 24 | ] 25 | } -------------------------------------------------------------------------------- /packages/api-docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [ 12 | { 13 | "path": "../api-common/tsconfig.json" 14 | }, 15 | { 16 | "path": "../api-tabs/tsconfig.json" 17 | } 18 | ], 19 | "include": [ 20 | "src" 21 | ], 22 | "exclude": [ 23 | "lib" 24 | ] 25 | } -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "customSyntax": "postcss-lit", 3 | "extends": [ 4 | "stylelint-config-standard" 5 | ], 6 | "rules": { 7 | "alpha-value-notation": ["number"], 8 | "color-function-notation": ["legacy"], 9 | "media-feature-range-notation": "prefix", 10 | "number-max-precision": [4, { 11 | "ignoreProperties": ["animation-timing-function", "transform"] 12 | }], 13 | "property-no-vendor-prefix": [true, { 14 | "ignoreProperties": ["user-select"] 15 | }], 16 | "selector-class-pattern": null, 17 | "value-keyword-case": null 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/_includes/_joiningBlocks/_layoutHome/content/10-hero.njk: -------------------------------------------------------------------------------- 1 | {% if rocketLaunch.homeLayout === 'background' %} 2 | 3 | {% endif %} 4 | 5 |

{{title}}

6 | 7 |

{{slogan}}

8 | 9 |
10 | {% for callToAction in callToActionItems %} 11 | {{ callToAction.text | safe }} 12 | {% endfor %} 13 |
14 | -------------------------------------------------------------------------------- /packages/api-docs/src/utils/markdown.ts: -------------------------------------------------------------------------------- 1 | import { html, nothing, type TemplateResult } from 'lit'; 2 | import { unsafeHTML } from 'lit/directives/unsafe-html.js'; 3 | import { marked } from 'marked'; 4 | import DOMPurify from 'dompurify'; 5 | 6 | marked.setOptions({ headerIds: false }); 7 | 8 | export const parse = (markdown?: string): TemplateResult => html` 9 | ${!markdown 10 | ? nothing 11 | : unsafeHTML( 12 | DOMPurify.sanitize(marked(markdown)).replace( 13 | /<(h[1-6]|a|p|ul|ol|li|pre|code|strong|em|blockquote|del)(\s+href="[^"]+")*>/g, 14 | '<$1 part="md-$1"$2>' 15 | ) 16 | )} 17 | `; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "./tsconfig.base.json", 5 | "files": [], 6 | "references": [ 7 | { 8 | "path": "./packages/api-common/tsconfig.json" 9 | }, 10 | { 11 | "path": "./packages/api-tabs/tsconfig.json" 12 | }, 13 | { 14 | "path": "./packages/api-demo/tsconfig.json" 15 | }, 16 | { 17 | "path": "./packages/api-docs/tsconfig.json" 18 | }, 19 | { 20 | "path": "./packages/api-viewer/tsconfig.json" 21 | }, 22 | { 23 | "path": "./fixtures/lit/tsconfig.json" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | verify: 7 | name: Verify 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout Repo 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Node.js 14 | uses: actions/setup-node@v4 15 | with: 16 | node-version: '20' 17 | cache: 'yarn' 18 | 19 | - name: Install Dependencies 20 | run: yarn --frozen-lockfile 21 | 22 | - name: Build packages 23 | run: yarn build 24 | 25 | - name: Lint 26 | run: yarn lint 27 | 28 | - name: Check size 29 | run: yarn size 30 | -------------------------------------------------------------------------------- /packages/api-viewer/tsconfig.json: -------------------------------------------------------------------------------- 1 | // Don't edit this file directly. It is generated by /scripts/update-package-configs.ts 2 | 3 | { 4 | "extends": "../../tsconfig.base.json", 5 | "compilerOptions": { 6 | "module": "ESNext", 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "composite": true 10 | }, 11 | "references": [ 12 | { 13 | "path": "../api-common/tsconfig.json" 14 | }, 15 | { 16 | "path": "../api-tabs/tsconfig.json" 17 | }, 18 | { 19 | "path": "../api-demo/tsconfig.json" 20 | }, 21 | { 22 | "path": "../api-docs/tsconfig.json" 23 | } 24 | ], 25 | "include": [ 26 | "src" 27 | ], 28 | "exclude": [ 29 | "lib" 30 | ] 31 | } -------------------------------------------------------------------------------- /docs/_data/site.cjs: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return { 3 | dir: 'ltr', 4 | lang: 'en', 5 | name: 'API Viewer Element', 6 | title: 'API Viewer Element', 7 | description: 'Document your Web Components', 8 | socialLinks: [ 9 | { 10 | name: 'GitHub', 11 | url: 'https://github.com/open-wc/api-viewer-element' 12 | } 13 | ], 14 | gitSiteUrl: 'https://github.com/open-wc/api-viewer-element', 15 | gitBranch: 'master', 16 | helpUrl: 'https://github.com/open-wc/api-viewer-element/issues', 17 | logoAlt: 'API Viewer Element', 18 | iconColorMaskIcon: '#3f93ce', 19 | iconColorMsapplicationTileColor: '#1d3557', 20 | iconColorThemeColor: '#1d3557' 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esNext", 4 | "module": "esNext", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "inlineSources": true, 9 | "lib": ["esnext", "es2018", "dom"], 10 | "moduleResolution": "node", 11 | "noFallthroughCasesInSwitch": true, 12 | "noImplicitAny": true, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "strict": true, 18 | "skipLibCheck": true, 19 | "experimentalDecorators": true, 20 | "allowSyntheticDefaultImports": true, 21 | "useDefineForClassFields": false, 22 | "importHelpers": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/_data/footer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Discover", 4 | "children": [ 5 | { 6 | "text": "Help and Feedback", 7 | "href": "https://github.com/open-wc/api-viewer-element/issues" 8 | } 9 | ] 10 | }, 11 | { 12 | "name": "Follow", 13 | "children": [ 14 | { 15 | "text": "GitHub", 16 | "href": "https://github.com/open-wc/api-viewer-element" 17 | }, 18 | { 19 | "text": "Twitter", 20 | "href": "https://twitter.com/OpenWc" 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "Support", 26 | "children": [ 27 | { 28 | "text": "Contribute", 29 | "href": "https://github.com/open-wc/api-viewer-element/blob/master/CONTRIBUTING.md" 30 | } 31 | ] 32 | } 33 | ] 34 | -------------------------------------------------------------------------------- /packages/api-demo/src/ui/events.ts: -------------------------------------------------------------------------------- 1 | import { html, nothing, type TemplateResult } from 'lit'; 2 | import type { KnobValue } from '../types.js'; 3 | 4 | const renderDetail = (detail: { value: KnobValue }): string => { 5 | const result = detail; 6 | const undef = 'undefined'; 7 | if ('value' in detail && detail.value === undefined) { 8 | result.value = undef; 9 | } 10 | return ` detail: ${JSON.stringify(detail).replace(`"${undef}"`, undef)}`; 11 | }; 12 | 13 | export const renderEvents = (log: CustomEvent[]): TemplateResult => html` 14 | ${log.map( 15 | (event) => html` 16 |

17 | event: 18 | ${event.type}.${event.detail == null 19 | ? nothing 20 | : renderDetail(event.detail)} 21 |

22 | ` 23 | )} 24 | `; 25 | -------------------------------------------------------------------------------- /.changeset/pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "pre", 3 | "tag": "pre", 4 | "initialVersions": { 5 | "@api-viewer/common": "1.0.0-pre.0", 6 | "@api-viewer/demo": "1.0.0-pre.0", 7 | "@api-viewer/docs": "1.0.0-pre.0", 8 | "@api-viewer/tabs": "1.0.0-pre.0", 9 | "api-viewer-element": "1.0.0-pre.0", 10 | "@api-viewer-fixtures/lit": "0.0.0" 11 | }, 12 | "changesets": [ 13 | "fast-candles-beam", 14 | "fifty-toes-confess", 15 | "fresh-candles-rush", 16 | "gorgeous-trees-smash", 17 | "lazy-crabs-yell", 18 | "metal-games-tie", 19 | "neat-poets-thank", 20 | "nice-brooms-tell", 21 | "old-days-kick", 22 | "rare-numbers-hide", 23 | "rich-berries-prove", 24 | "smooth-avocados-move", 25 | "stale-teachers-develop", 26 | "warm-mails-fry", 27 | "wicked-lizards-mate" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /packages/api-viewer/src/api-viewer.ts: -------------------------------------------------------------------------------- 1 | import type { CSSResultArray } from 'lit'; 2 | import { setTemplates } from '@api-viewer/common/lib/templates.js'; 3 | import { ApiViewerBase } from './base.js'; 4 | import styles from './styles.js'; 5 | 6 | export class ApiViewer extends ApiViewerBase { 7 | static get styles(): CSSResultArray { 8 | return styles; 9 | } 10 | 11 | protected firstUpdated(): void { 12 | this.setTemplates(); 13 | } 14 | 15 | public setTemplates(templates?: HTMLTemplateElement[]): void { 16 | setTemplates( 17 | this._id!, 18 | templates || Array.from(this.querySelectorAll('template')) 19 | ); 20 | } 21 | } 22 | 23 | customElements.define('api-viewer', ApiViewer); 24 | 25 | declare global { 26 | interface HTMLElementTagNameMap { 27 | 'api-viewer': ApiViewer; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/_assets/webmanifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API Viewer Element", 3 | "short_name": "API Viewer", 4 | "theme_color": "#ffffff", 5 | "background_color": "#ffffff", 6 | "display": "standalone", 7 | "orientation": "portrait", 8 | "Scope": "/", 9 | "start_url": "/", 10 | "icons": [ 11 | { 12 | "src": "../_merged_assets/_static/icons/android-chrome-192x192.png", 13 | "sizes": "128x128", 14 | "type": "image/png" 15 | }, 16 | { 17 | "src": "../_merged_assets/_static/icons/android-chrome-512x512.png", 18 | "sizes": "512x512", 19 | "type": "image/png" 20 | }, 21 | { 22 | "src": "../_merged_assets/_static/icons/maskable-icon.jpg", 23 | "sizes": "1024x1024", 24 | "type": "image/jpg", 25 | "purpose": "any maskable" 26 | } 27 | ], 28 | "splash_pages": null 29 | } 30 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: layout-home 3 | title: API Viewer Element 4 | slogan: Document your Web Components 5 | callToActionItems: 6 | - text: Get started 7 | href: /docs/guide/intro/ 8 | - text: Examples 9 | href: /docs/examples/api-viewer/ 10 | 11 | reasons: 12 | - header: Docs 13 | image: /_assets/docs.png 14 | link: /docs/examples/api-docs/ 15 | alt: Example of properties documentation 16 | - header: Demo 17 | image: /_assets/demo.png 18 | link: /docs/examples/api-demo/ 19 | alt: Component rendered in the demo UI 20 | - header: Knobs 21 | image: /_assets/knobs.png 22 | link: /docs/guide/using-demo/#knobs 23 | alt: Knobs for setting properties 24 | - header: Code 25 | image: /_assets/snippet.png 26 | link: /docs/guide/using-demo/#source 27 | alt: Expansion panel code snippet 28 | --- 29 | -------------------------------------------------------------------------------- /packages/api-demo/src/api-demo.ts: -------------------------------------------------------------------------------- 1 | import type { CSSResultArray } from 'lit'; 2 | import sharedStyles from '@api-viewer/common/lib/shared-styles.js'; 3 | import { setTemplates } from '@api-viewer/common/lib/templates.js'; 4 | import { ApiDemoBase } from './base.js'; 5 | import demoStyles from './styles.js'; 6 | 7 | export class ApiDemo extends ApiDemoBase { 8 | static get styles(): CSSResultArray { 9 | return [sharedStyles, demoStyles]; 10 | } 11 | 12 | protected firstUpdated(): void { 13 | this.setTemplates(); 14 | } 15 | 16 | public setTemplates(templates?: HTMLTemplateElement[]): void { 17 | setTemplates( 18 | this._id!, 19 | templates || Array.from(this.querySelectorAll('template')) 20 | ); 21 | } 22 | } 23 | 24 | customElements.define('api-demo', ApiDemo); 25 | 26 | declare global { 27 | interface HTMLElementTagNameMap { 28 | 'api-demo': ApiDemo; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /fixtures/lit/src/opened-mixin.ts: -------------------------------------------------------------------------------- 1 | import type { LitElement } from 'lit'; 2 | import { property } from 'lit/decorators/property.js'; 3 | 4 | /* eslint-disable @typescript-eslint/no-explicit-any */ 5 | export type Constructor = new (...args: any[]) => T; 6 | 7 | export interface OpenedMixinInterface { 8 | opened: boolean | null | undefined; 9 | 10 | toggle(): void; 11 | } 12 | 13 | export const OpenedMixin = >( 14 | base: T 15 | ): T & Constructor => { 16 | class OpenedMixinClass extends base { 17 | /** 18 | * When true, the content is visible. 19 | */ 20 | @property({ type: Boolean, reflect: true }) 21 | opened: boolean | null | undefined = false; 22 | 23 | /** 24 | * Toggle the opened property value. 25 | */ 26 | toggle() { 27 | this.opened = !this.opened; 28 | } 29 | } 30 | 31 | return OpenedMixinClass; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/api-demo/src/controllers/events-controller.ts: -------------------------------------------------------------------------------- 1 | import type { Event } from '@api-viewer/common/lib/manifest.js'; 2 | import { 3 | AbstractController, 4 | type AbstractControllerHost 5 | } from './abstract-controller.js'; 6 | import type { HasKnobs } from '../types.js'; 7 | 8 | export class EventsController extends AbstractController { 9 | constructor( 10 | host: AbstractControllerHost & HasKnobs, 11 | component: HTMLElement, 12 | events: Event[] 13 | ) { 14 | super(host, component); 15 | 16 | events.forEach(({ name }) => { 17 | component.addEventListener(name, ((evt: CustomEvent) => { 18 | const s = '-changed'; 19 | if (name.endsWith(s)) { 20 | const { knob } = host.getKnob(name.replace(s, '')); 21 | host.syncKnob(component, knob); 22 | } 23 | 24 | this.data = [...this.data, evt]; 25 | }) as EventListener); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/_assets/style.css: -------------------------------------------------------------------------------- 1 | :not(rocket-navigation):not(:defined) { 2 | opacity: 0; 3 | } 4 | 5 | .call-to-action { 6 | background: var(--button-one) !important; 7 | text-shadow: none !important; 8 | border-radius: 5px !important; 9 | padding-top: 15px !important; 10 | padding-bottom: 15px !important; 11 | border: none !important; 12 | } 13 | 14 | .call-to-action:hover, 15 | .call-to-action:focus, 16 | .call-to-action:active { 17 | background: var(--button-one-hover) !important; 18 | } 19 | 20 | .call-to-action:nth-child(2) { 21 | background: var(--button-two) !important; 22 | } 23 | 24 | .call-to-action:nth-child(2):hover, 25 | .call-to-action:nth-child(2):focus, 26 | .call-to-action:nth-child(2):active { 27 | background: var(--button-two-hover) !important; 28 | } 29 | 30 | body[layout='home'] .markdown-body .call-to-action:nth-of-type(2) { 31 | --primary-color: #222; 32 | --primary-color-lighter: #333; 33 | --primary-color-darker: #000; 34 | } 35 | -------------------------------------------------------------------------------- /packages/api-demo/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ClassField, 3 | CssCustomProperty 4 | } from '@api-viewer/common/lib/index.js'; 5 | 6 | export type CssCustomPropertyValue = CssCustomProperty & { value?: string }; 7 | 8 | export interface SlotValue { 9 | name: string; 10 | content: string; 11 | } 12 | 13 | export type KnobValue = string | number | boolean | null | undefined; 14 | 15 | export type ComponentWithProps = { 16 | [key: string]: KnobValue; 17 | }; 18 | 19 | export type Knobable = unknown | (CssCustomProperty | ClassField | SlotValue); 20 | 21 | export type Knob = T & { 22 | attribute: string | undefined; 23 | value: KnobValue; 24 | custom?: boolean; 25 | options?: string[]; 26 | knobType: string; 27 | }; 28 | 29 | export type PropertyKnob = Knob; 30 | 31 | export interface HasKnobs { 32 | getKnob(name: string): { knob: PropertyKnob; custom?: boolean }; 33 | syncKnob(component: Element, changed: PropertyKnob): void; 34 | } 35 | -------------------------------------------------------------------------------- /packages/api-tabs/src/api-viewer-panel.ts: -------------------------------------------------------------------------------- 1 | import { html } from '@api-viewer/common/lib/utils.js'; 2 | 3 | let panelIdCounter = 0; 4 | 5 | const tpl = html` 6 | 18 | 19 | `; 20 | 21 | export class ApiViewerPanel extends HTMLElement { 22 | constructor() { 23 | super(); 24 | 25 | const root = this.attachShadow({ mode: 'open' }); 26 | root.appendChild(tpl.content.cloneNode(true)); 27 | } 28 | 29 | connectedCallback(): void { 30 | this.setAttribute('role', 'tabpanel'); 31 | 32 | if (!this.id) { 33 | this.id = `api-viewer-panel-${panelIdCounter++}`; 34 | } 35 | } 36 | } 37 | 38 | customElements.define('api-viewer-panel', ApiViewerPanel); 39 | 40 | declare global { 41 | interface HTMLElementTagNameMap { 42 | 'api-viewer-panel': ApiViewerPanel; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 open-wc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE 10 | -------------------------------------------------------------------------------- /packages/api-demo/src/controllers/abstract-controller.ts: -------------------------------------------------------------------------------- 1 | import type { ReactiveController, ReactiveControllerHost } from 'lit'; 2 | 3 | export type AbstractControllerHost = HTMLElement & ReactiveControllerHost; 4 | 5 | export class AbstractController { 6 | host: AbstractControllerHost; 7 | 8 | el: HTMLElement; 9 | 10 | private _data: T[] = []; 11 | 12 | get data(): T[] { 13 | return this._data; 14 | } 15 | 16 | set data(data: T[]) { 17 | this._data = data; 18 | 19 | this.updateData(data); 20 | } 21 | 22 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 23 | updateData(_data: T[]): void { 24 | if (this.host.isConnected) { 25 | this.host.requestUpdate(); 26 | } 27 | } 28 | 29 | constructor(host: AbstractControllerHost, component: HTMLElement) { 30 | (this.host = host).addController(this as ReactiveController); 31 | this.el = component; 32 | } 33 | 34 | clear(): void { 35 | this.data = []; 36 | } 37 | 38 | destroy(): void { 39 | this.host.removeController(this as ReactiveController); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docs/_assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/api-common/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @api-viewer/common 2 | 3 | ## 1.0.0-pre.10 4 | 5 | ### Patch Changes 6 | 7 | - 91c394a: Use proper selector for demo copy button styles 8 | 9 | ## 1.0.0-pre.9 10 | 11 | ### Patch Changes 12 | 13 | - 5f7183f: Added the ability to show whether a property is static 14 | - 1d3a419: Show whether a property reflects to attribute 15 | 16 | ## 1.0.0-pre.8 17 | 18 | ### Patch Changes 19 | 20 | - 289741e: Update custom-elements-manifest to v2.0.0, add readonly support 21 | 22 | ## 1.0.0-pre.7 23 | 24 | ### Patch Changes 25 | 26 | - e39f213: Respect filtered elements when determining selected 27 | 28 | ## 1.0.0-pre.6 29 | 30 | ### Patch Changes 31 | 32 | - 3061534: Add only property to filter elements 33 | 34 | ## 1.0.0-pre.5 35 | 36 | ### Patch Changes 37 | 38 | - cc911b6: Add methods tab to API documentation 39 | 40 | ## 1.0.0-pre.4 41 | 42 | ### Patch Changes 43 | 44 | - 1e3dfe8: Update marked dependency to 4.0.10 45 | 46 | ## 1.0.0-pre.3 47 | 48 | ### Patch Changes 49 | 50 | - 24ada26: Use vanilla custom elements for tabs 51 | - 8f1df74: Adjust colors for dark color scheme 52 | 53 | ## 1.0.0-pre.2 54 | 55 | ### Patch Changes 56 | 57 | - e51bd2f: Move demo types to api-demo package 58 | 59 | ## 1.0.0-pre.1 60 | 61 | ### Patch Changes 62 | 63 | - e9f9747: Convert api-viewer-element to monorepo 64 | -------------------------------------------------------------------------------- /packages/api-tabs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@api-viewer/tabs", 3 | "version": "1.0.0-pre.10", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Tabs web component used by the API Viewer", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/open-wc/api-viewer-element.git", 12 | "directory": "packages/api-tabs" 13 | }, 14 | "author": "open-wc", 15 | "bugs": { 16 | "url": "https://github.com/open-wc/api-viewer-element/issues" 17 | }, 18 | "main": "lib/api-viewer-tabs.js", 19 | "module": "lib/api-viewer-tabs.js", 20 | "type": "module", 21 | "files": [ 22 | "lib" 23 | ], 24 | "keywords": [ 25 | "API", 26 | "documentation", 27 | "web-components" 28 | ], 29 | "dependencies": { 30 | "@api-viewer/common": "^1.0.0-pre.10" 31 | }, 32 | "contributors": [ 33 | { 34 | "name": "Serhii Kulykov", 35 | "email": "iamkulykov@gmail.com", 36 | "url": "https://twitter.com/serhiikulykov" 37 | }, 38 | { 39 | "name": "Benny Powers", 40 | "email": "web@bennypowers.com", 41 | "url": "https://twitter.com/PowersBenny" 42 | }, 43 | { 44 | "name": "Mikhail Bashkirov", 45 | "email": "bashmish@gmail.com", 46 | "url": "https://twitter.com/bashmish" 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | # Prevents changesets action from creating a PR on forks 11 | if: github.repository == 'open-wc/api-viewer-element' 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout Repo 16 | uses: actions/checkout@v4 17 | with: 18 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 19 | fetch-depth: 0 20 | 21 | - name: Setup Node.js 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: '20' 25 | cache: 'yarn' 26 | 27 | - name: Install Dependencies 28 | run: yarn --frozen-lockfile 29 | 30 | - name: Build packages 31 | run: yarn build 32 | 33 | - name: Analyze 34 | run: yarn analyze 35 | 36 | - name: Create Release Pull Request or Publish to npm 37 | id: changesets 38 | uses: changesets/action@v1 39 | with: 40 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 41 | publish: yarn release 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 45 | -------------------------------------------------------------------------------- /packages/api-common/src/templates.ts: -------------------------------------------------------------------------------- 1 | const templates: HTMLTemplateElement[][] = []; 2 | 3 | export const setTemplates = (id: number, tpl: HTMLTemplateElement[]): void => { 4 | templates[id] = tpl; 5 | }; 6 | 7 | export const TemplateTypes = Object.freeze({ 8 | HOST: 'host', 9 | KNOB: 'knob', 10 | SLOT: 'slot', 11 | PREFIX: 'prefix', 12 | SUFFIX: 'suffix', 13 | WRAPPER: 'wrapper' 14 | }); 15 | 16 | export const isTemplate = (node: unknown): node is HTMLTemplateElement => 17 | node instanceof HTMLTemplateElement; 18 | 19 | const matchTemplate = 20 | (name: string, type: string) => (tpl: HTMLTemplateElement) => { 21 | const { element, target } = tpl.dataset; 22 | return element === name && target === type; 23 | }; 24 | 25 | export const getTemplateNode = (node: unknown): Element | null => 26 | isTemplate(node) ? node.content.firstElementChild : null; 27 | 28 | export const getTemplate = ( 29 | id: number, 30 | name: string, 31 | type: string 32 | ): HTMLTemplateElement | undefined => 33 | templates[id].find(matchTemplate(name, type)); 34 | 35 | export const getTemplates = ( 36 | id: number, 37 | name: string, 38 | type: string 39 | ): HTMLTemplateElement[] => templates[id].filter(matchTemplate(name, type)); 40 | 41 | export const hasTemplate = (id: number, name: string, type: string): boolean => 42 | templates[id].some(matchTemplate(name, type)); 43 | -------------------------------------------------------------------------------- /packages/api-common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@api-viewer/common", 3 | "version": "1.0.0-pre.10", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Helpers and utilities used by the API Viewer", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/open-wc/api-viewer-element.git", 12 | "directory": "packages/api-common" 13 | }, 14 | "author": "open-wc", 15 | "bugs": { 16 | "url": "https://github.com/open-wc/api-viewer-element/issues" 17 | }, 18 | "main": "lib/index.js", 19 | "module": "lib/index.js", 20 | "type": "module", 21 | "files": [ 22 | "lib" 23 | ], 24 | "keywords": [ 25 | "API", 26 | "documentation", 27 | "web-components" 28 | ], 29 | "dependencies": { 30 | "custom-elements-manifest": "^2.0.0", 31 | "lit": "^2.0.0", 32 | "tslib": "^2.3.1" 33 | }, 34 | "contributors": [ 35 | { 36 | "name": "Serhii Kulykov", 37 | "email": "iamkulykov@gmail.com", 38 | "url": "https://twitter.com/serhiikulykov" 39 | }, 40 | { 41 | "name": "Benny Powers", 42 | "email": "web@bennypowers.com", 43 | "url": "https://twitter.com/PowersBenny" 44 | }, 45 | { 46 | "name": "Mikhail Bashkirov", 47 | "email": "bashmish@gmail.com", 48 | "url": "https://twitter.com/bashmish" 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /packages/api-demo/README.md: -------------------------------------------------------------------------------- 1 | # `@api-viewer/demo` 2 | 3 | Live playground for Web Components. Based on [custom elements manifest](https://github.com/webcomponents/custom-elements-manifest) JSON format. 4 | 5 | ```html 6 | 7 | ``` 8 | 9 | [Documentation →](https://api-viewer.open-wc.org/docs/guide/intro/) 10 | 11 | [Live Demo →](https://api-viewer.open-wc.org/docs/examples/api-demo/) 12 | 13 | [Screenshot of api-viewer demo](https://api-viewer.open-wc.org) 14 | 15 | ## Install 16 | 17 | ```sh 18 | npm install @api-viewer/demo 19 | ``` 20 | 21 | Check out the [Getting Started](https://api-viewer.open-wc.org/docs/guide/intro/#usage) guide. 22 | 23 | ## Features 24 | 25 | - [Source](https://api-viewer.open-wc.org/docs/guide/using-demo/#source) - Code snippet matching the rendered component. 26 | - [Knobs](https://api-viewer.open-wc.org/docs/guide/using-demo/#knobs) - Change properties and slotted content dynamically. 27 | - [Styles](https://api-viewer.open-wc.org/docs/guide/using-demo/#styles) - Change values of the custom CSS properties. 28 | - [Event log](https://api-viewer.open-wc.org/docs/guide/using-demo/#events) - Output the events fired by the component. 29 | - [Templates](https://api-viewer.open-wc.org/docs/api/templates/) - Provide additional HTML to be shown. 30 | -------------------------------------------------------------------------------- /packages/api-docs/README.md: -------------------------------------------------------------------------------- 1 | # `@api-viewer/docs` 2 | 3 | API documentation for Web Components. Based on [custom elements manifest](https://github.com/webcomponents/custom-elements-manifest) JSON format. 4 | 5 | ```html 6 | 7 | ``` 8 | 9 | [Documentation →](https://api-viewer.open-wc.org/docs/guide/intro/) 10 | 11 | [Live Demo →](https://api-viewer.open-wc.org/docs/examples/api-docs/) 12 | 13 | [Screenshot of api-viewer docs](https://api-viewer.open-wc.org) 14 | 15 | ## Install 16 | 17 | ```sh 18 | npm install @api-viewer/docs 19 | ``` 20 | 21 | Check out the [Getting Started](https://api-viewer.open-wc.org/docs/guide/intro/#usage) guide. 22 | 23 | ## Features 24 | 25 | - [Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#properties) - JS properties publicly exposed by the component. 26 | - [Attributes](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#attributes) - HTML attributes (except those that match properties). 27 | - [Events](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#events) - DOM events dispatched by the component. 28 | - [Slots](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#slots) - Default `` and / or named slots, if any. 29 | - [CSS Custom Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-custom-properties) - Styling API of the component. 30 | - [CSS Shadow Parts](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-shadow-parts) - Elements that can be styled using `::part()`. 31 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb-base", 4 | "plugin:@typescript-eslint/eslint-recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "plugin:import/typescript", 7 | "plugin:lit/all", 8 | "plugin:wc/recommended", 9 | "plugin:prettier/recommended" 10 | ], 11 | "plugins": ["@typescript-eslint", "wc", "prettier"], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "sourceType": "module", 15 | "ecmaVersion": 2019 16 | }, 17 | "env": { 18 | "browser": true 19 | }, 20 | "rules": { 21 | "@typescript-eslint/explicit-function-return-type": "off", 22 | "import/extensions": "off", 23 | "import/no-import-module-exports": "off", 24 | "import/no-unresolved": "off", 25 | "import/prefer-default-export": "off", 26 | "lit/no-template-map": "off", 27 | "lit/prefer-static-styles": "off", 28 | "class-methods-use-this": [ 29 | "error", 30 | { 31 | "exceptMethods": ["render", "update"] 32 | } 33 | ], 34 | "no-console": ["error", { "allow": ["error"] }], 35 | "no-param-reassign": "off", 36 | "no-plusplus": "off", 37 | "no-underscore-dangle": "off", 38 | "prefer-destructuring": "off" 39 | }, 40 | "overrides": [ 41 | { 42 | "files": ["src/@types/*.d.ts"], 43 | "rules": { 44 | "@typescript-eslint/no-explicit-any": "off" 45 | } 46 | }, 47 | { 48 | "files": ["scripts/*.js"], 49 | "rules": { 50 | "import/no-extraneous-dependencies": "off", 51 | "no-console": "off", 52 | "no-restricted-syntax": "off" 53 | } 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /docs/docs/examples/theming.md: -------------------------------------------------------------------------------- 1 | # Examples >> Theming || 40 2 | 3 | ```js script 4 | import { html } from '@mdjs/mdjs-preview'; 5 | import '../../../packages/api-viewer/lib/api-viewer.js'; 6 | import '../../../fixtures/lit/lib/expansion-panel.js'; 7 | import '../../../fixtures/lit/lib/fancy-accordion.js'; 8 | import '../../../fixtures/lit/lib/intl-currency.js'; 9 | import '../../../fixtures/lit/lib/progress-bar.js'; 10 | ``` 11 | 12 | ```html preview-story 13 | 14 | 15 | 16 | 17 | 31 | 36 | 39 | 42 | 45 | 46 | 47 | 52 | ``` 53 | -------------------------------------------------------------------------------- /packages/api-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@api-viewer/demo", 3 | "version": "1.0.0-pre.10", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "Live demo playground for Web Components", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/open-wc/api-viewer-element.git", 12 | "directory": "packages/api-demo" 13 | }, 14 | "author": "open-wc", 15 | "bugs": { 16 | "url": "https://github.com/open-wc/api-viewer-element/issues" 17 | }, 18 | "main": "lib/api-demo.js", 19 | "module": "lib/api-demo.js", 20 | "type": "module", 21 | "scripts": { 22 | "analyze": "cem analyze --litelement --globs 'src/*.ts'", 23 | "size": "size-limit" 24 | }, 25 | "files": [ 26 | "custom-elements.json", 27 | "lib" 28 | ], 29 | "keywords": [ 30 | "API", 31 | "documentation", 32 | "web-components" 33 | ], 34 | "dependencies": { 35 | "@api-viewer/common": "^1.0.0-pre.10", 36 | "@api-viewer/tabs": "^1.0.0-pre.10", 37 | "highlight-ts": "9.12.1-2", 38 | "lit": "^2.0.0", 39 | "tslib": "^2.3.1" 40 | }, 41 | "contributors": [ 42 | { 43 | "name": "Serhii Kulykov", 44 | "email": "iamkulykov@gmail.com", 45 | "url": "https://twitter.com/serhiikulykov" 46 | }, 47 | { 48 | "name": "Benny Powers", 49 | "email": "web@bennypowers.com", 50 | "url": "https://twitter.com/PowersBenny" 51 | }, 52 | { 53 | "name": "Mikhail Bashkirov", 54 | "email": "bashmish@gmail.com", 55 | "url": "https://twitter.com/bashmish" 56 | } 57 | ], 58 | "customElements": "custom-elements.json", 59 | "size-limit": [ 60 | { 61 | "path": "lib/api-demo.js", 62 | "limit": "25 KB" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /packages/api-demo/src/controllers/styles-controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type CssCustomProperty, 3 | unquote 4 | } from '@api-viewer/common/lib/index.js'; 5 | import { 6 | AbstractController, 7 | type AbstractControllerHost 8 | } from './abstract-controller.js'; 9 | import type { CssCustomPropertyValue } from '../types.js'; 10 | 11 | export class StylesController extends AbstractController { 12 | constructor( 13 | host: AbstractControllerHost, 14 | component: HTMLElement, 15 | cssProps: CssCustomProperty[] 16 | ) { 17 | super(host, component); 18 | 19 | if (cssProps.length) { 20 | const style = getComputedStyle(component); 21 | 22 | this.data = cssProps.map((cssProp) => { 23 | let value = cssProp.default 24 | ? unquote(cssProp.default) 25 | : style.getPropertyValue(cssProp.name); 26 | 27 | const result: CssCustomPropertyValue = cssProp; 28 | if (value) { 29 | value = value.trim(); 30 | result.default = value; 31 | result.value = value; 32 | } 33 | 34 | return result; 35 | }); 36 | } 37 | } 38 | 39 | setValue(name: string, value: string): void { 40 | this.data = this.data.map((prop) => 41 | prop.name === name ? { ...prop, value } : prop 42 | ); 43 | } 44 | 45 | updateData(data: CssCustomPropertyValue[]): void { 46 | super.updateData(data); 47 | 48 | if (data.length) { 49 | data.forEach((prop) => { 50 | const { name, value } = prop; 51 | if (value) { 52 | if (value === prop.default) { 53 | this.el.style.removeProperty(name); 54 | } else { 55 | this.el.style.setProperty(name, value); 56 | } 57 | } 58 | }); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fixtures/lit/src/intl-currency.ts: -------------------------------------------------------------------------------- 1 | import { 2 | css, 3 | html, 4 | LitElement, 5 | type CSSResult, 6 | type TemplateResult 7 | } from 'lit'; 8 | import { customElement } from 'lit/decorators/custom-element.js'; 9 | import { property } from 'lit/decorators/property.js'; 10 | 11 | const format = ( 12 | value: number, 13 | currency: string | null | undefined, 14 | locale: string | null | undefined 15 | ) => { 16 | if (!currency || !locale) { 17 | return ''; 18 | } 19 | return new Intl.NumberFormat(locale, { 20 | style: 'currency', 21 | currency 22 | }).format(value); 23 | }; 24 | 25 | /** 26 | * A custom element that formats currency using Intl. 27 | * 28 | * @element intl-currency 29 | */ 30 | @customElement('intl-currency') 31 | export class IntlCurrency extends LitElement { 32 | /** 33 | * Amount to be formatted. 34 | */ 35 | @property({ type: Number }) value = 0; 36 | 37 | /** 38 | * Currency code used for formatting. 39 | */ 40 | @property() currency: string | null | undefined = 'EUR'; 41 | 42 | /** 43 | * Locale code used for formatting. 44 | */ 45 | @property() locale: string | null | undefined = 'en-GB'; 46 | 47 | /** 48 | * Version of the component 49 | */ 50 | static version = '1.0.0'; 51 | 52 | static get styles(): CSSResult { 53 | return css` 54 | :host { 55 | all: inherit; 56 | display: inline-block; 57 | } 58 | 59 | div { 60 | text-decoration: inherit; 61 | } 62 | `; 63 | } 64 | 65 | protected render(): TemplateResult { 66 | return html` 67 |
${format(this.value, this.currency, this.locale)}
68 | `; 69 | } 70 | } 71 | 72 | declare global { 73 | interface HTMLElementTagNameMap { 74 | 'intl-currency': IntlCurrency; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/api-viewer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-viewer-element", 3 | "version": "1.0.0-pre.10", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "API documentation and live playground for Web Components", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/open-wc/api-viewer-element.git", 12 | "directory": "packages/api-viewer" 13 | }, 14 | "author": "open-wc", 15 | "bugs": { 16 | "url": "https://github.com/open-wc/api-viewer-element/issues" 17 | }, 18 | "main": "lib/api-viewer.js", 19 | "module": "lib/api-viewer.js", 20 | "type": "module", 21 | "scripts": { 22 | "analyze": "cem analyze --litelement --globs 'src/*.ts'", 23 | "size": "size-limit" 24 | }, 25 | "files": [ 26 | "custom-elements.json", 27 | "lib" 28 | ], 29 | "keywords": [ 30 | "API", 31 | "documentation", 32 | "web-components" 33 | ], 34 | "dependencies": { 35 | "@api-viewer/common": "^1.0.0-pre.10", 36 | "@api-viewer/demo": "^1.0.0-pre.10", 37 | "@api-viewer/docs": "^1.0.0-pre.10", 38 | "lit": "^2.0.0", 39 | "tslib": "^2.3.1" 40 | }, 41 | "contributors": [ 42 | { 43 | "name": "Serhii Kulykov", 44 | "email": "iamkulykov@gmail.com", 45 | "url": "https://twitter.com/serhiikulykov" 46 | }, 47 | { 48 | "name": "Benny Powers", 49 | "email": "web@bennypowers.com", 50 | "url": "https://twitter.com/PowersBenny" 51 | }, 52 | { 53 | "name": "Mikhail Bashkirov", 54 | "email": "bashmish@gmail.com", 55 | "url": "https://twitter.com/bashmish" 56 | } 57 | ], 58 | "customElements": "custom-elements.json", 59 | "size-limit": [ 60 | { 61 | "path": "lib/api-viewer.js", 62 | "limit": "45 KB" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /docs/docs/examples/api-demo.md: -------------------------------------------------------------------------------- 1 | # Examples >> api-demo || 30 2 | 3 | ```js script 4 | import { html } from '@mdjs/mdjs-preview'; 5 | import '../../../packages/api-demo/lib/api-demo.js'; 6 | import '../../../fixtures/lit/lib/expansion-panel.js'; 7 | import '../../../fixtures/lit/lib/fancy-accordion.js'; 8 | import '../../../fixtures/lit/lib/intl-currency.js'; 9 | import '../../../fixtures/lit/lib/progress-bar.js'; 10 | ``` 11 | 12 | ```html preview-story 13 | 14 | 21 | 35 | 40 | 43 | 46 | 49 | 50 | 55 | ``` 56 | -------------------------------------------------------------------------------- /packages/api-docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@api-viewer/docs", 3 | "version": "1.0.0-pre.10", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "description": "API documentation viewer for Web Components", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/open-wc/api-viewer-element.git", 12 | "directory": "packages/api-docs" 13 | }, 14 | "author": "open-wc", 15 | "bugs": { 16 | "url": "https://github.com/open-wc/api-viewer-element/issues" 17 | }, 18 | "main": "lib/api-docs.js", 19 | "module": "lib/api-docs.js", 20 | "type": "module", 21 | "scripts": { 22 | "analyze": "cem analyze --litelement --globs 'src/*.ts'", 23 | "size": "size-limit" 24 | }, 25 | "files": [ 26 | "custom-elements.json", 27 | "lib" 28 | ], 29 | "keywords": [ 30 | "API", 31 | "documentation", 32 | "web-components" 33 | ], 34 | "dependencies": { 35 | "@api-viewer/common": "^1.0.0-pre.10", 36 | "@api-viewer/tabs": "^1.0.0-pre.10", 37 | "@types/dompurify": "^2.3.1", 38 | "@types/marked": "^4.0.0", 39 | "dompurify": "^2.5.4", 40 | "lit": "^2.0.0", 41 | "marked": "^4.0.10", 42 | "tslib": "^2.3.1" 43 | }, 44 | "contributors": [ 45 | { 46 | "name": "Serhii Kulykov", 47 | "email": "iamkulykov@gmail.com", 48 | "url": "https://twitter.com/serhiikulykov" 49 | }, 50 | { 51 | "name": "Benny Powers", 52 | "email": "web@bennypowers.com", 53 | "url": "https://twitter.com/PowersBenny" 54 | }, 55 | { 56 | "name": "Mikhail Bashkirov", 57 | "email": "bashmish@gmail.com", 58 | "url": "https://twitter.com/bashmish" 59 | } 60 | ], 61 | "customElements": "custom-elements.json", 62 | "size-limit": [ 63 | { 64 | "path": "lib/api-docs.js", 65 | "limit": "35 KB" 66 | } 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /docs/docs/examples/api-viewer.md: -------------------------------------------------------------------------------- 1 | # Examples >> api-viewer || 10 2 | 3 | ```js script 4 | import { html } from '@mdjs/mdjs-preview'; 5 | import '../../../packages/api-viewer/lib/api-viewer.js'; 6 | import '../../../fixtures/lit/lib/expansion-panel.js'; 7 | import '../../../fixtures/lit/lib/fancy-accordion.js'; 8 | import '../../../fixtures/lit/lib/intl-currency.js'; 9 | import '../../../fixtures/lit/lib/progress-bar.js'; 10 | ``` 11 | 12 | ```html preview-story 13 | 14 | 26 | 40 | 45 | 48 | 51 | 54 | 55 | 60 | ``` 61 | -------------------------------------------------------------------------------- /packages/api-tabs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @api-viewer/tabs 2 | 3 | ## 1.0.0-pre.10 4 | 5 | ### Patch Changes 6 | 7 | - 91c394a: Use proper selector for demo copy button styles 8 | - Updated dependencies [91c394a] 9 | - @api-viewer/common@1.0.0-pre.10 10 | 11 | ## 1.0.0-pre.9 12 | 13 | ### Patch Changes 14 | 15 | - 5f7183f: Added the ability to show whether a property is static 16 | - 1d3a419: Show whether a property reflects to attribute 17 | - Updated dependencies [5f7183f] 18 | - Updated dependencies [1d3a419] 19 | - @api-viewer/common@1.0.0-pre.9 20 | 21 | ## 1.0.0-pre.8 22 | 23 | ### Patch Changes 24 | 25 | - 289741e: Update custom-elements-manifest to v2.0.0, add readonly support 26 | - Updated dependencies [289741e] 27 | - @api-viewer/common@1.0.0-pre.8 28 | 29 | ## 1.0.0-pre.7 30 | 31 | ### Patch Changes 32 | 33 | - e39f213: Respect filtered elements when determining selected 34 | - Updated dependencies [e39f213] 35 | - @api-viewer/common@1.0.0-pre.7 36 | 37 | ## 1.0.0-pre.6 38 | 39 | ### Patch Changes 40 | 41 | - 3061534: Add only property to filter elements 42 | - Updated dependencies [3061534] 43 | - @api-viewer/common@1.0.0-pre.6 44 | 45 | ## 1.0.0-pre.5 46 | 47 | ### Patch Changes 48 | 49 | - cc911b6: Add methods tab to API documentation 50 | - Updated dependencies [cc911b6] 51 | - @api-viewer/common@1.0.0-pre.5 52 | 53 | ## 1.0.0-pre.4 54 | 55 | ### Patch Changes 56 | 57 | - 1e3dfe8: Update marked dependency to 4.0.10 58 | - Updated dependencies [1e3dfe8] 59 | - @api-viewer/common@1.0.0-pre.4 60 | 61 | ## 1.0.0-pre.3 62 | 63 | ### Patch Changes 64 | 65 | - 24ada26: Use vanilla custom elements for tabs 66 | - Updated dependencies [24ada26] 67 | - Updated dependencies [8f1df74] 68 | - @api-viewer/common@1.0.0-pre.3 69 | 70 | ## 1.0.0-pre.2 71 | 72 | ### Patch Changes 73 | 74 | - e51bd2f: Move demo types to api-demo package 75 | 76 | ## 1.0.0-pre.1 77 | 78 | ### Patch Changes 79 | 80 | - e9f9747: Convert api-viewer-element to monorepo 81 | -------------------------------------------------------------------------------- /packages/api-common/src/manifest-mixin.ts: -------------------------------------------------------------------------------- 1 | import { html, type LitElement } from 'lit'; 2 | import { property } from 'lit/decorators/property.js'; 3 | import { fetchManifest, hasCustomElements, type Package } from './manifest.js'; 4 | 5 | /* eslint-disable @typescript-eslint/no-explicit-any */ 6 | export type Constructor = new (...args: any[]) => T; 7 | 8 | export interface ManifestMixinInterface { 9 | src?: string; 10 | 11 | manifest?: Package; 12 | 13 | only?: string[]; 14 | 15 | selected?: string; 16 | 17 | jsonFetched: Promise; 18 | } 19 | 20 | export const emptyDataWarning = html` 21 |
No custom elements found in the JSON file.
22 | `; 23 | 24 | export const ManifestMixin = >( 25 | base: T 26 | ): T & Constructor => { 27 | class ManifestClass extends base { 28 | @property() src?: string; 29 | 30 | @property({ attribute: false }) 31 | manifest?: Package; 32 | 33 | @property({ 34 | reflect: true, 35 | converter: { 36 | fromAttribute: (value: string) => value.split(','), 37 | toAttribute: (value: string[]) => value.join(',') 38 | } 39 | }) 40 | only?: string[]; 41 | 42 | @property() selected?: string; 43 | 44 | jsonFetched: Promise = Promise.resolve(null); 45 | 46 | private lastSrc?: string; 47 | 48 | willUpdate(): void { 49 | const { src } = this; 50 | 51 | if (this.manifest) { 52 | if (hasCustomElements(this.manifest)) { 53 | this.lastSrc = undefined; 54 | this.jsonFetched = Promise.resolve(this.manifest); 55 | } else { 56 | console.error('No custom elements found in the `manifest` object.'); 57 | } 58 | } else if (src && this.lastSrc !== src) { 59 | this.lastSrc = src; 60 | this.jsonFetched = fetchManifest(src); 61 | } 62 | } 63 | } 64 | 65 | return ManifestClass; 66 | }; 67 | -------------------------------------------------------------------------------- /packages/api-demo/src/ui/highlight-css.ts: -------------------------------------------------------------------------------- 1 | import type { LanguageDef } from 'highlight-ts/es/types.js'; 2 | import { 3 | APOS_STRING_MODE, 4 | QUOTE_STRING_MODE, 5 | CSS_NUMBER_MODE, 6 | C_BLOCK_COMMENT_MODE 7 | } from 'highlight-ts/es/common.js'; 8 | 9 | const FUNCTION_LIKE = { 10 | begin: /[\w-]+\(/, 11 | returnBegin: true, 12 | contains: [ 13 | { 14 | className: 'built_in', 15 | begin: /[\w-]+/ 16 | }, 17 | { 18 | begin: /\(/, 19 | end: /\)/, 20 | contains: [APOS_STRING_MODE, QUOTE_STRING_MODE, CSS_NUMBER_MODE] 21 | } 22 | ] 23 | }; 24 | 25 | const ATTRIBUTE = { 26 | className: 'attribute', 27 | begin: /\S/, 28 | end: ':', 29 | excludeEnd: true, 30 | starts: { 31 | endsWithParent: true, 32 | excludeEnd: true, 33 | contains: [ 34 | FUNCTION_LIKE, 35 | CSS_NUMBER_MODE, 36 | QUOTE_STRING_MODE, 37 | APOS_STRING_MODE, 38 | C_BLOCK_COMMENT_MODE, 39 | { 40 | className: 'number', 41 | begin: '#[0-9A-Fa-f]+' 42 | }, 43 | { 44 | className: 'meta', 45 | begin: '!important' 46 | } 47 | ] 48 | } 49 | }; 50 | 51 | const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*'; 52 | 53 | const RULE = { 54 | begin: /(?:[A-Z_.-]+|--[a-zA-Z0-9_-]+)\s*:/, 55 | returnBegin: true, 56 | end: ';', 57 | endsWithParent: true, 58 | contains: [ATTRIBUTE] 59 | }; 60 | 61 | export const CSS: LanguageDef = { 62 | name: 'css', 63 | case_insensitive: true, 64 | illegal: /[=/|'$]/, 65 | contains: [ 66 | C_BLOCK_COMMENT_MODE, 67 | { 68 | className: 'selector-attr', 69 | begin: /\[/, 70 | end: /\]/, 71 | illegal: '$', 72 | contains: [APOS_STRING_MODE, QUOTE_STRING_MODE] 73 | }, 74 | { 75 | className: 'selector-tag', 76 | begin: IDENT_RE, 77 | relevance: 0 78 | }, 79 | { 80 | begin: '{', 81 | end: '}', 82 | illegal: /\S/, 83 | contains: [C_BLOCK_COMMENT_MODE, RULE] 84 | } 85 | ] 86 | }; 87 | -------------------------------------------------------------------------------- /packages/api-demo/src/controllers/slots-controller.ts: -------------------------------------------------------------------------------- 1 | import type { Slot } from '@api-viewer/common/lib/index.js'; 2 | import { 3 | hasTemplate, 4 | TemplateTypes 5 | } from '@api-viewer/common/lib/templates.js'; 6 | import { 7 | AbstractController, 8 | type AbstractControllerHost 9 | } from './abstract-controller.js'; 10 | import { formatSlot } from '../ui/controls.js'; 11 | import type { SlotValue } from '../types.js'; 12 | 13 | export class SlotsController extends AbstractController { 14 | enabled: boolean; 15 | 16 | constructor( 17 | host: AbstractControllerHost, 18 | component: HTMLElement, 19 | id: number, 20 | slots: Slot[] 21 | ) { 22 | super(host, component); 23 | 24 | this.enabled = !hasTemplate(id, component.localName, TemplateTypes.SLOT); 25 | this.data = slots 26 | .sort((a, b) => { 27 | if (a.name === '') { 28 | return 1; 29 | } 30 | if (b.name === '') { 31 | return -1; 32 | } 33 | return a.name.localeCompare(b.name); 34 | }) 35 | .map((slot) => ({ 36 | ...slot, 37 | content: formatSlot(slot.name) 38 | })) as SlotValue[]; 39 | } 40 | 41 | setValue(name: string, content: string): void { 42 | this.data = this.data.map((slot) => 43 | slot.name === name ? { ...slot, content } : slot 44 | ); 45 | } 46 | 47 | updateData(data: SlotValue[]): void { 48 | super.updateData(data); 49 | 50 | // Apply slots content by re-creating nodes 51 | if (this.enabled && this.el.isConnected && data && data.length) { 52 | this.el.innerHTML = ''; 53 | data.forEach((slot) => { 54 | let node: Element | Text; 55 | const { name, content } = slot; 56 | if (name) { 57 | node = document.createElement('div'); 58 | node.setAttribute('slot', name); 59 | node.textContent = content; 60 | } else { 61 | node = document.createTextNode(content); 62 | } 63 | this.el.appendChild(node); 64 | }); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /docs/docs/guide/intro.md: -------------------------------------------------------------------------------- 1 | # Guide >> Introduction || 10 2 | 3 | API Viewer is a set of custom elements and helpers providing interactive UI for documenting web components. 4 | This project is based on [Custom Elements Manifest](https://github.com/webcomponents/custom-elements-manifest), a file format that describes custom HTML elements. 5 | 6 | ## Install 7 | 8 | ```bash 9 | npm i api-viewer-element --save-dev 10 | ``` 11 | 12 | ## Usage 13 | 14 | 1. Install [custom elements manifest analyzer](https://custom-elements-manifest.open-wc.org/analyzer/getting-started/): 15 | 16 | ```bash 17 | npm install @custom-elements-manifest/analyzer 18 | ``` 19 | 20 | 2. Analyze your components: 21 | 22 | ```bash 23 | cem analyze --globs "src/components/my-element.js" 24 | ``` 25 | 26 | 3. Create an HTML file and import the component: 27 | 28 | ```html 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | ## ES modules 44 | 45 | Api Viewer is authored using ES modules which are [natively supported](https://caniuse.com/es6-module) 46 | by modern browsers. However, it also uses "bare module imports" which are [not yet standardized](https://github.com/WICG/import-maps) 47 | and require a small transform. 48 | 49 | We recommend using of the modern tools that leverage ES modules based development, such as 50 | [Web Dev Server](https://modern-web.dev/docs/dev-server/overview/) or [Vite](https://vitejs.dev). 51 | We also recommend [Rollup Plugin HTML](https://modern-web.dev/docs/building/rollup-plugin-html/) when bundling API Viewer docs for production. 52 | 53 | ## CDN 54 | 55 | You can import API Viewer from one of the content delivery networks that support ES modules: 56 | 57 | [unpkg.com CDN](https://unpkg.com): 58 | 59 | ```html 60 | 61 | ``` 62 | 63 | [Skypack CDN](https://www.skypack.dev): 64 | 65 | ```html 66 | 67 | ``` 68 | 69 | [JSPM CDN](https://jspm.org): 70 | 71 | ```html 72 | 73 | ``` 74 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Getting Started 4 | 5 | > This project adheres to the Contributor Covenant [code of conduct](./CODE_OF_CONDUCT.md). By participating in this project, you agree to abide by its terms. 6 | 7 | First, create a fork of the [open-wc/api-viewer-element](https://github.com/open-wc/api-viewer-element) repository by hitting the `fork` button on the GitHub page. 8 | 9 | Next, clone your fork onto your computer (replacing YOUR_USERNAME with your actual GitHub username). 10 | 11 | ```sh 12 | git clone git@github.com:YOUR_USERNAME/api-viewer-element.git 13 | ``` 14 | 15 | Once cloning is complete, change directory to the repository and add the upstream project as a remote. 16 | 17 | ```sh 18 | cd api-viewer-element 19 | git remote add upstream git@github.com:open-wc/api-viewer-element.git 20 | ``` 21 | 22 | ## Preparing Your Local Environment for Development 23 | 24 | Now that you have cloned the repository, ensure you have [Node.js](https://nodejs.org/en/download/) installed (we recommend Node 16.13 LTS), then run the following command to set up the development environment. 25 | 26 | ```sh 27 | npm install 28 | ``` 29 | 30 | This will download and install all packages needed. 31 | 32 | ## Making Your Changes 33 | 34 | First, update your fork with the latest code from upstream, then create a new branch for your work. 35 | 36 | ```sh 37 | git checkout master 38 | git pull upstream master --rebase 39 | git checkout -b my-awesome-fix 40 | ``` 41 | 42 | ### Linting 43 | 44 | Commits are linted using precommit hooks, meaning that any code that raises a linting error cannot be committed. In order to help avoid that, we recommend using an IDE or editor with an ESLint plugin in order to streamline the development process. Plugins are available for all the popular editors. For more information see [ESLint Integrations](https://eslint.org/docs/user-guide/integrations) 45 | 46 | ## Committing Your Changes 47 | 48 | Commit messages must follow the [conventional commit format](https://www.conventionalcommits.org/en/v1.0.0/). 49 | 50 | ## Create a Pull Request 51 | 52 | After you commit your changes, it's time to push your branch. 53 | 54 | ```sh 55 | git push -u origin my-awesome-fix 56 | ``` 57 | 58 | After a successful push, visit your fork on GitHub. You should see a button that will allow you to create a pull request. 59 | -------------------------------------------------------------------------------- /packages/api-common/src/shared-styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | export default css` 4 | :host { 5 | display: block; 6 | text-align: left; 7 | box-sizing: border-box; 8 | max-width: 800px; 9 | min-width: 360px; 10 | font-size: 1rem; 11 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 12 | Oxygen-Sans, Ubuntu, Cantarell, sans-serif; 13 | border: 1px solid var(--ave-border-color); 14 | border-radius: var(--ave-border-radius); 15 | 16 | --ave-primary-color: #01579b; 17 | --ave-secondary-color: rgba(0, 0, 0, 0.54); 18 | --ave-accent-color: #d63200; 19 | --ave-border-color: rgba(0, 0, 0, 0.12); 20 | --ave-border-radius: 4px; 21 | --ave-header-color: #fff; 22 | --ave-item-color: rgba(0, 0, 0, 0.87); 23 | --ave-label-color: #424242; 24 | --ave-link-color: #01579b; 25 | --ave-link-hover-color: #d63200; 26 | --ave-tab-indicator-size: 2px; 27 | --ave-tab-color: rgba(0, 0, 0, 0.54); 28 | --ave-tag-background-color: #e2e3e5; 29 | --ave-tag-border-color: #d6d8db; 30 | --ave-tag-color: #383d41; 31 | --ave-monospace-font: Menlo, 'DejaVu Sans Mono', 'Liberation Mono', Consolas, 32 | 'Courier New', monospace; 33 | } 34 | 35 | :host([hidden]), 36 | [hidden] { 37 | display: none !important; 38 | } 39 | 40 | header { 41 | display: flex; 42 | align-items: center; 43 | justify-content: space-between; 44 | padding: 0.75rem; 45 | background: var(--ave-header-background, var(--ave-primary-color)); 46 | border-top-left-radius: var(--ave-border-radius); 47 | border-top-right-radius: var(--ave-border-radius); 48 | } 49 | 50 | nav { 51 | display: flex; 52 | align-items: center; 53 | } 54 | 55 | [part='header-title'] { 56 | color: var(--ave-header-color); 57 | font-family: var(--ave-monospace-font); 58 | font-size: 0.875rem; 59 | line-height: 1.5rem; 60 | } 61 | 62 | [part='select-label'] { 63 | margin-left: 0.5rem; 64 | } 65 | 66 | [part='warning'] { 67 | padding: 1rem; 68 | } 69 | 70 | @media (max-width: 480px) { 71 | header { 72 | flex-direction: column; 73 | } 74 | 75 | nav { 76 | margin-top: 0.5rem; 77 | } 78 | } 79 | 80 | @media (prefers-color-scheme: dark) { 81 | :host { 82 | background: #fff; 83 | color: #000; 84 | } 85 | } 86 | `; 87 | -------------------------------------------------------------------------------- /docs/docs/api/properties.md: -------------------------------------------------------------------------------- 1 | # API >> Properties || 20 2 | 3 | API Viewer uses [reactive properties](https://lit.dev/docs/components/properties/) for configuration. 4 | String properties, such as `src`, can be set declaratively using HTML attributes. 5 | In such cases, it's up to you to decide whether to use a property or an attribute. 6 | 7 | ## Common 8 | 9 | The following properties can be set on each of the web components that are public parts of the API Viewer. 10 | 11 | ### `src` 12 | 13 | Use `src` property to provide URL for fetching manifest data as JSON: 14 | 15 | ```html 16 | 17 | ``` 18 | 19 | ### `manifest` 20 | 21 | Use `manifest` property instead of `src` to pass manifest data directly: 22 | 23 | ```html 24 | 25 | 32 | ``` 33 | 34 | ### `only` 35 | 36 | Use `only` to display API only for one or a few elements in the scope of a certain documentation page and filter out the rest. 37 | 38 | ```html 39 | 40 | ``` 41 | 42 | ### `selected` 43 | 44 | Use `selected` property to configure the displayed element. 45 | This property is only used if the manifest contains data about multiple elements. 46 | When a user selects another element, the property is updated accordingly. 47 | 48 | ```html 49 | 50 | ``` 51 | 52 | ## Additional 53 | 54 | The following properties are not available for all the web components, but only for a subset of them. 55 | 56 | ### `section` 57 | 58 | Use `section` property on the `` to toggle between demo and API docs: 59 | 60 | ```html 61 | 62 | ``` 63 | 64 | ### `exclude-knobs` 65 | 66 | Use `exclude-knobs` property to prevent creating knobs for certain properties. 67 | For example, you can exclude properties that accept objects or arrays. 68 | This property is available on both `` and ``. 69 | 70 | ```html 71 | 75 | ``` 76 | -------------------------------------------------------------------------------- /packages/api-docs/src/base.ts: -------------------------------------------------------------------------------- 1 | import { html, LitElement, type TemplateResult } from 'lit'; 2 | import { until } from 'lit/directives/until.js'; 3 | import { 4 | emptyDataWarning, 5 | getCustomElements, 6 | getElementData, 7 | getPublicFields, 8 | getPublicMethods, 9 | hasCustomElements, 10 | ManifestMixin, 11 | type Package 12 | } from '@api-viewer/common/lib/index.js'; 13 | import { parse } from './utils/markdown.js'; 14 | import './layout.js'; 15 | 16 | async function renderDocs( 17 | jsonFetched: Promise, 18 | onSelect: (e: CustomEvent) => void, 19 | only?: string[], 20 | selected?: string 21 | ): Promise { 22 | const manifest = await jsonFetched; 23 | 24 | if (!hasCustomElements(manifest)) { 25 | return emptyDataWarning; 26 | } 27 | 28 | const elements = getCustomElements(manifest, only); 29 | 30 | const data = getElementData(manifest, elements, selected)!; 31 | const props = getPublicFields(data.members); 32 | const methods = getPublicMethods(data.members); 33 | 34 | return html` 35 |
36 |
<${data.name}>
37 | 51 |
52 |
53 | ${parse(data.description)} 54 |
55 | 66 | `; 67 | } 68 | 69 | export class ApiDocsBase extends ManifestMixin(LitElement) { 70 | protected render(): TemplateResult { 71 | return html`${until( 72 | renderDocs(this.jsonFetched, this._onSelect, this.only, this.selected) 73 | )}`; 74 | } 75 | 76 | private _onSelect(e: Event): void { 77 | this.selected = (e.target as HTMLSelectElement).value; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/api-docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @api-viewer/docs 2 | 3 | ## 1.0.0-pre.10 4 | 5 | ### Patch Changes 6 | 7 | - 91c394a: Use proper selector for demo copy button styles 8 | - Updated dependencies [91c394a] 9 | - @api-viewer/common@1.0.0-pre.10 10 | - @api-viewer/tabs@1.0.0-pre.10 11 | 12 | ## 1.0.0-pre.9 13 | 14 | ### Patch Changes 15 | 16 | - 5f7183f: Added the ability to show whether a property is static 17 | - 1d3a419: Show whether a property reflects to attribute 18 | - Updated dependencies [5f7183f] 19 | - Updated dependencies [1d3a419] 20 | - @api-viewer/common@1.0.0-pre.9 21 | - @api-viewer/tabs@1.0.0-pre.9 22 | 23 | ## 1.0.0-pre.8 24 | 25 | ### Patch Changes 26 | 27 | - 289741e: Update custom-elements-manifest to v2.0.0, add readonly support 28 | - Updated dependencies [289741e] 29 | - @api-viewer/common@1.0.0-pre.8 30 | - @api-viewer/tabs@1.0.0-pre.8 31 | 32 | ## 1.0.0-pre.7 33 | 34 | ### Patch Changes 35 | 36 | - e39f213: Respect filtered elements when determining selected 37 | - Updated dependencies [e39f213] 38 | - @api-viewer/common@1.0.0-pre.7 39 | - @api-viewer/tabs@1.0.0-pre.7 40 | 41 | ## 1.0.0-pre.6 42 | 43 | ### Patch Changes 44 | 45 | - 3061534: Add only property to filter elements 46 | - Updated dependencies [3061534] 47 | - @api-viewer/common@1.0.0-pre.6 48 | - @api-viewer/tabs@1.0.0-pre.6 49 | 50 | ## 1.0.0-pre.5 51 | 52 | ### Patch Changes 53 | 54 | - afd7ef1: Show method params and return type 55 | - cc911b6: Add methods tab to API documentation 56 | - Updated dependencies [cc911b6] 57 | - @api-viewer/common@1.0.0-pre.5 58 | - @api-viewer/tabs@1.0.0-pre.5 59 | 60 | ## 1.0.0-pre.4 61 | 62 | ### Patch Changes 63 | 64 | - 1e3dfe8: Update marked dependency to 4.0.10 65 | - Updated dependencies [1e3dfe8] 66 | - @api-viewer/common@1.0.0-pre.4 67 | - @api-viewer/tabs@1.0.0-pre.4 68 | 69 | ## 1.0.0-pre.3 70 | 71 | ### Patch Changes 72 | 73 | - 24ada26: Use vanilla custom elements for tabs 74 | - Updated dependencies [24ada26] 75 | - Updated dependencies [8f1df74] 76 | - @api-viewer/common@1.0.0-pre.3 77 | - @api-viewer/tabs@1.0.0-pre.3 78 | 79 | ## 1.0.0-pre.2 80 | 81 | ### Patch Changes 82 | 83 | - e51bd2f: Move demo types to api-demo package 84 | - Updated dependencies [e51bd2f] 85 | - @api-viewer/common@1.0.0-pre.2 86 | - @api-viewer/tabs@1.0.0-pre.2 87 | 88 | ## 1.0.0-pre.1 89 | 90 | ### Patch Changes 91 | 92 | - e9f9747: Convert api-viewer-element to monorepo 93 | - Updated dependencies [e9f9747] 94 | - @api-viewer/common@1.0.0-pre.1 95 | - @api-viewer/tabs@1.0.0-pre.1 96 | -------------------------------------------------------------------------------- /docs/assets/theme.css: -------------------------------------------------------------------------------- 1 | api-viewer[theme='custom'] { 2 | background-color: #fff; 3 | border: none; 4 | border-radius: 6px; 5 | box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 6 | 0 0 0 1px rgba(10, 10, 10, 0.16); 7 | font-family: BlinkMacSystemFont, -apple-system, 'Segoe UI', Roboto, Oxygen, 8 | Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Helvetica, 9 | Arial, sans-serif; 10 | --ave-primary-color: #3273dc; 11 | --ave-accent-color: #f14668; 12 | --ave-header-color: #0a0a0a; 13 | --ave-border-color: #ededed; 14 | } 15 | 16 | /* Custom layout styles */ 17 | api-viewer[theme='custom']::part(header) { 18 | padding: 0.75rem 1rem; 19 | background: #ededed; 20 | } 21 | 22 | api-viewer[theme='custom']::part(demo-output) { 23 | border-top: none; 24 | } 25 | 26 | /* Custom input styles */ 27 | api-viewer[theme='custom']::part(input), 28 | api-viewer[theme='custom']::part(select) { 29 | padding: calc(0.5em - 1px) calc(0.75em - 1px); 30 | font-size: 1rem; 31 | } 32 | 33 | api-viewer[theme='custom']::part(input) { 34 | font-size: 0.75rem; 35 | } 36 | 37 | /* Custom checkbox styles */ 38 | api-viewer[theme='custom']::part(checkbox) { 39 | margin: 0.5rem 0.25rem; 40 | } 41 | 42 | /* Custom select styles */ 43 | api-viewer[theme='custom']::part(select) { 44 | height: 2.5em; 45 | padding-right: 2.5em; 46 | font-size: 1em; 47 | border: solid 1px #dbdbdb; 48 | border-radius: 4px; 49 | line-height: 1.5; 50 | -webkit-appearance: none; 51 | -moz-appearance: none; 52 | appearance: none; 53 | } 54 | 55 | api-viewer[theme='custom']::part(select-label) { 56 | height: 2.5em; 57 | max-width: 100%; 58 | position: relative; 59 | font-size: 0.75rem; 60 | } 61 | 62 | api-viewer[theme='custom']::part(select-label)::after { 63 | display: block; 64 | content: ''; 65 | box-sizing: border-box; 66 | position: absolute; 67 | top: 50%; 68 | right: 1.125em; 69 | width: 0.625em; 70 | height: 0.625em; 71 | margin-top: -0.4375em; 72 | border: 3px solid transparent; 73 | border-radius: 2px; 74 | border-right: 0; 75 | border-top: 0; 76 | transform: rotate(-45deg); 77 | transform-origin: center; 78 | border-color: #3273dc; 79 | pointer-events: none; 80 | } 81 | 82 | /* Custom tab styles */ 83 | api-viewer[theme='custom']::part(tab) { 84 | max-width: 155px; 85 | font-size: 0.875rem; 86 | text-transform: initial; 87 | font-weight: normal; 88 | } 89 | 90 | @media (max-width: 480px) { 91 | api-viewer[theme='custom']::part(tab) { 92 | max-width: 120px; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /packages/api-demo/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @api-viewer/demo 2 | 3 | ## 1.0.0-pre.10 4 | 5 | ### Patch Changes 6 | 7 | - 91c394a: Use proper selector for demo copy button styles 8 | - Updated dependencies [91c394a] 9 | - @api-viewer/common@1.0.0-pre.10 10 | - @api-viewer/tabs@1.0.0-pre.10 11 | 12 | ## 1.0.0-pre.9 13 | 14 | ### Patch Changes 15 | 16 | - 5f7183f: Added the ability to show whether a property is static 17 | - 1d3a419: Show whether a property reflects to attribute 18 | - Updated dependencies [5f7183f] 19 | - Updated dependencies [1d3a419] 20 | - @api-viewer/common@1.0.0-pre.9 21 | - @api-viewer/tabs@1.0.0-pre.9 22 | 23 | ## 1.0.0-pre.8 24 | 25 | ### Patch Changes 26 | 27 | - 289741e: Update custom-elements-manifest to v2.0.0, add readonly support 28 | - Updated dependencies [289741e] 29 | - @api-viewer/common@1.0.0-pre.8 30 | - @api-viewer/tabs@1.0.0-pre.8 31 | 32 | ## 1.0.0-pre.7 33 | 34 | ### Patch Changes 35 | 36 | - e39f213: Respect filtered elements when determining selected 37 | - Updated dependencies [e39f213] 38 | - @api-viewer/common@1.0.0-pre.7 39 | - @api-viewer/tabs@1.0.0-pre.7 40 | 41 | ## 1.0.0-pre.6 42 | 43 | ### Patch Changes 44 | 45 | - 3061534: Add only property to filter elements 46 | - Updated dependencies [3061534] 47 | - @api-viewer/common@1.0.0-pre.6 48 | - @api-viewer/tabs@1.0.0-pre.6 49 | 50 | ## 1.0.0-pre.5 51 | 52 | ### Patch Changes 53 | 54 | - cc911b6: Add methods tab to API documentation 55 | - Updated dependencies [cc911b6] 56 | - @api-viewer/common@1.0.0-pre.5 57 | - @api-viewer/tabs@1.0.0-pre.5 58 | 59 | ## 1.0.0-pre.4 60 | 61 | ### Patch Changes 62 | 63 | - 1e3dfe8: Update marked dependency to 4.0.10 64 | - Updated dependencies [1e3dfe8] 65 | - @api-viewer/common@1.0.0-pre.4 66 | - @api-viewer/tabs@1.0.0-pre.4 67 | 68 | ## 1.0.0-pre.3 69 | 70 | ### Patch Changes 71 | 72 | - 24ada26: Use vanilla custom elements for tabs 73 | - Updated dependencies [24ada26] 74 | - Updated dependencies [8f1df74] 75 | - @api-viewer/common@1.0.0-pre.3 76 | - @api-viewer/tabs@1.0.0-pre.3 77 | 78 | ## 1.0.0-pre.2 79 | 80 | ### Patch Changes 81 | 82 | - e51bd2f: Move demo types to api-demo package 83 | - 9c60a0a: Update slot knobs to render name properly 84 | - Updated dependencies [e51bd2f] 85 | - @api-viewer/common@1.0.0-pre.2 86 | - @api-viewer/tabs@1.0.0-pre.2 87 | 88 | ## 1.0.0-pre.1 89 | 90 | ### Patch Changes 91 | 92 | - 56f3e68: Improve demo controllers, do not reset state 93 | - e9f9747: Convert api-viewer-element to monorepo 94 | - Updated dependencies [e9f9747] 95 | - @api-viewer/common@1.0.0-pre.1 96 | - @api-viewer/tabs@1.0.0-pre.1 97 | -------------------------------------------------------------------------------- /packages/api-viewer/README.md: -------------------------------------------------------------------------------- 1 | # <api-viewer> 2 | 3 | API documentation and live playground for Web Components. Based on [custom elements manifest](https://github.com/webcomponents/custom-elements-manifest) JSON format. 4 | 5 | ```html 6 | 7 | ``` 8 | 9 | [Documentation →](https://api-viewer.open-wc.org/docs/guide/intro/) 10 | 11 | [Live Demo →](https://api-viewer.open-wc.org/docs/examples/api-viewer/) 12 | 13 | [Screenshot of api-viewer docs](https://api-viewer.open-wc.org) 14 | 15 | [Screenshot of api-viewer demo](https://api-viewer.open-wc.org) 16 | 17 | ## Install 18 | 19 | ```sh 20 | npm install api-viewer-element 21 | ``` 22 | 23 | Check out the [Getting Started](https://api-viewer.open-wc.org/docs/guide/intro/#usage) guide. 24 | 25 | ## Features 26 | 27 | - [API docs viewer](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/) 28 | - [Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#properties) - JS properties publicly exposed by the component. 29 | - [Attributes](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#attributes) - HTML attributes (except those that match properties). 30 | - [Events](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#events) - DOM events dispatched by the component. 31 | - [Slots](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#slots) - Default `` and / or named slots, if any. 32 | - [CSS Custom Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-custom-properties) - Styling API of the component. 33 | - [CSS Shadow Parts](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-shadow-parts) - Elements that can be styled using `::part()`. 34 | - [Live playground](https://api-viewer.open-wc.org/docs/guide/using-demo/) 35 | - [Source](https://api-viewer.open-wc.org/docs/guide/using-demo/#source) - Code snippet matching the rendered component. 36 | - [Knobs](https://api-viewer.open-wc.org/docs/guide/using-demo/#knobs) - Change properties and slotted content dynamically. 37 | - [Styles](https://api-viewer.open-wc.org/docs/guide/using-demo/#styles) - Change values of the custom CSS properties. 38 | - [Event log](https://api-viewer.open-wc.org/docs/guide/using-demo/#events) - Output the events fired by the component. 39 | - [Templates](https://api-viewer.open-wc.org/docs/api/templates/) - Provide additional HTML to be shown. 40 | -------------------------------------------------------------------------------- /packages/api-demo/src/base.ts: -------------------------------------------------------------------------------- 1 | import { html, LitElement, type TemplateResult } from 'lit'; 2 | import { property } from 'lit/decorators/property.js'; 3 | import { until } from 'lit/directives/until.js'; 4 | import { 5 | emptyDataWarning, 6 | getCustomElements, 7 | getElementData, 8 | getPublicFields, 9 | hasCustomElements, 10 | ManifestMixin, 11 | type Package 12 | } from '@api-viewer/common/lib/index.js'; 13 | import './layout.js'; 14 | 15 | async function renderDemo( 16 | jsonFetched: Promise, 17 | onSelect: (e: CustomEvent) => void, 18 | only?: string[], 19 | selected?: string, 20 | id?: number, 21 | exclude = '' 22 | ): Promise { 23 | const manifest = await jsonFetched; 24 | 25 | if (!hasCustomElements(manifest)) { 26 | return emptyDataWarning; 27 | } 28 | 29 | const elements = getCustomElements(manifest, only); 30 | 31 | const data = getElementData(manifest, elements, selected)!; 32 | const props = getPublicFields(data.members); 33 | 34 | return html` 35 |
36 |
<${data.name}>
37 | 51 |
52 | 62 | `; 63 | } 64 | 65 | let id = 0; 66 | 67 | export class ApiDemoBase extends ManifestMixin(LitElement) { 68 | @property({ type: String, attribute: 'exclude-knobs' }) excludeKnobs?: string; 69 | 70 | protected _id?: number; 71 | 72 | constructor() { 73 | super(); 74 | 75 | this._id = id++; 76 | } 77 | 78 | protected render(): TemplateResult { 79 | return html` 80 | ${until( 81 | renderDemo( 82 | this.jsonFetched, 83 | this._onSelect, 84 | this.only, 85 | this.selected, 86 | this._id, 87 | this.excludeKnobs 88 | ) 89 | )} 90 | `; 91 | } 92 | 93 | private _onSelect(e: Event): void { 94 | this.selected = (e.target as HTMLSelectElement).value; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /scripts/runWorkspacesScripts.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { join, dirname, basename } from 'path'; 3 | import { fileURLToPath } from 'url'; 4 | import concurrently from 'concurrently'; 5 | import pc from 'picocolors'; 6 | 7 | /** 8 | * @typedef {Object} ScriptConfig 9 | * @property {string} script 10 | * @property {number} concurrency 11 | * @property {string} folder 12 | * @property {Array} filteredPackages 13 | */ 14 | 15 | /** 16 | * @param {ScriptConfig} config 17 | */ 18 | export function runWorkspacesScripts({ 19 | script, 20 | concurrency, 21 | folder = 'packages', 22 | filteredPackages = [] 23 | }) { 24 | const moduleDir = dirname(fileURLToPath(import.meta.url)); 25 | 26 | function findPackagesWithScript(directory) { 27 | const packages = []; 28 | 29 | for (const name of fs.readdirSync(directory)) { 30 | if (!filteredPackages.includes(name)) { 31 | const pkgPath = join(directory, name); 32 | const pkgJsonPath = join(pkgPath, 'package.json'); 33 | 34 | if (fs.existsSync(pkgJsonPath)) { 35 | /** @type {{ scripts: object | undefined }} */ 36 | const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); 37 | 38 | if (pkgJson.scripts && pkgJson.scripts[script]) { 39 | packages.push(pkgPath); 40 | } 41 | } 42 | } 43 | } 44 | 45 | return packages; 46 | } 47 | 48 | const packagesDir = join(moduleDir, '..', folder); 49 | const packagesWithScript = findPackagesWithScript(packagesDir); 50 | 51 | const commands = packagesWithScript.map((pkgPath) => ({ 52 | name: basename(pkgPath), 53 | command: `cd ${pkgPath} && yarn ${script}` 54 | })); 55 | 56 | const { result } = concurrently(commands, { maxProcesses: concurrency }); 57 | result 58 | .then(() => { 59 | console.log( 60 | pc.green( 61 | `Successfully executed command ${pc.yellow( 62 | script 63 | )} for packages: ${pc.yellow(commands.map((c) => c.name).join(', '))}` 64 | ) 65 | ); 66 | console.log(); 67 | }) 68 | .catch((error) => { 69 | if (error instanceof Error) { 70 | console.error(error); 71 | } else if (Array.isArray(error)) { 72 | const count = error.filter((err) => err !== 0).length; 73 | console.log(''); 74 | console.log( 75 | pc.red( 76 | `Failed to execute command ${pc.yellow( 77 | script 78 | )} for ${count} packages. But we don't know which ones, because concurrently doesn't say.` 79 | ) 80 | ); 81 | console.log(); 82 | } 83 | process.exit(1); 84 | }); 85 | } 86 | -------------------------------------------------------------------------------- /packages/api-docs/src/styles.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | export default css` 4 | p, 5 | ul, 6 | ol { 7 | margin: 1rem 0; 8 | font-size: 0.9375rem; 9 | line-height: 1.5; 10 | } 11 | 12 | a { 13 | color: var(--ave-link-color); 14 | } 15 | 16 | a:hover { 17 | color: var(--ave-link-hover-color); 18 | } 19 | 20 | pre { 21 | white-space: pre-wrap; 22 | } 23 | 24 | api-docs-layout { 25 | display: block; 26 | } 27 | 28 | [part='tab'][heading^='CSS'] { 29 | min-width: 120px; 30 | font-size: 0.8125rem; 31 | } 32 | 33 | [part='docs-item'] { 34 | display: block; 35 | padding: 0.5rem; 36 | color: var(--ave-item-color); 37 | } 38 | 39 | [part='docs-item']:not(:first-of-type) { 40 | border-top: solid 1px var(--ave-border-color); 41 | } 42 | 43 | [part='docs-tag'] { 44 | background-color: var(--ave-tag-background-color); 45 | border: 1px solid var(--ave-tag-border-color); 46 | border-radius: 3px; 47 | color: var(--ave-tag-color); 48 | display: inline-block; 49 | font-size: 0.75rem; 50 | padding: 1px 5px; 51 | } 52 | 53 | [part='docs-description'] { 54 | display: block; 55 | padding: 0 1rem; 56 | border-bottom: solid 1px var(--ave-border-color); 57 | } 58 | 59 | [part='docs-row'] { 60 | display: flex; 61 | flex-wrap: wrap; 62 | margin-bottom: 1rem; 63 | } 64 | 65 | [part='docs-column'] { 66 | box-sizing: border-box; 67 | flex-basis: 25%; 68 | padding-right: 0.5rem; 69 | } 70 | 71 | [part='docs-column']:only-child { 72 | flex-basis: 100%; 73 | } 74 | 75 | .column-name-css, 76 | .column-type { 77 | flex-basis: 50%; 78 | } 79 | 80 | [part='docs-label'] { 81 | color: var(--ave-label-color); 82 | font-size: 0.75rem; 83 | line-height: 1rem; 84 | letter-spacing: 0.1rem; 85 | } 86 | 87 | [part='docs-value'] { 88 | font-family: var(--ave-monospace-font); 89 | font-size: 0.875rem; 90 | line-height: 1.5rem; 91 | } 92 | 93 | [part='docs-markdown'] p, 94 | [part='docs-markdown'] ul, 95 | [part='docs-markdown'] ol { 96 | margin: 0.5rem 0; 97 | } 98 | 99 | [part$='params'] { 100 | color: var(--ave-item-color); 101 | } 102 | 103 | [part$='type'] { 104 | color: var(--ave-secondary-color); 105 | } 106 | 107 | .accent { 108 | color: var(--ave-accent-color); 109 | } 110 | 111 | @media (max-width: 480px) { 112 | .column-type { 113 | margin-top: 1rem; 114 | } 115 | 116 | .column-name-css, 117 | .column-type { 118 | flex-basis: 100%; 119 | } 120 | 121 | [part='tab'][heading^='CSS'] { 122 | max-width: 125px; 123 | } 124 | } 125 | `; 126 | -------------------------------------------------------------------------------- /packages/api-demo/src/ui/knobs.ts: -------------------------------------------------------------------------------- 1 | import { unquote, type ClassField } from '@api-viewer/common/lib/index.js'; 2 | import { 3 | getTemplateNode, 4 | getTemplates, 5 | TemplateTypes 6 | } from '@api-viewer/common/lib/templates.js'; 7 | import type { ComponentWithProps, KnobValue, PropertyKnob } from '../types.js'; 8 | 9 | const getDefault = (prop: PropertyKnob): KnobValue => { 10 | const { knobType, default: value } = prop; 11 | switch (knobType) { 12 | case 'boolean': 13 | return value !== 'false'; 14 | case 'number': 15 | return Number(value); 16 | default: 17 | return unquote(value); 18 | } 19 | }; 20 | 21 | const normalizeType = (type: string | undefined = ''): string => 22 | type.replace(' | undefined', '').replace(' | null', ''); 23 | 24 | export const getKnobs = (props: ClassField[], exclude = ''): PropertyKnob[] => { 25 | // Exclude getters and specific properties 26 | let propKnobs = props.filter( 27 | ({ name, readonly }) => !exclude.includes(name) && !readonly 28 | ) as PropertyKnob[]; 29 | 30 | // Set knob types and default knobs values 31 | propKnobs = propKnobs.map((prop) => { 32 | const knob = { 33 | ...prop, 34 | knobType: normalizeType(prop.type?.text) 35 | }; 36 | 37 | if (typeof knob.default === 'string') { 38 | knob.value = getDefault(knob); 39 | } 40 | 41 | return knob; 42 | }); 43 | 44 | return propKnobs; 45 | }; 46 | 47 | export const getCustomKnobs = (tag: string, vid?: number): PropertyKnob[] => 48 | getTemplates(vid!, tag, TemplateTypes.KNOB) 49 | .map((template) => { 50 | const { attr, type } = template.dataset; 51 | let result = null; 52 | if (attr) { 53 | if (type === 'select') { 54 | const node = getTemplateNode(template); 55 | const options = node 56 | ? Array.from(node.children) 57 | .filter( 58 | (c): c is HTMLOptionElement => c instanceof HTMLOptionElement 59 | ) 60 | .map((option) => option.value) 61 | : []; 62 | if (node instanceof HTMLSelectElement && options.length > 1) { 63 | result = { 64 | name: attr, 65 | attribute: attr, 66 | knobType: type, 67 | options 68 | }; 69 | } 70 | } 71 | if (type === 'string' || type === 'boolean') { 72 | result = { 73 | name: attr, 74 | attribute: attr, 75 | knobType: type 76 | }; 77 | } 78 | } 79 | return result as PropertyKnob; 80 | }) 81 | .filter(Boolean); 82 | 83 | export const getInitialKnobs = ( 84 | propKnobs: PropertyKnob[], 85 | component: HTMLElement 86 | ): PropertyKnob[] => 87 | propKnobs.filter((prop) => { 88 | const { name, knobType } = prop; 89 | const defaultValue = getDefault(prop); 90 | return ( 91 | (component as unknown as ComponentWithProps)[name] !== defaultValue || 92 | (knobType === 'boolean' && defaultValue) 93 | ); 94 | }); 95 | -------------------------------------------------------------------------------- /packages/api-viewer/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # api-viewer-element 2 | 3 | ## 1.0.0-pre.10 4 | 5 | ### Patch Changes 6 | 7 | - 91c394a: Use proper selector for demo copy button styles 8 | - Updated dependencies [91c394a] 9 | - @api-viewer/demo@1.0.0-pre.10 10 | - @api-viewer/common@1.0.0-pre.10 11 | - @api-viewer/docs@1.0.0-pre.10 12 | 13 | ## 1.0.0-pre.9 14 | 15 | ### Patch Changes 16 | 17 | - 5f7183f: Added the ability to show whether a property is static 18 | - 1d3a419: Show whether a property reflects to attribute 19 | - Updated dependencies [5f7183f] 20 | - Updated dependencies [1d3a419] 21 | - @api-viewer/common@1.0.0-pre.9 22 | - @api-viewer/demo@1.0.0-pre.9 23 | - @api-viewer/docs@1.0.0-pre.9 24 | 25 | ## 1.0.0-pre.8 26 | 27 | ### Patch Changes 28 | 29 | - 289741e: Update custom-elements-manifest to v2.0.0, add readonly support 30 | - Updated dependencies [289741e] 31 | - @api-viewer/common@1.0.0-pre.8 32 | - @api-viewer/demo@1.0.0-pre.8 33 | - @api-viewer/docs@1.0.0-pre.8 34 | 35 | ## 1.0.0-pre.7 36 | 37 | ### Patch Changes 38 | 39 | - e39f213: Respect filtered elements when determining selected 40 | - Updated dependencies [e39f213] 41 | - @api-viewer/common@1.0.0-pre.7 42 | - @api-viewer/demo@1.0.0-pre.7 43 | - @api-viewer/docs@1.0.0-pre.7 44 | 45 | ## 1.0.0-pre.6 46 | 47 | ### Patch Changes 48 | 49 | - 3061534: Add only property to filter elements 50 | - Updated dependencies [3061534] 51 | - @api-viewer/common@1.0.0-pre.6 52 | - @api-viewer/demo@1.0.0-pre.6 53 | - @api-viewer/docs@1.0.0-pre.6 54 | 55 | ## 1.0.0-pre.5 56 | 57 | ### Patch Changes 58 | 59 | - cc911b6: Add methods tab to API documentation 60 | - Updated dependencies [afd7ef1] 61 | - Updated dependencies [cc911b6] 62 | - @api-viewer/docs@1.0.0-pre.5 63 | - @api-viewer/common@1.0.0-pre.5 64 | - @api-viewer/demo@1.0.0-pre.5 65 | 66 | ## 1.0.0-pre.4 67 | 68 | ### Patch Changes 69 | 70 | - 1e3dfe8: Update marked dependency to 4.0.10 71 | - Updated dependencies [1e3dfe8] 72 | - @api-viewer/docs@1.0.0-pre.4 73 | - @api-viewer/common@1.0.0-pre.4 74 | - @api-viewer/demo@1.0.0-pre.4 75 | 76 | ## 1.0.0-pre.3 77 | 78 | ### Patch Changes 79 | 80 | - 24ada26: Use vanilla custom elements for tabs 81 | - Updated dependencies [24ada26] 82 | - Updated dependencies [8f1df74] 83 | - @api-viewer/common@1.0.0-pre.3 84 | - @api-viewer/demo@1.0.0-pre.3 85 | - @api-viewer/docs@1.0.0-pre.3 86 | 87 | ## 1.0.0-pre.2 88 | 89 | ### Patch Changes 90 | 91 | - e51bd2f: Move demo types to api-demo package 92 | - 9c60a0a: Update slot knobs to render name properly 93 | - Updated dependencies [e51bd2f] 94 | - Updated dependencies [9c60a0a] 95 | - @api-viewer/common@1.0.0-pre.2 96 | - @api-viewer/demo@1.0.0-pre.2 97 | - @api-viewer/docs@1.0.0-pre.2 98 | 99 | ## 1.0.0-pre.1 100 | 101 | ### Patch Changes 102 | 103 | - e9f9747: Convert api-viewer-element to monorepo 104 | - Updated dependencies [56f3e68] 105 | - Updated dependencies [e9f9747] 106 | - @api-viewer/demo@1.0.0-pre.1 107 | - @api-viewer/common@1.0.0-pre.1 108 | - @api-viewer/docs@1.0.0-pre.1 109 | -------------------------------------------------------------------------------- /packages/api-demo/src/ui/controls.ts: -------------------------------------------------------------------------------- 1 | import { html, type TemplateResult } from 'lit'; 2 | import type { 3 | CssCustomPropertyValue, 4 | Knobable, 5 | PropertyKnob, 6 | SlotValue 7 | } from '../types.js'; 8 | 9 | type InputRenderer = (item: Knobable, id: string) => TemplateResult; 10 | 11 | const capitalize = (name: string): string => 12 | name[0].toUpperCase() + name.slice(1); 13 | 14 | export const formatSlot = (name: string): string => 15 | capitalize(name === '' ? 'content' : name); 16 | 17 | export const cssPropRenderer: InputRenderer = ( 18 | knob: Knobable, 19 | id: string 20 | ): TemplateResult => { 21 | const { name, value } = knob as CssCustomPropertyValue; 22 | 23 | return html` 24 | 31 | `; 32 | }; 33 | 34 | export const propRenderer: InputRenderer = ( 35 | knob: Knobable, 36 | id: string 37 | ): TemplateResult => { 38 | const { name, knobType, value, options } = knob as PropertyKnob; 39 | let input; 40 | if (knobType === 'select' && Array.isArray(options)) { 41 | input = html` 42 | 47 | `; 48 | } else if (knobType === 'boolean') { 49 | input = html` 50 | 58 | `; 59 | } else { 60 | input = html` 61 | 69 | `; 70 | } 71 | return input; 72 | }; 73 | 74 | export const slotRenderer: InputRenderer = ( 75 | knob: Knobable, 76 | id: string 77 | ): TemplateResult => { 78 | const { name, content } = knob as SlotValue; 79 | 80 | return html` 81 | 89 | `; 90 | }; 91 | 92 | export const renderKnobs = ( 93 | items: Knobable[], 94 | header: string, 95 | type: string, 96 | renderer: InputRenderer 97 | ): TemplateResult => { 98 | const rows = items.map((item: Knobable) => { 99 | const { name } = item as PropertyKnob; 100 | const id = `${type}-${name || 'default'}`; 101 | const label = type === 'slot' ? formatSlot(name) : name; 102 | return html` 103 | 104 | 105 | 106 | 107 | ${renderer(item, id)} 108 | 109 | `; 110 | }); 111 | 112 | return html` 113 |

${header}

114 | 115 | ${rows} 116 |
117 | `; 118 | }; 119 | -------------------------------------------------------------------------------- /docs/docs/guide/using-demo.md: -------------------------------------------------------------------------------- 1 | # Guide >> Using demo || 30 2 | 3 | Live demo is an interactive playground that renders an instance of a web component and provides UI controls to interact with it. 4 | Several panels are available depending on the functionality the component supports. 5 | 6 | ## Importing 7 | 8 | In order to use live demo, import the components documented in the manifest. 9 | The demo component uses [`customElements.whenDefined()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined), which returns a Promise, so importing the components lazily also works. 10 | 11 | ```html 12 | 15 | 16 | ``` 17 | 18 | If you want to render live demo separately from the API documentation, consider using [``](../../examples/api-demo/) element instead of the ``. 19 | All of the features and use cases listed below apply to both components. 20 | 21 | ## Source 22 | 23 | The Source panel contains an HTML code snippet representing the component with its 24 | [properties](../writing-jsdoc/#properties), HTML attributes and [slots](../writing-jsdoc/#slots). 25 | When setting knobs or styles using corresponding panels, code snippet is updated. 26 | 27 | For example, changing a custom CSS property to the value other than the default one will add ` 91 | 92 | `; 93 | 94 | export class ApiViewerTab extends HTMLElement { 95 | private _mousedown = false; 96 | 97 | private _selected = false; 98 | 99 | get selected(): boolean { 100 | return this._selected; 101 | } 102 | 103 | set selected(selected: boolean) { 104 | this._selected = selected; 105 | 106 | this.setAttribute('aria-selected', String(selected)); 107 | this.setAttribute('tabindex', selected ? '0' : '-1'); 108 | 109 | this.toggleAttribute('selected', selected); 110 | } 111 | 112 | constructor() { 113 | super(); 114 | 115 | const root = this.attachShadow({ mode: 'open' }); 116 | root.appendChild(tpl.content.cloneNode(true)); 117 | 118 | this.addEventListener('focus', () => this._setFocused(true), true); 119 | this.addEventListener( 120 | 'blur', 121 | () => { 122 | this._setFocused(false); 123 | this._setActive(false); 124 | }, 125 | true 126 | ); 127 | 128 | this.addEventListener('mousedown', () => { 129 | this._setActive((this._mousedown = true)); 130 | const mouseUpListener = () => { 131 | this._setActive((this._mousedown = false)); 132 | document.removeEventListener('mouseup', mouseUpListener); 133 | }; 134 | document.addEventListener('mouseup', mouseUpListener); 135 | }); 136 | } 137 | 138 | connectedCallback(): void { 139 | this.setAttribute('role', 'tab'); 140 | 141 | if (!this.id) { 142 | this.id = `api-viewer-tab-${tabIdCounter++}`; 143 | } 144 | } 145 | 146 | private _setActive(active: boolean): void { 147 | this.toggleAttribute('active', active); 148 | } 149 | 150 | private _setFocused(focused: boolean): void { 151 | this.toggleAttribute('focused', focused); 152 | this.toggleAttribute('focus-ring', focused && !this._mousedown); 153 | } 154 | } 155 | 156 | customElements.define('api-viewer-tab', ApiViewerTab); 157 | 158 | declare global { 159 | interface HTMLElementTagNameMap { 160 | 'api-viewer-tab': ApiViewerTab; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # <api-viewer> 2 | 3 | API documentation and live playground for Web Components. Based on [custom elements manifest](https://github.com/webcomponents/custom-elements-manifest) JSON format. 4 | 5 | ```html 6 | 7 | ``` 8 | 9 | [Documentation →](https://api-viewer.open-wc.org/docs/guide/intro/) 10 | 11 | [Live Demo →](https://api-viewer.open-wc.org/docs/examples/api-viewer/) 12 | 13 | [Screenshot of api-viewer docs](https://api-viewer.open-wc.org) 14 | 15 | [Screenshot of api-viewer demo](https://api-viewer.open-wc.org) 16 | 17 | ## Features 18 | 19 | - [API docs viewer](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/) 20 | - [Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#properties) - JS properties publicly exposed by the component. 21 | - [Attributes](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#attributes) - HTML attributes (except those that match properties). 22 | - [Events](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#events) - DOM events dispatched by the component. 23 | - [Slots](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#slots) - Default `` and / or named slots, if any. 24 | - [CSS Custom Properties](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-custom-properties) - Styling API of the component. 25 | - [CSS Shadow Parts](https://api-viewer.open-wc.org/docs/guide/writing-jsdoc/#css-shadow-parts) - Elements that can be styled using `::part()`. 26 | - [Live playground](https://api-viewer.open-wc.org/docs/guide/using-demo/) 27 | - [Source](https://api-viewer.open-wc.org/docs/guide/using-demo/#source) - Code snippet matching the rendered component. 28 | - [Knobs](https://api-viewer.open-wc.org/docs/guide/using-demo/#knobs) - Change properties and slotted content dynamically. 29 | - [Styles](https://api-viewer.open-wc.org/docs/guide/using-demo/#styles) - Change values of the custom CSS properties. 30 | - [Event log](https://api-viewer.open-wc.org/docs/guide/using-demo/#events) - Output the events fired by the component. 31 | - [Templates](https://api-viewer.open-wc.org/docs/api/templates/) - Provide additional HTML to be shown. 32 | 33 | ## Install 34 | 35 | ```sh 36 | npm install api-viewer-element 37 | ``` 38 | 39 | Check out the [Getting Started](https://api-viewer.open-wc.org/docs/guide/intro/#usage) guide. 40 | 41 | ## Usage 42 | 43 | The following web components are available: 44 | 45 | - [``](https://api-viewer.open-wc.org/docs/api/elements/#api-viewer-element) 46 | - [``](https://api-viewer.open-wc.org/docs/api/elements/#api-docs-element) 47 | - [``](https://api-viewer.open-wc.org/docs/api/elements/#api-demo-element) 48 | 49 | ## Contributing 50 | 51 | ### Install dependencies 52 | 53 | ```sh 54 | yarn 55 | ``` 56 | 57 | ### Run demo in browser 58 | 59 | ```sh 60 | yarn dev 61 | ``` 62 | 63 | Open http://127.0.0.1:8000 64 | 65 | ### Run the docs locally 66 | 67 | ```sh 68 | yarn start 69 | ``` 70 | 71 | Open http://127.0.0.1:8000 72 | 73 | ### Build the docs site 74 | 75 | ```sh 76 | yarn dist 77 | ``` 78 | 79 | ## Acknowledgements 80 | 81 | - Big thanks to [@thepassle](https://github.com/thepassle) for creating Custom Elements Manifest Analyzer, that this project is built upon. 82 | - Big thanks to [@runem](http://github.com/runem) for creating [Web Component Analyzer](https://github.com/runem/web-component-analyzer) used in older versions of API Viewer. 83 | - Big thanks to [Modern Web](https://modern-web.dev) for [Web Dev Server](https://modern-web.dev/docs/dev-server/overview/) and [Rocket](https://rocket.modern-web.dev) used for the documentation website. 84 | - Thanks to [@bahrus](https://github.com/bahrus) for [wc-info](https://github.com/bahrus/wc-info), a similar web component that served as a source of inspiration for me. 85 | - The `@api-viewer/tabs` web component is based on [tabs example](https://github.com/GoogleChromeLabs/howto-components/tree/master/elements/howto-tabs) from [HowTo: Components](https://developers.google.com/web/fundamentals/web-components/examples) project. 86 | - The visual appearance is largely inspired by older version of [Vuetify](https://vuetifyjs.com/en/getting-started/quick-start) API documentation. 87 | -------------------------------------------------------------------------------- /docs/docs/api/elements.md: -------------------------------------------------------------------------------- 1 | # API >> Elements || 10 2 | 3 | API Viewer consists of two major features: documentation and demo (interactive live playground). 4 | Both features reuse the same [manifest data](../../guide/writing-jsdoc/), by default you can switch between them using radio buttons. 5 | 6 | Alternatively, you can use separate elements for documentation and demo. 7 | This does not mean having to load manifest data twice: it can be fetched once and then passed to the elements using `manifest` property. 8 | 9 | ## Entrypoints 10 | 11 | There are two ES module entrypoints available for each of the web components that are public parts of the API Viewer. 12 | The main entrypoint recommended for most users defines a custom element with default styles. 13 | 14 | ### `` element 15 | 16 | A custom element that provides both API docs and live playground: 17 | 18 | ```js 19 | import 'api-viewer-element'; 20 | ``` 21 | 22 | ### `` element 23 | 24 | A custom element that only provides API docs (no live playground): 25 | 26 | ```js 27 | import '@api-viewer/docs'; 28 | ``` 29 | 30 | ### `` element 31 | 32 | A custom element that only provides live playground (no API docs): 33 | 34 | ```js 35 | import '@api-viewer/demo'; 36 | ``` 37 | 38 | Note: the default entrypoint shares most of the code with both `` and ``. 39 | However, it does not contain custom element definitions for these components. 40 | You need to import them separately. 41 | 42 | ## Base classes 43 | 44 | API Viewer provides a set of [Lit](https://lit.dev/docs/components/defining/) based classes that can be imported without defining custom elements. 45 | This is useful if you want to create an extension and register your own component with a different tag name. 46 | 47 | Please note that attempting to register the same base class twice will result in an error. 48 | Do not pass any base class directly to `customElements.define()`: make sure to extend it instead, as shown in the examples below. 49 | 50 | ### `ApiViewerBase` class 51 | 52 | A class that you can use to create your own version of ``. 53 | If you don't need [`