diff --git a/.gitignore b/.gitignore index e7f19329c..b0a6ab872 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ package.json package-lock.json dist docs/assets/images/sprite.svg +docs/public/pagefind node_modules src/react cdn +.astro diff --git a/docs/.vscode/extensions.json b/docs/.vscode/extensions.json new file mode 100644 index 000000000..22a15055d --- /dev/null +++ b/docs/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/docs/.vscode/launch.json b/docs/.vscode/launch.json new file mode 100644 index 000000000..d64220976 --- /dev/null +++ b/docs/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/docs/_includes/component.njk b/docs/_includes/component.njk deleted file mode 100644 index 709082471..000000000 --- a/docs/_includes/component.njk +++ /dev/null @@ -1,349 +0,0 @@ -{% extends "default.njk" %} - -{# Find the component based on the `tag` front matter #} -{% set component = getComponent('wa-' + page.fileSlug) %} - -{% block content %} - {# Determine the badge variant #} - {% if component.status == 'stable' %} - {% set badgeVariant = 'brand' %} - {% elseif component.status == 'experimental' %} - {% set badgeVariant = 'warning' %} - {% elseif component.status == 'planned' %} - {% set badgeVariant = 'neutral' %} - {% elseif component.status == 'deprecated' %} - {% set badgeVariant = 'danger' %} - {% else %} - {% set badgeVariant = 'neutral' %} - {% endif %} - - {# Header #} -
-

{{ component.name | classNameToComponentName }}

- -
- <{{ component.tagName }}> | {{ component.name }} -
- -
- - Since {{component.since or '?' }} - - - {{ component.status }} - -
-
- -

- {% if component.summary %} - {{ component.summary | markdownInline | safe }} - {% endif %} -

- - {# Markdown content #} - {{ content | safe }} - - {# Importing #} -

Importing

-

- If you're using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use - any of the following snippets to cherry pick this component. -

- - - Script - Import - Bundler - React - - -

- To import this component from the CDN - using a script tag: -

-
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}"></script>
-
- - -

- To import this component from the CDN - using a JavaScript import: -

-
import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@{{ meta.version }}/{{ meta.cdndir }}/{{ component.path }}';
-
- - -

- To import this component using a bundler: -

-
import '@shoelace-style/shoelace/{{ meta.npmdir }}/{{ component.path }}';
-
- - -

- To import this component as a React component: -

-
import {{ component.name }} from '@shoelace-style/shoelace/{{ meta.npmdir }}/react/{{ component.tagNameWithoutPrefix }}';
-
-
- - {# Slots #} - {% if component.slots.length %} -

Slots

- - - - - - - - - - {% for slot in component.slots %} - - - - - {% endfor %} - -
NameDescription
- {% if slot.name %} - {{ slot.name }} - {% else %} - (default) - {% endif %} - {{ slot.description | markdownInline | safe }}
- -

Learn more about using slots.

- {% endif %} - - {# Properties #} - {% if component.properties.length %} -

Properties

- - - - - - - - - - - - - {% for prop in component.properties %} - - - - - - - - {% endfor %} - - - - - - - - -
NameDescriptionReflectsTypeDefault
- {{ prop.name }} - {% if prop.attribute | length > 0 %} - {% if prop.attribute != prop.name %} -
- - - - {{ prop.attribute }} - - - - {% endif %} - {% endif %} -
- {{ prop.description | markdownInline | safe }} - - {% if prop.reflects %} - - {% endif %} - - {% if prop.type.text %} - {{ prop.type.text | trimPipes | markdownInline | safe }} - {% else %} - - - {% endif %} - - {% if prop.default %} - {{ prop.default | markdownInline | safe }} - {% else %} - - - {% endif %} -
updateComplete - A read-only promise that resolves when the component has - finished updating. -
- -

Learn more about attributes and properties.

- {% endif %} - - {# Events #} - {% if component.events.length %} -

Events

- - - - - - - - - - - - {% for event in component.events %} - - - - - - - {% endfor %} - -
NameReact EventDescriptionEvent Detail
{{ event.name }}{{ event.reactName }}{{ event.description | markdownInline | safe }} - {% if event.type.text %} - {{ event.type.text | trimPipes }} - {% else %} - - - {% endif %} -
- -

Learn more about events.

- {% endif %} - - {# Methods #} - {% if component.methods.length %} -

Methods

- - - - - - - - - - - {% for method in component.methods %} - - - - - - {% endfor %} - -
NameDescriptionArguments
{{ method.name }}(){{ method.description | markdownInline | safe }} - {% if method.parameters.length %} - - {% for param in method.parameters %} - {{ param.name }}: {{ param.type.text | trimPipes }}{% if not loop.last %},{% endif %} - {% endfor %} - - {% else %} - - - {% endif %} -
- -

Learn more about methods.

- {% endif %} - - {# Custom Properties #} - {% if component.cssProperties.length %} -

Custom Properties

- - - - - - - - - - - {% for cssProperty in component.cssProperties %} - - - - - - {% endfor %} - -
NameDescriptionDefault
{{ cssProperty.name }}{{ cssProperty.description | markdownInline | safe }}{{ cssProperty.default }}
- -

Learn more about customizing CSS custom properties.

- {% endif %} - - {# CSS Parts #} - {% if component.cssParts.length %} -

Parts

- - - - - - - - - - {% for cssPart in component.cssParts %} - - - - - {% endfor %} - -
NameDescription
{{ cssPart.name }}{{ cssPart.description | markdownInline | safe }}
- -

Learn more about customizing CSS parts.

- {% endif %} - - {# Animations #} - {% if component.animations.length %} -

Animations

- - - - - - - - - - {% for animation in component.animations %} - - - - - {% endfor %} - -
NameDescription
{{ animation.name }}{{ animation.description | markdownInline | safe }}
- -

Learn more about customizing animations.

- {% endif %} - - {# Dependencies #} - {% if component.dependencies.length %} -

Dependencies

- -

This component automatically imports the following dependencies.

- - - {% endif %} -{% endblock %} diff --git a/docs/_includes/default.njk b/docs/_includes/default.njk deleted file mode 100644 index b9db3c213..000000000 --- a/docs/_includes/default.njk +++ /dev/null @@ -1,129 +0,0 @@ - - - - {# Metadata #} - - - - {{ meta.title }} - - {# Opt out of Turbo caching #} - - - {# Stylesheets #} - - - - - {# Favicons #} - - - {# Twitter Cards #} - - - - - {# OpenGraph #} - - - - - - {# Web Awesome #} - - - - - - {# Set the initial theme and menu states here to prevent flashing #} - - - {# Web Fonts #} - - - - - {# Turbo + Scroll positioning #} - - - - - - - - - Skip to main content - - - {# Menu toggle #} - - - - - {# Content #} -
- -
- {% if toc %} - - {% endif %} - -
- {% block content %} - {{ content | safe }} - {% endblock %} -
-
-
- - diff --git a/docs/_includes/sidebar.njk b/docs/_includes/sidebar.njk deleted file mode 100644 index 121c033e8..000000000 --- a/docs/_includes/sidebar.njk +++ /dev/null @@ -1,85 +0,0 @@ - diff --git a/docs/_utilities/active-links.cjs b/docs/_utilities/active-links.cjs deleted file mode 100644 index 7a998054e..000000000 --- a/docs/_utilities/active-links.cjs +++ /dev/null @@ -1,35 +0,0 @@ -function normalizePathname(pathname) { - // Remove /index.html - if (pathname.endsWith('/index.html')) { - pathname = pathname.replace(/\/index\.html/, ''); - } - - // Remove trailing slashes - return pathname.replace(/\/$/, ''); -} - -/** - * Adds a class name to links that are currently active. - */ -module.exports = function (doc, options) { - options = { - className: 'active-link', // the class to add to active links - pathname: undefined, // the current pathname to compare - within: 'body', // element containing the target links - ...options - }; - - const within = doc.querySelector(options.within); - - if (!within) { - return doc; - } - - within.querySelectorAll('a').forEach(link => { - if (normalizePathname(options.pathname) === normalizePathname(link.pathname)) { - link.classList.add(options.className); - } - }); - - return doc; -}; diff --git a/docs/_utilities/anchor-headings.cjs b/docs/_utilities/anchor-headings.cjs deleted file mode 100644 index 64a71668a..000000000 --- a/docs/_utilities/anchor-headings.cjs +++ /dev/null @@ -1,64 +0,0 @@ -const { createSlug } = require('./strings.cjs'); - -/** - * Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM. - * The same document will be returned with the appropriate DOM manipulations. - */ -module.exports = function (doc, options) { - options = { - levels: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], // the headings to convert - className: 'anchor-heading', // the class name to add - within: 'body', // the element containing the target headings - ...options - }; - - const within = doc.querySelector(options.within); - - if (!within) { - return doc; - } - - within.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => { - const hasAnchor = heading.querySelector('a'); - const anchor = doc.createElement('a'); - let id = heading.textContent ?? ''; - let suffix = 0; - - // Skip heading levels we don't care about - if (!options.levels?.includes(heading.tagName.toLowerCase())) { - return; - } - - // Convert dots to underscores - id = id.replace(/\./g, '_'); - - // Turn it into a slug - id = createSlug(id); - - // Make sure it starts with a letter - if (!/^[a-z]/i.test(id)) { - id = `id_${id}`; - } - - // Make sure the id is unique - const originalId = id; - while (doc.getElementById(id) !== null) { - id = `${originalId}-${++suffix}`; - } - - if (hasAnchor || !id) return; - - heading.setAttribute('id', id); - anchor.setAttribute('href', `#${encodeURIComponent(id)}`); - anchor.setAttribute('aria-label', `Direct link to "${heading.textContent}"`); - - if (options.className) { - heading.classList.add(options.className); - } - - // Append the anchor - heading.append(anchor); - }); - - return doc; -}; diff --git a/docs/_utilities/code-previews.cjs b/docs/_utilities/code-previews.cjs deleted file mode 100644 index 59daefcce..000000000 --- a/docs/_utilities/code-previews.cjs +++ /dev/null @@ -1,138 +0,0 @@ -let count = 1; - -function escapeHtml(str) { - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} - -/** - * Turns code fields with the :preview suffix into interactive code previews. - */ -module.exports = function (doc, options) { - options = { - within: 'body', // the element containing the code fields to convert - ...options - }; - - const within = doc.querySelector(options.within); - if (!within) { - return doc; - } - - within.querySelectorAll('[class*=":preview"]').forEach(code => { - const pre = code.closest('pre'); - if (!pre) { - return; - } - const adjacentPre = pre.nextElementSibling?.tagName.toLowerCase() === 'pre' ? pre.nextElementSibling : null; - const reactCode = adjacentPre?.querySelector('code[class$="react"]'); - const sourceGroupId = `code-preview-source-group-${count}`; - const isExpanded = code.getAttribute('class').includes(':expanded'); - const noCodePen = code.getAttribute('class').includes(':no-codepen'); - - count++; - - const htmlButton = ` - - `; - - const reactButton = ` - - `; - - const codePenButton = ` - - `; - - const codePreview = ` -
-
- ${code.textContent} -
- -
-
- -
-
-
${escapeHtml(code.textContent)}
-
- - ${ - reactCode - ? ` -
-
${escapeHtml(reactCode.textContent)}
-
- ` - : '' - } -
- -
- - - ${reactCode ? ` ${htmlButton} ${reactButton} ` : ''} - - ${noCodePen ? '' : codePenButton} -
-
- `; - - pre.insertAdjacentHTML('afterend', codePreview); - pre.remove(); - - if (adjacentPre) { - adjacentPre.remove(); - } - }); - - // Wrap code preview scripts in anonymous functions so they don't run in the global scope - doc.querySelectorAll('.code-preview__preview script').forEach(script => { - if (script.type === 'module') { - // Modules are already scoped - script.textContent = script.innerHTML; - } else { - // Wrap non-modules in an anonymous function so they don't run in the global scope - script.textContent = `(() => { ${script.innerHTML} })();`; - } - }); - - return doc; -}; diff --git a/docs/_utilities/copy-code-buttons.cjs b/docs/_utilities/copy-code-buttons.cjs deleted file mode 100644 index be2784604..000000000 --- a/docs/_utilities/copy-code-buttons.cjs +++ /dev/null @@ -1,23 +0,0 @@ -let codeBlockId = 0; - -/** - * Adds copy code buttons to code fields. The provided doc should be a document object provided by JSDOM. The same - * document will be returned with the appropriate DOM manipulations. - */ -module.exports = function (doc) { - doc.querySelectorAll('pre > code').forEach(code => { - const pre = code.closest('pre'); - const button = doc.createElement('wa-copy-button'); - - if (!code.id) { - code.id = `code-block-${++codeBlockId}`; - } - - button.classList.add('copy-code-button'); - button.setAttribute('from', code.id); - - pre.append(button); - }); - - return doc; -}; diff --git a/docs/_utilities/external-links.cjs b/docs/_utilities/external-links.cjs deleted file mode 100644 index 36a95898a..000000000 --- a/docs/_utilities/external-links.cjs +++ /dev/null @@ -1,41 +0,0 @@ -const { isExternalLink } = require('./strings.cjs'); - -/** - * Transforms external links to make them safer and optionally add a target. The provided doc should be a document - * object provided by JSDOM. The same document will be returned with the appropriate DOM manipulations. - */ -module.exports = function (doc, options) { - options = { - className: 'external-link', // the class name to add to links - noopener: true, // sets rel="noopener" - noreferrer: true, // sets rel="noreferrer" - ignore: () => false, // callback function to filter links that should be ignored - within: 'body', // element that contains the target links - target: '', // sets the target attribute - ...options - }; - - const within = doc.querySelector(options.within); - - if (within) { - within.querySelectorAll('a').forEach(link => { - if (isExternalLink(link) && !options.ignore(link)) { - link.classList.add(options.className); - - const rel = []; - if (options.noopener) rel.push('noopener'); - if (options.noreferrer) rel.push('noreferrer'); - - if (rel.length) { - link.setAttribute('rel', rel.join(' ')); - } - - if (options.target) { - link.setAttribute('target', options.target); - } - } - }); - } - - return doc; -}; diff --git a/docs/_utilities/highlight-code.cjs b/docs/_utilities/highlight-code.cjs deleted file mode 100644 index bb4c01f09..000000000 --- a/docs/_utilities/highlight-code.cjs +++ /dev/null @@ -1,63 +0,0 @@ -const Prism = require('prismjs'); -const PrismLoader = require('prismjs/components/index.js'); - -PrismLoader('diff'); -PrismLoader.silent = true; - -/** Highlights a code string. */ -function highlight(code, language) { - const alias = language.replace(/^diff-/, ''); - const isDiff = /^diff-/i.test(language); - - // Auto-load the target language - if (!Prism.languages[alias]) { - PrismLoader(alias); - - if (!Prism.languages[alias]) { - throw new Error(`Unsupported language for code highlighting: "${language}"`); - } - } - - // Register diff-* languages to use the diff grammar - if (isDiff) { - Prism.languages[language] = Prism.languages.diff; - } - - return Prism.highlight(code, Prism.languages[language], language); -} - -/** - * Highlights all code fields that have a language parameter. If the language has a colon in its name, the first chunk - * will be the language used and additional chunks will be applied as classes to the `
`. For example, a code field
- * tagged with "html:preview" will be rendered as `
`.
- *
- * The provided doc should be a document object provided by JSDOM. The same document will be returned with the
- * appropriate DOM manipulations.
- */
-module.exports = function (doc) {
-  doc.querySelectorAll('pre > code[class]').forEach(code => {
-    // Look for class="language-*" and split colons into separate classes
-    code.classList.forEach(className => {
-      if (className.startsWith('language-')) {
-        //
-        // We use certain suffixes to indicate code previews, expanded states, etc. The class might look something like
-        // this:
-        //
-        //  class="language-html:preview:expanded"
-        //
-        // The language will always come first, so we need to drop the "language-" prefix and everything after the first
-        // color to get the highlighter language.
-        //
-        const language = className.replace(/^language-/, '').split(':')[0];
-
-        try {
-          code.innerHTML = highlight(code.textContent ?? '', language);
-        } catch (err) {
-          // Language not found, skip it
-        }
-      }
-    });
-  });
-
-  return doc;
-};
diff --git a/docs/_utilities/markdown.cjs b/docs/_utilities/markdown.cjs
deleted file mode 100644
index 7cd6386be..000000000
--- a/docs/_utilities/markdown.cjs
+++ /dev/null
@@ -1,75 +0,0 @@
-const MarkdownIt = require('markdown-it');
-const markdownItContainer = require('markdown-it-container');
-const markdownItIns = require('markdown-it-ins');
-const markdownItKbd = require('markdown-it-kbd');
-const markdownItMark = require('markdown-it-mark');
-const markdownItReplaceIt = require('markdown-it-replace-it');
-
-const markdown = MarkdownIt({
-  html: true,
-  xhtmlOut: false,
-  breaks: false,
-  langPrefix: 'language-',
-  linkify: false,
-  typographer: false
-});
-
-// Third-party plugins
-markdown.use(markdownItContainer);
-markdown.use(markdownItIns);
-markdown.use(markdownItKbd);
-markdown.use(markdownItMark);
-markdown.use(markdownItReplaceIt);
-
-// Callouts
-['tip', 'warning', 'danger'].forEach(type => {
-  const variant = type === 'tip' ? 'brand' : type;
-  let icon = 'circle-info';
-  if (type === 'warning') icon = 'triangle-exclamation';
-  if (type === 'danger') icon = 'circle-exclamation';
-
-  markdown.use(markdownItContainer, type, {
-    render: function (tokens, idx) {
-      if (tokens[idx].nesting === 1) {
-        return `
-          
-            
-        `;
-      }
-      return '\n';
-    }
-  });
-});
-
-// Asides
-markdown.use(markdownItContainer, 'aside', {
-  render: function (tokens, idx) {
-    if (tokens[idx].nesting === 1) {
-      return `\n';
-  }
-});
-
-// Details
-markdown.use(markdownItContainer, 'details', {
-  validate: params => params.trim().match(/^details\s+(.*)$/),
-  render: (tokens, idx) => {
-    const m = tokens[idx].info.trim().match(/^details\s+(.*)$/);
-    if (tokens[idx].nesting === 1) {
-      return `
\n${markdown.utils.escapeHtml(m[1])}\n`; - } - return '
\n'; - } -}); - -// Replace [#1234] with a link to GitHub issues -markdownItReplaceIt.replacements.push({ - name: 'github-issues', - re: /\[#([0-9]+)\]/gs, - sub: '#$1', - html: true, - default: true -}); - -module.exports = markdown; diff --git a/docs/_utilities/prettier.cjs b/docs/_utilities/prettier.cjs deleted file mode 100644 index db18fba40..000000000 --- a/docs/_utilities/prettier.cjs +++ /dev/null @@ -1,26 +0,0 @@ -const { format } = require('prettier'); - -/** Formats markup using prettier. */ -module.exports = function (content, options) { - options = { - arrowParens: 'avoid', - bracketSpacing: true, - htmlWhitespaceSensitivity: 'css', - insertPragma: false, - bracketSameLine: false, - jsxSingleQuote: false, - parser: 'html', - printWidth: 120, - proseWrap: 'preserve', - quoteProps: 'as-needed', - requirePragma: false, - semi: true, - singleQuote: true, - tabWidth: 2, - trailingComma: 'none', - useTabs: false, - ...options - }; - - return format(content, options); -}; diff --git a/docs/_utilities/replacer.cjs b/docs/_utilities/replacer.cjs deleted file mode 100644 index d2036ce7e..000000000 --- a/docs/_utilities/replacer.cjs +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @typedef {object} Replacement - * @property {string | RegExp} pattern - * @property {string} replacement - */ - -/** - * @typedef {Array} Replacements - */ - -/** - * @param {Document} content - * @param {Replacements} replacements - */ -module.exports = function (content, replacements) { - /** This seems trivial, but by assigning to a string first, THEN using innerHTML after iterating over every replacement, we reduce the calculations of JSDOM. At the time of writing benchmarks show a reduction from 9seconds to 3 seconds by doing so. */ - let html = content.body.innerHTML; - - replacements.forEach(replacement => { - html = html.replaceAll(replacement.pattern, replacement.replacement); - }); - - content.body.innerHTML = html; -}; diff --git a/docs/_utilities/scrolling-tables.cjs b/docs/_utilities/scrolling-tables.cjs deleted file mode 100644 index 148248dbe..000000000 --- a/docs/_utilities/scrolling-tables.cjs +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM. - * The same document will be returned with the appropriate DOM manipulations. - */ -module.exports = function (doc, options) { - const tables = [...doc.querySelectorAll('table')]; - - options = { - className: 'table-scroll', // the class name to add to the table's container - ...options - }; - - tables.forEach(table => { - const div = doc.createElement('div'); - div.classList.add(options.className); - table.insertAdjacentElement('beforebegin', div); - div.append(table); - }); - - return doc; -}; diff --git a/docs/_utilities/strings.cjs b/docs/_utilities/strings.cjs deleted file mode 100644 index 6831d66d9..000000000 --- a/docs/_utilities/strings.cjs +++ /dev/null @@ -1,16 +0,0 @@ -const slugify = require('slugify'); - -/** Creates a slug from an arbitrary string of text. */ -module.exports.createSlug = function (text) { - return slugify(String(text), { - remove: /[^\w|\s]/g, - lower: true - }); -}; - -/** Determines whether or not a link is external. */ -module.exports.isExternalLink = function (link) { - // We use the "internal" hostname when initializing JSDOM so we know that those are local links - if (!link.hostname || link.hostname === 'internal') return false; - return true; -}; diff --git a/docs/_utilities/table-of-contents.cjs b/docs/_utilities/table-of-contents.cjs deleted file mode 100644 index 1ac04fd31..000000000 --- a/docs/_utilities/table-of-contents.cjs +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Generates an in-page table of contents based on headings. - */ -module.exports = function (doc, options) { - options = { - levels: ['h2'], // headings to include (they must have an id) - container: 'nav', // the container to append links to - listItem: true, // if true, links will be wrapped in
  • - within: 'body', // the element containing the headings to summarize - ...options - }; - - const container = doc.querySelector(options.container); - const within = doc.querySelector(options.within); - const headingSelector = options.levels.map(h => `${h}[id]`).join(', '); - - if (!container || !within) { - return doc; - } - - within.querySelectorAll(headingSelector).forEach(heading => { - const listItem = doc.createElement('li'); - const link = doc.createElement('a'); - const level = heading.tagName.slice(1); - - link.href = `#${heading.id}`; - link.textContent = heading.textContent; - - if (options.listItem) { - // List item + link - listItem.setAttribute('data-level', level); - listItem.append(link); - container.append(listItem); - } else { - // Link only - link.setAttribute('data-level', level); - container.append(link); - } - }); - - return doc; -}; diff --git a/docs/_utilities/typography.cjs b/docs/_utilities/typography.cjs deleted file mode 100644 index 53fe84b61..000000000 --- a/docs/_utilities/typography.cjs +++ /dev/null @@ -1,23 +0,0 @@ -const smartquotes = require('smartquotes'); - -smartquotes.replacements.push([/---/g, '\u2014']); // em dash -smartquotes.replacements.push([/--/g, '\u2013']); // en dash -smartquotes.replacements.push([/\.\.\./g, '\u2026']); // ellipsis -smartquotes.replacements.push([/\(c\)/gi, '\u00A9']); // copyright -smartquotes.replacements.push([/\(r\)/gi, '\u00AE']); // registered trademark -smartquotes.replacements.push([/\?!/g, '\u2048']); // ?! -smartquotes.replacements.push([/!!/g, '\u203C']); // !! -smartquotes.replacements.push([/\?\?/g, '\u2047']); // ?? -smartquotes.replacements.push([/([0-9]\s?)-(\s?[0-9])/g, '$1\u2013$2']); // number ranges use en dash - -/** - * Improves typography by adding smart quotes and similar corrections within the specified element(s). - * - * The provided doc should be a document object provided by JSDOM. The same document will be returned with the - * appropriate DOM manipulations. - */ -module.exports = function (doc, selector = 'body') { - const elements = [...doc.querySelectorAll(selector)]; - elements.forEach(el => smartquotes.element(el)); - return doc; -}; diff --git a/docs/assets/scripts/docs.js b/docs/assets/scripts/docs.js deleted file mode 100644 index 9c3ae3099..000000000 --- a/docs/assets/scripts/docs.js +++ /dev/null @@ -1,206 +0,0 @@ -// -// Sidebar -// -// When the sidebar is hidden, we apply the inert attribute to prevent focus from reaching it. Due to the many states -// the sidebar can have (e.g. static, hidden, expanded), we test for visibility by checking to see if it's placed -// offscreen or not. Then, on resize/transition we make sure to update the attribute accordingly. -// -(() => { - function getSidebar() { - return document.getElementById('sidebar'); - } - - function isSidebarOpen() { - return document.documentElement.classList.contains('sidebar-open'); - } - - function isSidebarVisible() { - return getSidebar().getBoundingClientRect().x >= 0; - } - - function toggleSidebar(force) { - const isOpen = typeof force === 'boolean' ? force : !isSidebarOpen(); - return document.documentElement.classList.toggle('sidebar-open', isOpen); - } - - function updateInert() { - getSidebar().inert = !isSidebarVisible(); - } - - // Toggle the menu - document.addEventListener('click', event => { - const menuToggle = event.target.closest('#menu-toggle'); - if (!menuToggle) return; - toggleSidebar(); - }); - - // Update the sidebar's inert state when the window resizes and when the sidebar transitions - window.addEventListener('resize', () => toggleSidebar(false)); - - document.addEventListener('transitionend', event => { - const sidebar = event.target.closest('#sidebar'); - if (!sidebar) return; - updateInert(); - }); - - // Close when a menu item is selected on mobile - document.addEventListener('click', event => { - const sidebar = event.target.closest('#sidebar'); - const link = event.target.closest('a'); - if (!sidebar || !link) return; - - if (isSidebarOpen()) { - toggleSidebar(); - } - }); - - // Close when open and escape is pressed - document.addEventListener('keydown', event => { - if (event.key === 'Escape' && isSidebarOpen()) { - event.stopImmediatePropagation(); - toggleSidebar(); - } - }); - - // Close when clicking outside of the sidebar - document.addEventListener('mousedown', event => { - if (isSidebarOpen() & !event.target?.closest('#sidebar, #menu-toggle')) { - event.stopImmediatePropagation(); - toggleSidebar(); - } - }); - - updateInert(); -})(); - -// -// Open details when printing -// -(() => { - const detailsOpenOnPrint = new Set(); - - window.addEventListener('beforeprint', () => { - detailsOpenOnPrint.clear(); - document.querySelectorAll('details').forEach(details => { - if (details.open) { - detailsOpenOnPrint.add(details); - } - details.open = true; - }); - }); - - window.addEventListener('afterprint', () => { - document.querySelectorAll('details').forEach(details => { - details.open = detailsOpenOnPrint.has(details); - }); - detailsOpenOnPrint.clear(); - }); -})(); - -// -// Smooth links -// -(() => { - document.addEventListener('click', event => { - const link = event.target.closest('a'); - const id = (link?.hash ?? '').substr(1); - const isFragment = link?.hasAttribute('href') && link?.getAttribute('href').startsWith('#'); - - if (!link || !isFragment || link.getAttribute('data-smooth-link') === 'false') { - return; - } - - // Scroll to the top - if (link.hash === '') { - event.preventDefault(); - window.scroll({ top: 0, behavior: 'smooth' }); - history.pushState(undefined, undefined, location.pathname); - } - - // Scroll to an id - if (id) { - const target = document.getElementById(id); - - if (target) { - event.preventDefault(); - window.scroll({ top: target.offsetTop, behavior: 'smooth' }); - history.pushState(undefined, undefined, `#${id}`); - } - } - }); -})(); - -// -// Table of Contents scrollspy -// -(() => { - // This will be stale if its not a function. - const getLinks = () => [...document.querySelectorAll('.content__toc a')]; - const linkTargets = new WeakMap(); - const visibleTargets = new WeakSet(); - const observer = new IntersectionObserver(handleIntersect, { rootMargin: '0px 0px' }); - let debounce; - - function handleIntersect(entries) { - entries.forEach(entry => { - // Remember which targets are visible - if (entry.isIntersecting) { - visibleTargets.add(entry.target); - } else { - visibleTargets.delete(entry.target); - } - }); - - updateActiveLinks(); - } - - function updateActiveLinks() { - const links = getLinks(); - // Find the first visible target and activate the respective link - links.find(link => { - const target = linkTargets.get(link); - - if (target && visibleTargets.has(target)) { - links.forEach(el => el.classList.toggle('active', el === link)); - return true; - } - - return false; - }); - } - - // Observe link targets - function observeLinks() { - getLinks().forEach(link => { - const hash = link.hash.slice(1); - const target = hash ? document.querySelector(`.content__body #${hash}`) : null; - - if (target) { - linkTargets.set(link, target); - observer.observe(target); - } - }); - } - - observeLinks(); - - document.addEventListener('turbo:load', updateActiveLinks); - document.addEventListener('turbo:load', observeLinks); -})(); - -// -// Show custom versions in the sidebar -// -(() => { - function updateVersion() { - const el = document.querySelector('.sidebar-version'); - if (!el) return; - - if (location.hostname === 'next.shoelace.style') el.textContent = 'Next'; - if (location.hostname === 'localhost') el.textContent = 'Development'; - } - - updateVersion(); - - document.addEventListener('turbo:load', updateVersion); -})(); diff --git a/docs/assets/scripts/search.js b/docs/assets/scripts/search.js deleted file mode 100644 index 7241e0bc3..000000000 --- a/docs/assets/scripts/search.js +++ /dev/null @@ -1,384 +0,0 @@ -(() => { - // Append the search dialog to the body - const siteSearch = document.createElement('div'); - const scrollbarWidth = Math.abs(window.innerWidth - document.documentElement.clientWidth); - - siteSearch.classList.add('search'); - siteSearch.innerHTML = ` -
    - -
    -
    -
    - - - -
    -
    -
    -
      -
      No matching pages
      -
      -
      - Navigate - Select - Esc Close -
      -
      -
      - `; - - const overlay = siteSearch.querySelector('.search__overlay'); - const dialog = siteSearch.querySelector('.search__dialog'); - const input = siteSearch.querySelector('.search__input'); - const clearButton = siteSearch.querySelector('.search__clear-button'); - const results = siteSearch.querySelector('.search__results'); - const version = document.documentElement.getAttribute('data-wa-version'); - const key = `search_${version}`; - const searchDebounce = 50; - const animationDuration = 150; - let isShowing = false; - let searchTimeout; - let searchIndex; - let map; - - const loadSearchIndex = new Promise(resolve => { - const cache = localStorage.getItem(key); - const wait = 'requestIdleCallback' in window ? requestIdleCallback : requestAnimationFrame; - - // Cleanup older search indices (everything before this version) - try { - const items = { ...localStorage }; - - Object.keys(items).forEach(k => { - if (key > k) { - localStorage.removeItem(k); - } - }); - } catch { - /* do nothing */ - } - - // Look for a cached index - try { - if (cache) { - const data = JSON.parse(cache); - - searchIndex = window.lunr.Index.load(data.searchIndex); - map = data.map; - - return resolve(); - } - } catch { - /* do nothing */ - } - - // Wait until idle to fetch the index - wait(() => { - fetch('/assets/search.json') - .then(res => res.json()) - .then(data => { - if (!window.lunr) { - console.error('The Lunr search client has not yet been loaded.'); - } - - searchIndex = window.lunr.Index.load(data.searchIndex); - map = data.map; - - // Cache the search index for this version - if (version) { - try { - localStorage.setItem(key, JSON.stringify(data)); - } catch (err) { - console.warn(`Unable to cache the search index: ${err}`); - } - } - - resolve(); - }); - }); - }); - - async function show() { - isShowing = true; - document.body.append(siteSearch); - document.body.classList.add('search-visible'); - document.body.style.setProperty('--docs-search-scroll-lock-size', `${scrollbarWidth}px`); - clearButton.hidden = true; - requestAnimationFrame(() => input.focus()); - updateResults(); - - dialog.showModal(); - - await Promise.all([ - dialog.animate( - [ - { opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' }, - { opacity: 1, transform: 'scale(1)', transformOrigin: 'top' } - ], - { duration: animationDuration } - ).finished, - overlay.animate([{ opacity: 0 }, { opacity: 1 }], { duration: animationDuration }).finished - ]); - - dialog.addEventListener('mousedown', handleMouseDown); - dialog.addEventListener('keydown', handleKeyDown); - } - - async function hide() { - isShowing = false; - - await Promise.all([ - dialog.animate( - [ - { opacity: 1, transform: 'scale(1)', transformOrigin: 'top' }, - { opacity: 0, transform: 'scale(.9)', transformOrigin: 'top' } - ], - { duration: animationDuration } - ).finished, - overlay.animate([{ opacity: 1 }, { opacity: 0 }], { duration: animationDuration }).finished - ]); - - dialog.close(); - - input.blur(); // otherwise Safari will scroll to the bottom of the page on close - input.value = ''; - document.body.classList.remove('search-visible'); - document.body.style.removeProperty('--docs-search-scroll-lock-size'); - siteSearch.remove(); - updateResults(); - - dialog.removeEventListener('mousedown', handleMouseDown); - dialog.removeEventListener('keydown', handleKeyDown); - } - - function handleInput() { - clearButton.hidden = input.value === ''; - - // Debounce search queries - clearTimeout(searchTimeout); - searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce); - } - - function handleClear() { - clearButton.hidden = true; - input.value = ''; - input.focus(); - updateResults(); - } - - function handleMouseDown(event) { - if (!event.target.closest('.search__content')) { - hide(); - } - } - - function handleKeyDown(event) { - // Close when pressing escape - if (event.key === 'Escape') { - event.preventDefault(); // prevent from closing immediately so it can animate - event.stopImmediatePropagation(); - hide(); - return; - } - - // Handle keyboard selections - if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) { - event.preventDefault(); - - const currentEl = results.querySelector('[data-selected="true"]'); - const items = [...results.querySelectorAll('li')]; - const index = items.indexOf(currentEl); - let nextEl; - - if (items.length === 0) { - return; - } - - switch (event.key) { - case 'ArrowUp': - nextEl = items[Math.max(0, index - 1)]; - break; - case 'ArrowDown': - nextEl = items[Math.min(items.length - 1, index + 1)]; - break; - case 'Home': - nextEl = items[0]; - break; - case 'End': - nextEl = items[items.length - 1]; - break; - case 'Enter': - currentEl?.querySelector('a')?.click(); - break; - } - - // Update the selected item - items.forEach(item => { - if (item === nextEl) { - input.setAttribute('aria-activedescendant', item.id); - item.setAttribute('data-selected', 'true'); - nextEl.scrollIntoView({ block: 'nearest' }); - } else { - item.setAttribute('data-selected', 'false'); - } - }); - } - } - - async function updateResults(query = '') { - try { - await loadSearchIndex; - - const hasQuery = query.length > 0; - const searchTerms = query - .split(' ') - .map((term, index, arr) => { - // Search API: https://lunrjs.com/guides/searching.html - if (index === arr.length - 1) { - // The last term is not mandatory and 1x fuzzy. We also duplicate it with a wildcard to match partial words - // as the user types. - return `${term}~1 ${term}*`; - } else { - // All other terms are mandatory and 1x fuzzy - return `+${term}~1`; - } - }) - .join(' '); - const matches = hasQuery ? searchIndex.search(searchTerms) : []; - const hasResults = hasQuery && matches.length > 0; - - siteSearch.classList.toggle('search--has-results', hasQuery && hasResults); - siteSearch.classList.toggle('search--no-results', hasQuery && !hasResults); - - input.setAttribute('aria-activedescendant', ''); - results.innerHTML = ''; - - matches.forEach((match, index) => { - const page = map[match.ref]; - const li = document.createElement('li'); - const a = document.createElement('a'); - const displayTitle = page.title ?? ''; - const displayDescription = page.description ?? ''; - const displayUrl = page.url.replace(/^\//, '').replace(/\/$/, ''); - let icon = 'file-text'; - - a.setAttribute('role', 'option'); - a.setAttribute('id', `search-result-item-${match.ref}`); - - if (page.url.includes('getting-started/')) { - icon = 'lightbulb'; - } - if (page.url.includes('resources/')) { - icon = 'book'; - } - if (page.url.includes('components/')) { - icon = 'puzzle-piece'; - } - if (page.url.includes('tokens/')) { - icon = 'swatchbook'; - } - if (page.url.includes('utilities/')) { - icon = 'wrench'; - } - if (page.url.includes('tutorials/')) { - icon = 'gamepad'; - } - - li.classList.add('search__result'); - li.setAttribute('role', 'option'); - li.setAttribute('id', `search-result-item-${match.ref}`); - li.setAttribute('data-selected', index === 0 ? 'true' : 'false'); - - a.href = page.url; - a.innerHTML = ` - -
      -
      -
      -
      -
      - `; - a.querySelector('.search__result-title').textContent = displayTitle; - a.querySelector('.search__result-description').textContent = displayDescription; - a.querySelector('.search__result-url').textContent = displayUrl; - - li.appendChild(a); - results.appendChild(li); - }); - } catch { - // Ignore query errors as the user types - } - } - - // Show the search dialog when clicking on data-plugin="search" - document.addEventListener('click', event => { - const searchButton = event.target.closest('[data-plugin="search"]'); - if (searchButton) { - show(); - } - }); - - // Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element - document.addEventListener('keydown', event => { - if ( - !isShowing && - (event.key === '/' || (event.key === 'k' && (event.metaKey || event.ctrlKey))) && - !event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase())) - ) { - event.preventDefault(); - show(); - } - }); - - // Purge cache when we press CMD+CTRL+R - document.addEventListener('keydown', event => { - if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'r') { - localStorage.clear(); - } - }); - - input.addEventListener('input', handleInput); - clearButton.addEventListener('click', handleClear); - - // Close when a result is selected - results.addEventListener('click', event => { - if (event.target.closest('a')) { - hide(); - } - }); - - // We're using Turbo, so when a user searches for something, visits a result, and presses the back button, the search - // UI will still be visible but not interactive. This removes the search UI when Turbo renders a page so they don't - // get trapped. - window.addEventListener('turbo:render', () => { - document.body.classList.remove('search-visible'); - document.querySelectorAll('.search__overlay, .search__dialog').forEach(el => el.remove()); - }); -})(); diff --git a/docs/assets/scripts/turbo.js b/docs/assets/scripts/turbo.js deleted file mode 100644 index 7075217f0..000000000 --- a/docs/assets/scripts/turbo.js +++ /dev/null @@ -1,29 +0,0 @@ -import * as Turbo from 'https://cdn.jsdelivr.net/npm/@hotwired/turbo@7.3.0/+esm'; - -(() => { - if (!window.scrollPositions) { - window.scrollPositions = {}; - } - - function preserveScroll() { - document.querySelectorAll('[data-preserve-scroll').forEach(element => { - scrollPositions[element.id] = element.scrollTop; - }); - } - - function restoreScroll(event) { - document.querySelectorAll('[data-preserve-scroll').forEach(element => { - element.scrollTop = scrollPositions[element.id]; - }); - - if (event.detail && event.detail.newBody) { - event.detail.newBody.querySelectorAll('[data-preserve-scroll').forEach(element => { - element.scrollTop = scrollPositions[element.id]; - }); - } - } - - window.addEventListener('turbo:before-cache', preserveScroll); - window.addEventListener('turbo:before-render', restoreScroll); - window.addEventListener('turbo:render', restoreScroll); -})(); diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs new file mode 100644 index 000000000..258affdbf --- /dev/null +++ b/docs/astro.config.mjs @@ -0,0 +1,142 @@ +import { defineConfig } from 'astro/config'; +import starlight from '@astrojs/starlight'; +import * as url from 'node:url'; +import * as path from 'node:path'; +// const __filename = url.fileURLToPath(import.meta.url); +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + +import FullReload from 'vite-plugin-full-reload'; + +import { customElementsManifest } from './src/js/cem.js'; +import { RemarkPluginFindAndReplace } from 'remark-plugin-find-and-replace'; +import rehypeExternalLinks from 'rehype-external-links'; +import remarkCodeHighlighter from './src/plugins/prism'; +import GithubAutolink from './src/plugins/github-autolink.ts'; + +const version = customElementsManifest().package.version; +const cdndir = 'cdn'; +const npmdir = 'dist'; + +function remarkFrontmatterPlugin() { + // All remark and rehype plugins return a separate function + return function (tree, file) { + const frontmatter = file.data.astro.frontmatter; + + frontmatter.npmdir = npmdir; + frontmatter.cdndir = cdndir; + frontmatter.version = version; + }; +} + +// https://astro.build/config +export default defineConfig({ + server: { + open: true, + port: 4000, + host: true + }, + vite: { + plugins: [ + FullReload([ + path.relative(__dirname, '../dist/custom-elements.json'), + path.relative(__dirname, './public/**/*.*') + ]) + ] + }, + outDir: '../_site', + site: 'https://shoelace.style', + markdown: { + syntaxHighlight: 'prism', + remarkPlugins: [ + remarkFrontmatterPlugin, + RemarkPluginFindAndReplace({ + replacements: [ + { pattern: '%VERSION%', replacement: version }, + { pattern: '%CDNDIR%', replacement: cdndir }, + { pattern: '%NPMDIR%', replacement: npmdir } + ] + }), + GithubAutolink, + remarkCodeHighlighter + ], + rehypePlugins: [ + () => + rehypeExternalLinks({ + rel: ['nofollow', 'noopener', 'noreferrer'], + target: ['_blank'], + properties: { + class: 'external-link' + } + }) + ] + }, + integrations: [ + starlight({ + expressiveCode: false, + title: 'Web Awesome', + social: { + github: 'https://github.com/shoelace-style/shoelace', + twitter: 'https://twitter.com/shoelace_style' + }, + sidebar: [ + { + label: 'Experimental', + autogenerate: { directory: 'experimental' } + }, + { + label: 'Getting Started', + autogenerate: { directory: 'getting-started' } + }, + { + label: 'Frameworks', + autogenerate: { directory: 'frameworks' } + }, + { + label: 'Resources', + autogenerate: { directory: 'resources' }, + items: [ + { + label: 'Community', + link: '/resources/community' + }, + { + label: 'Help & Support', + link: 'https://github.com/shoelace-style/shoelace/discussions' + }, + { + label: 'Accessibility', + link: '/resources/accessibility' + }, + { + label: 'Contributing', + link: '/resources/contributing' + }, + { + label: 'Changelog', + link: '/resources/changelog' + } + ] + }, + { + label: 'Components', + autogenerate: { directory: 'components' } + }, + { + label: 'Design Tokens', + autogenerate: { directory: 'tokens' } + }, + { + label: 'Tutorials', + autogenerate: { directory: 'tutorials' } + } + ], + // Component overrides + components: { + // Override the default `Head` component. + Head: './src/components/overrides/Head.astro', + TableOfContents: './src/components/overrides/TableOfContents.astro', + Search: './src/components/overrides/Search.astro' + } + }) + ] +}); diff --git a/docs/eleventy.config.cjs b/docs/eleventy.config.cjs deleted file mode 100644 index 6f4172e93..000000000 --- a/docs/eleventy.config.cjs +++ /dev/null @@ -1,246 +0,0 @@ -/* eslint-disable no-invalid-this */ -const fs = require('fs'); -const path = require('path'); -const lunr = require('lunr'); -const { capitalCase } = require('change-case'); -const { JSDOM } = require('jsdom'); -const { customElementsManifest, getAllComponents } = require('./_utilities/cem.cjs'); -const webAwesomeFlavoredMarkdown = require('./_utilities/markdown.cjs'); -const activeLinks = require('./_utilities/active-links.cjs'); -const anchorHeadings = require('./_utilities/anchor-headings.cjs'); -const codePreviews = require('./_utilities/code-previews.cjs'); -const copyCodeButtons = require('./_utilities/copy-code-buttons.cjs'); -const externalLinks = require('./_utilities/external-links.cjs'); -const highlightCodeBlocks = require('./_utilities/highlight-code.cjs'); -const tableOfContents = require('./_utilities/table-of-contents.cjs'); -const prettier = require('./_utilities/prettier.cjs'); -const scrollingTables = require('./_utilities/scrolling-tables.cjs'); -const typography = require('./_utilities/typography.cjs'); -const replacer = require('./_utilities/replacer.cjs'); - -const assetsDir = 'assets'; -const cdndir = 'cdn'; -const npmdir = 'dist'; -const allComponents = getAllComponents(); -let hasBuiltSearchIndex = false; - -module.exports = function (eleventyConfig) { - // - // Global data - // - eleventyConfig.addGlobalData('baseUrl', 'https://shoelace.style/'); // the production URL - eleventyConfig.addGlobalData('layout', 'default'); // make 'default' the default layout - eleventyConfig.addGlobalData('toc', true); // enable the table of contents - eleventyConfig.addGlobalData('meta', { - title: 'Web Awesome', - description: 'A forward-thinking library of web components.', - image: 'images/og-image.png', - version: customElementsManifest.package.version, - components: allComponents, - cdndir, - npmdir - }); - - // - // Layout aliases - // - eleventyConfig.addLayoutAlias('default', 'default.njk'); - - // - // Copy assets - // - eleventyConfig.addPassthroughCopy(assetsDir); - eleventyConfig.setServerPassthroughCopyBehavior('passthrough'); // emulates passthrough copy during --serve - - // - // Functions - // - - // Generates a URL relative to the site's root - eleventyConfig.addNunjucksGlobal('rootUrl', (value = '', absolute = false) => { - value = path.join('/', value); - return absolute ? new URL(value, eleventyConfig.globalData.baseUrl).toString() : value; - }); - - // Generates a URL relative to the site's asset directory - eleventyConfig.addNunjucksGlobal('assetUrl', (value = '', absolute = false) => { - value = path.join(`/${assetsDir}`, value); - return absolute ? new URL(value, eleventyConfig.globalData.baseUrl).toString() : value; - }); - - // Fetches a specific component's metadata - eleventyConfig.addNunjucksGlobal('getComponent', tagName => { - const component = allComponents.find(c => c.tagName === tagName); - if (!component) { - throw new Error( - `Unable to find a component called "${tagName}". Make sure the file name is the same as the component's tag ` + - `name (minus the wa- prefix).` - ); - } - return component; - }); - - // - // Custom markdown syntaxes - // - eleventyConfig.setLibrary('md', webAwesomeFlavoredMarkdown); - - // - // Filters - // - eleventyConfig.addFilter('markdown', content => { - return webAwesomeFlavoredMarkdown.render(content); - }); - - eleventyConfig.addFilter('markdownInline', content => { - return webAwesomeFlavoredMarkdown.renderInline(content); - }); - - // Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited. - // With Prettier 3, this means a leading pipe will exist if the line wraps. - eleventyConfig.addFilter('trimPipes', content => { - return typeof content === 'string' ? content.replace(/^(\s|\|)/g, '').replace(/(\s|\|)$/g, '') : content; - }); - - eleventyConfig.addFilter('classNameToComponentName', className => { - let name = capitalCase(className.replace(/^Wa/, '')); - if (name === 'Qr Code') name = 'QR Code'; // manual override - return name; - }); - - eleventyConfig.addFilter('removeWaPrefix', tagName => { - return tagName.replace(/^wa-/, ''); - }); - - // - // Transforms - // - eleventyConfig.addTransform('html-transform', function (content) { - // Parse the template and get a Document object - const doc = new JSDOM(content, { - // We must set a default URL so links are parsed with a hostname. Let's use a bogus TLD so we can easily - // identify which ones are internal and which ones are external. - url: `https://internal/` - }).window.document; - - // DOM transforms - activeLinks(doc, { pathname: this.page.url }); - anchorHeadings(doc, { - within: '#content .content__body', - levels: ['h2', 'h3', 'h4', 'h5'] - }); - tableOfContents(doc, { - levels: ['h2', 'h3'], - container: '#content .content__toc > ul', - within: '#content .content__body' - }); - codePreviews(doc); - externalLinks(doc, { target: '_blank' }); - highlightCodeBlocks(doc); - scrollingTables(doc); - copyCodeButtons(doc); // must be after codePreviews + highlightCodeBlocks - typography(doc, '#content'); - - replacer(doc, [ - { pattern: '%VERSION%', replacement: customElementsManifest.package.version }, - { pattern: '%CDNDIR%', replacement: cdndir }, - { pattern: '%NPMDIR%', replacement: npmdir } - ]); - - // Serialize the Document object to an HTML string and prepend the doctype - content = `\n${doc.documentElement.outerHTML}`; - - // String transforms - content = prettier(content); - - return content; - }); - - // - // Build a search index - // - eleventyConfig.on('eleventy.after', ({ results }) => { - // We only want to build the search index on the first run so all pages get indexed. - if (hasBuiltSearchIndex) { - return; - } - - const map = {}; - const searchIndexFilename = path.join(eleventyConfig.dir.output, assetsDir, 'search.json'); - const lunrInput = path.resolve('../node_modules/lunr/lunr.min.js'); - const lunrOutput = path.join(eleventyConfig.dir.output, assetsDir, 'scripts/lunr.js'); - const searchIndex = lunr(function () { - // The search index uses these field names extensively, so shortening them can save some serious bytes. The - // initial index file went from 468 KB => 401 KB by using single-character names! - this.ref('id'); // id - this.field('t', { boost: 50 }); // title - this.field('h', { boost: 25 }); // headings - this.field('c'); // content - - results.forEach((result, index) => { - const url = path - .join('/', path.relative(eleventyConfig.dir.output, result.outputPath)) - .replace(/\\/g, '/') // convert backslashes to forward slashes - .replace(/\/index.html$/, '/'); // convert trailing /index.html to / - const doc = new JSDOM(result.content, { - // We must set a default URL so links are parsed with a hostname. Let's use a bogus TLD so we can easily - // identify which ones are internal and which ones are external. - url: `https://internal/` - }).window.document; - const content = doc.querySelector('#content'); - - // Get title and headings - const title = (doc.querySelector('title')?.textContent || path.basename(result.outputPath)).trim(); - const headings = [...content.querySelectorAll('h1, h2, h3, h4')] - .map(heading => heading.textContent) - .join(' ') - .replace(/\s+/g, ' ') - .trim(); - - // Remove code blocks and whitespace from content - [...content.querySelectorAll('code[class|=language]')].forEach(code => code.remove()); - const textContent = content.textContent.replace(/\s+/g, ' ').trim(); - - // Update the index and map - this.add({ id: index, t: title, h: headings, c: textContent }); - map[index] = { title, url }; - }); - }); - - // Copy the Lunr search client and write the index - fs.mkdirSync(path.dirname(lunrOutput), { recursive: true }); - fs.copyFileSync(lunrInput, lunrOutput); - fs.writeFileSync(searchIndexFilename, JSON.stringify({ searchIndex, map }), 'utf-8'); - - hasBuiltSearchIndex = true; - }); - - // - // Send a signal to stdout that let's the build know we've reached this point - // - eleventyConfig.on('eleventy.after', () => { - console.log('[eleventy.after]'); - }); - - // - // Dev server options (see https://www.11ty.dev/docs/dev-server/#options) - // - eleventyConfig.setServerOptions({ - domDiff: false, // disable dom diffing so custom elements don't break on reload, - port: 4000, // if port 4000 is taken, 11ty will use the next one available - watch: ['cdn/**/*'] // additional files to watch that will trigger server updates (array of paths or globs) - }); - - // - // 11ty config - // - return { - dir: { - input: 'pages', - output: '../_site', - includes: '../_includes' // resolved relative to the input dir - }, - markdownTemplateEngine: 'njk', // use Nunjucks instead of Liquid for markdown files - templateEngineOverride: ['njk'] // just Nunjucks and then markdown - }; -}; diff --git a/docs/pages/404.md b/docs/pages/404.md deleted file mode 100644 index 085c8d42a..000000000 --- a/docs/pages/404.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -meta: - title: Page Not Found - description: "The page you were looking for couldn't be found." -permalink: 404.html -toc: false ---- - -
      - -# Page Not Found - -![A UFO takes one of the little worker monsters](/assets/images/undraw-taken.svg) - -The page you were looking for couldn't be found. - -Press [[/]] to search, or [head back to the homepage](/). - -
      diff --git a/docs/assets/examples/carousel/field.jpg b/docs/public/assets/examples/carousel/field.jpg similarity index 100% rename from docs/assets/examples/carousel/field.jpg rename to docs/public/assets/examples/carousel/field.jpg diff --git a/docs/assets/examples/carousel/mountains.jpg b/docs/public/assets/examples/carousel/mountains.jpg similarity index 100% rename from docs/assets/examples/carousel/mountains.jpg rename to docs/public/assets/examples/carousel/mountains.jpg diff --git a/docs/assets/examples/carousel/sunset.jpg b/docs/public/assets/examples/carousel/sunset.jpg similarity index 100% rename from docs/assets/examples/carousel/sunset.jpg rename to docs/public/assets/examples/carousel/sunset.jpg diff --git a/docs/assets/examples/carousel/valley.jpg b/docs/public/assets/examples/carousel/valley.jpg similarity index 100% rename from docs/assets/examples/carousel/valley.jpg rename to docs/public/assets/examples/carousel/valley.jpg diff --git a/docs/assets/examples/carousel/waterfall.jpg b/docs/public/assets/examples/carousel/waterfall.jpg similarity index 100% rename from docs/assets/examples/carousel/waterfall.jpg rename to docs/public/assets/examples/carousel/waterfall.jpg diff --git a/docs/assets/examples/include.html b/docs/public/assets/examples/include.html similarity index 100% rename from docs/assets/examples/include.html rename to docs/public/assets/examples/include.html diff --git a/docs/assets/images/awesome.svg b/docs/public/assets/images/awesome.svg similarity index 100% rename from docs/assets/images/awesome.svg rename to docs/public/assets/images/awesome.svg diff --git a/docs/assets/images/chrome.png b/docs/public/assets/images/chrome.png similarity index 100% rename from docs/assets/images/chrome.png rename to docs/public/assets/images/chrome.png diff --git a/docs/assets/images/edge.png b/docs/public/assets/images/edge.png similarity index 100% rename from docs/assets/images/edge.png rename to docs/public/assets/images/edge.png diff --git a/docs/assets/images/firefox.png b/docs/public/assets/images/firefox.png similarity index 100% rename from docs/assets/images/firefox.png rename to docs/public/assets/images/firefox.png diff --git a/docs/assets/images/gitpod.svg b/docs/public/assets/images/gitpod.svg similarity index 100% rename from docs/assets/images/gitpod.svg rename to docs/public/assets/images/gitpod.svg diff --git a/docs/public/assets/images/houston.webp b/docs/public/assets/images/houston.webp new file mode 100644 index 000000000..930c16497 Binary files /dev/null and b/docs/public/assets/images/houston.webp differ diff --git a/docs/assets/images/logo.svg b/docs/public/assets/images/logo.svg similarity index 100% rename from docs/assets/images/logo.svg rename to docs/public/assets/images/logo.svg diff --git a/docs/assets/images/og-image.png b/docs/public/assets/images/og-image.png similarity index 100% rename from docs/assets/images/og-image.png rename to docs/public/assets/images/og-image.png diff --git a/docs/assets/images/opera.png b/docs/public/assets/images/opera.png similarity index 100% rename from docs/assets/images/opera.png rename to docs/public/assets/images/opera.png diff --git a/docs/assets/images/safari.png b/docs/public/assets/images/safari.png similarity index 100% rename from docs/assets/images/safari.png rename to docs/public/assets/images/safari.png diff --git a/docs/assets/images/shoe.svg b/docs/public/assets/images/shoe.svg similarity index 100% rename from docs/assets/images/shoe.svg rename to docs/public/assets/images/shoe.svg diff --git a/docs/public/assets/images/sprite.svg b/docs/public/assets/images/sprite.svg new file mode 100644 index 000000000..217fb532c --- /dev/null +++ b/docs/public/assets/images/sprite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/assets/images/tie.webp b/docs/public/assets/images/tie.webp similarity index 100% rename from docs/assets/images/tie.webp rename to docs/public/assets/images/tie.webp diff --git a/docs/assets/images/touch-icon.png b/docs/public/assets/images/touch-icon.png similarity index 100% rename from docs/assets/images/touch-icon.png rename to docs/public/assets/images/touch-icon.png diff --git a/docs/assets/images/twitter-card.png b/docs/public/assets/images/twitter-card.png similarity index 100% rename from docs/assets/images/twitter-card.png rename to docs/public/assets/images/twitter-card.png diff --git a/docs/assets/images/undraw-content-team.svg b/docs/public/assets/images/undraw-content-team.svg similarity index 100% rename from docs/assets/images/undraw-content-team.svg rename to docs/public/assets/images/undraw-content-team.svg diff --git a/docs/assets/images/undraw-not-found.svg b/docs/public/assets/images/undraw-not-found.svg similarity index 100% rename from docs/assets/images/undraw-not-found.svg rename to docs/public/assets/images/undraw-not-found.svg diff --git a/docs/assets/images/undraw-taken.svg b/docs/public/assets/images/undraw-taken.svg similarity index 100% rename from docs/assets/images/undraw-taken.svg rename to docs/public/assets/images/undraw-taken.svg diff --git a/docs/assets/images/walk.gif b/docs/public/assets/images/walk.gif similarity index 100% rename from docs/assets/images/walk.gif rename to docs/public/assets/images/walk.gif diff --git a/docs/assets/images/wordmark.svg b/docs/public/assets/images/wordmark.svg similarity index 100% rename from docs/assets/images/wordmark.svg rename to docs/public/assets/images/wordmark.svg diff --git a/docs/assets/images/favicon.svg b/docs/public/favicon.svg similarity index 100% rename from docs/assets/images/favicon.svg rename to docs/public/favicon.svg diff --git a/docs/src/assets/houston.webp b/docs/src/assets/houston.webp new file mode 100644 index 000000000..930c16497 Binary files /dev/null and b/docs/src/assets/houston.webp differ diff --git a/docs/src/components/Docs.astro b/docs/src/components/Docs.astro new file mode 100644 index 000000000..3a5f43756 --- /dev/null +++ b/docs/src/components/Docs.astro @@ -0,0 +1,125 @@ +--- +--- + + diff --git a/docs/_includes/logo.njk b/docs/src/components/Logo.astro similarity index 99% rename from docs/_includes/logo.njk rename to docs/src/components/Logo.astro index a4d891f64..d0fd4be1b 100644 --- a/docs/_includes/logo.njk +++ b/docs/src/components/Logo.astro @@ -1 +1,4 @@ +--- +--- + diff --git a/docs/src/components/Search.astro b/docs/src/components/Search.astro new file mode 100644 index 000000000..4a36d9524 --- /dev/null +++ b/docs/src/components/Search.astro @@ -0,0 +1,389 @@ +--- +--- + + diff --git a/docs/src/components/Turbo.astro b/docs/src/components/Turbo.astro new file mode 100644 index 000000000..293a96bf7 --- /dev/null +++ b/docs/src/components/Turbo.astro @@ -0,0 +1,36 @@ +--- +--- + + diff --git a/docs/src/components/overrides/Head.astro b/docs/src/components/overrides/Head.astro new file mode 100644 index 000000000..756537a3a --- /dev/null +++ b/docs/src/components/overrides/Head.astro @@ -0,0 +1,55 @@ +--- +import type { Props } from '@astrojs/starlight/props'; +import { default as AstroHead } from '@astrojs/starlight/components/Head.astro'; +import Turbo from "../Turbo.astro" +import Docs from "../Docs.astro" +import Search from "../Search.astro" + +import '../../styles/global.css' +import '../../styles/syntax-highlight.css' +import '../../styles/code-previews.css' +import { customElementsManifest } from '../../js/cem'; + +const version = customElementsManifest().package.version +--- + + + + + + +<> + + + {/* */} + + + + + + + + + + + + diff --git a/docs/src/components/overrides/Search.astro b/docs/src/components/overrides/Search.astro new file mode 100644 index 000000000..0e3a157cb --- /dev/null +++ b/docs/src/components/overrides/Search.astro @@ -0,0 +1,436 @@ +--- +import '@pagefind/default-ui/css/ui.css'; +import { Icon } from '@astrojs/starlight/components'; +import type { Props } from '@astrojs/starlight/props'; + +const { labels } = Astro.props; + +const pagefindTranslations = { + placeholder: labels['search.label'], + ...Object.fromEntries( + Object.entries(labels) + .filter(([key]) => key.startsWith('pagefind.')) + .map(([key, value]) => [key.replace('pagefind.', ''), value]) + ), +}; + +--- + + + + + +
      + { + /* TODO: Make the layout of this button flexible to accommodate different word lengths. Currently hard-coded for English: ā€œCancelā€ */ + } + + { +
      + + } +
      +
      +
      + + + + + + diff --git a/docs/src/components/overrides/TableOfContents.astro b/docs/src/components/overrides/TableOfContents.astro new file mode 100644 index 000000000..25abebbb7 --- /dev/null +++ b/docs/src/components/overrides/TableOfContents.astro @@ -0,0 +1,63 @@ +--- +import { default as StarlightTOC } from '@astrojs/starlight/components/TableOfContents.astro'; +import type { Props } from "@astrojs/starlight/props" +const { labels, toc, slug, entry, id } = Astro.props; + +import { getComponentFromFileName } from "../../js/cem.js" + +if (slug.includes("components/")) { + const component = getComponentFromFileName(slug + ".md") + + const { + hasSlots, + hasProperties, + hasEvents, + hasMethods, + hasCssProperties, + hasCssParts, + hasAnimations, + hasDependencies, + } = component + + toc.items.push({ + text: "Importing", + slug: "importing", + depth: 0, + children: [] + }) + + const strToText = { + CssProperties: "Custom Properties", + CssParts: "Parts", + } + + const strToId = { + CssProperties: "custom-properties", + CssParts: "parts", + } + + ;[ + "Slots", + "Properties", + "Events", + "Methods", + "CssProperties", + "CssParts", + "Animations", + "Dependencies", + ].forEach((str) => { + if (component[`has${str}`]) { + toc.items.push({ + text: strToText[str] || str, + slug: strToId[str] || str.toLowerCase(), + depth: 0, + children: [] + }) + } + }) + +} +--- + + + diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts new file mode 100644 index 000000000..95b5451cb --- /dev/null +++ b/docs/src/content/config.ts @@ -0,0 +1,16 @@ +import { defineCollection, z } from 'astro:content'; +import { docsSchema, i18nSchema } from '@astrojs/starlight/schema'; + +export const collections = { + docs: defineCollection({ + schema: docsSchema({ + extend: z.object({ + // Add a new field to the schema. + category: z + .enum(['components', 'experimental', 'frameworks', 'getting-started', 'resources', 'tokens', 'tutorials']) + .optional() + }) + }) + }), + i18n: defineCollection({ type: 'data', schema: i18nSchema() }) +}; diff --git a/docs/src/content/docs/404.md b/docs/src/content/docs/404.md new file mode 100644 index 000000000..70643dd4b --- /dev/null +++ b/docs/src/content/docs/404.md @@ -0,0 +1,28 @@ +--- +title: Page Not Found +description: "The page you were looking for couldn't be found." +tableOfContents: false +pageTitle: false +--- + +
      + +# Page Not Found + +![A UFO takes one of the little worker monsters](/assets/images/undraw-taken.svg) + +The page you were looking for couldn't be found. + +Press / to search, or [head back to the homepage](/). + +
      + + diff --git a/docs/pages/components/alert.md b/docs/src/content/docs/components/alert.md similarity index 98% rename from docs/pages/components/alert.md rename to docs/src/content/docs/components/alert.md index bd67a079e..41cb4acb0 100644 --- a/docs/pages/components/alert.md +++ b/docs/src/content/docs/components/alert.md @@ -1,8 +1,7 @@ --- -meta: - title: Alert - description: Alerts are used to display important messages inline or as toast notifications. -layout: component +title: Alert +description: Alerts are used to display important messages inline or as toast notifications. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -24,7 +23,7 @@ const App = () => ( ); ``` -:::warning +:::caution Alerts will not be visible if the `open` attribute is not present. ::: diff --git a/docs/pages/components/animated-image.md b/docs/src/content/docs/components/animated-image.md similarity index 94% rename from docs/pages/components/animated-image.md rename to docs/src/content/docs/components/animated-image.md index cc64b8dbf..c7b8381cf 100644 --- a/docs/pages/components/animated-image.md +++ b/docs/src/content/docs/components/animated-image.md @@ -1,8 +1,7 @@ --- -meta: - title: Animated Image - description: A component for displaying animated GIFs and WEBPs that play and pause on interaction. -layout: component +title: Animated Image +description: A component for displaying animated GIFs and WEBPs that play and pause on interaction. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -61,8 +60,6 @@ To set a custom size, apply a width and/or height to the host element. ``` -{% raw %} - ```jsx:react import WaAnimatedImage from '@shoelace-style/shoelace/dist/react/animated-image'; @@ -75,8 +72,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Customizing the Control Box You can change the appearance and location of the control box by targeting the `control-box` part in your styles. diff --git a/docs/pages/components/animation.md b/docs/src/content/docs/components/animation.md similarity index 97% rename from docs/pages/components/animation.md rename to docs/src/content/docs/components/animation.md index e5dc61b24..66d109a91 100644 --- a/docs/pages/components/animation.md +++ b/docs/src/content/docs/components/animation.md @@ -1,8 +1,7 @@ --- -meta: - title: Animation - description: Animate elements declaratively with nearly 100 baked-in presets, or roll your own with custom keyframes. -layout: component +title: Animation +description: Animate elements declaratively with nearly 100 baked-in presets, or roll your own with custom keyframes. +layout: ../../../layouts/ComponentLayout.astro --- To animate an element, wrap it in `` and set an animation `name`. The animation will not start until you add the `play` attribute. Refer to the [properties table](#properties) for a list of all animation options. @@ -80,7 +79,8 @@ This example demonstrates all of the baked-in animations and easings. Animations
      - + +
      @@ -134,6 +134,10 @@ This example demonstrates all of the baked-in animations and easings. Animations ``` +```jsx:react + +``` + ### Using Intersection Observer Use an [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to control the animation when an element enters or exits the viewport. For example, scroll the box below in and out of your screen. The animation stops when the box exits the viewport and restarts each time it enters the viewport. diff --git a/docs/pages/components/avatar.md b/docs/src/content/docs/components/avatar.md similarity index 98% rename from docs/pages/components/avatar.md rename to docs/src/content/docs/components/avatar.md index f02fefc7d..54adf623f 100644 --- a/docs/pages/components/avatar.md +++ b/docs/src/content/docs/components/avatar.md @@ -1,8 +1,7 @@ --- -meta: - title: Avatar - description: Avatars are used to represent a person or object. -layout: component +title: Avatar +description: Avatars are used to represent a person or object. +layout: ../../../layouts/ComponentLayout.astro --- By default, a generic icon will be shown. You can personalize avatars by adding custom icons, initials, and images. You should always provide a `label` for assistive devices. diff --git a/docs/pages/components/badge.md b/docs/src/content/docs/components/badge.md similarity index 96% rename from docs/pages/components/badge.md rename to docs/src/content/docs/components/badge.md index 37c04deaf..fde18079d 100644 --- a/docs/pages/components/badge.md +++ b/docs/src/content/docs/components/badge.md @@ -1,8 +1,7 @@ --- -meta: - title: Badge - description: Badges are used to draw attention and display statuses or counts. -layout: component +title: Badge +description: Badges are used to draw attention and display statuses or counts. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -154,8 +153,6 @@ One of the most common use cases for badges is attaching them to buttons. To mak ``` -{% raw %} - ```jsx:react import WaBadge from '@shoelace-style/shoelace/dist/react/badge'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -184,8 +181,6 @@ const App = () => ( ); ``` -{% endraw %} - ### With Menu Items When including badges in menu items, use the `suffix` slot to make sure they're aligned correctly. @@ -198,8 +193,6 @@ When including badges in menu items, use the `suffix` slot to make sure they're ``` -{% raw %} - ```jsx:react import WaBadge from '@shoelace-style/shoelace/dist/react/badge'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -227,5 +220,3 @@ const App = () => ( ); ``` - -{% endraw %} diff --git a/docs/pages/components/breadcrumb-item.md b/docs/src/content/docs/components/breadcrumb-item.md similarity index 85% rename from docs/pages/components/breadcrumb-item.md rename to docs/src/content/docs/components/breadcrumb-item.md index 733d129ce..c86347171 100644 --- a/docs/pages/components/breadcrumb-item.md +++ b/docs/src/content/docs/components/breadcrumb-item.md @@ -1,8 +1,7 @@ --- -meta: - title: Breadcrumb Item - description: Breadcrumb Items are used inside breadcrumbs to represent different links. -layout: component +title: Breadcrumb Item +description: Breadcrumb Items are used inside breadcrumbs to represent different links. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/breadcrumb.md b/docs/src/content/docs/components/breadcrumb.md similarity index 97% rename from docs/pages/components/breadcrumb.md rename to docs/src/content/docs/components/breadcrumb.md index c897b5524..de36a25d8 100644 --- a/docs/pages/components/breadcrumb.md +++ b/docs/src/content/docs/components/breadcrumb.md @@ -1,8 +1,7 @@ --- -meta: - title: Breadcrumb - description: Breadcrumbs provide a group of links so users can easily navigate a website's hierarchy. -layout: component +title: Breadcrumb +description: Breadcrumbs provide a group of links so users can easily navigate a website's hierarchy. +layout: ../../../layouts/ComponentLayout.astro --- Breadcrumbs are usually placed before a page's main content with the current page shown last to indicate the user's position in the navigation. diff --git a/docs/pages/components/button-group.md b/docs/src/content/docs/components/button-group.md similarity index 98% rename from docs/pages/components/button-group.md rename to docs/src/content/docs/components/button-group.md index 15976ca1d..8303fdda9 100644 --- a/docs/pages/components/button-group.md +++ b/docs/src/content/docs/components/button-group.md @@ -1,8 +1,7 @@ --- -meta: - title: Button Group - description: Button groups can be used to group related buttons into sections. -layout: component +title: Button Group +description: Button groups can be used to group related buttons into sections. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/button.md b/docs/src/content/docs/components/button.md similarity index 98% rename from docs/pages/components/button.md rename to docs/src/content/docs/components/button.md index beb0c413b..699285f20 100644 --- a/docs/pages/components/button.md +++ b/docs/src/content/docs/components/button.md @@ -1,8 +1,7 @@ --- -meta: - title: Button - description: Buttons represent actions that are available to the user. -layout: component +title: Button +description: Buttons represent actions that are available to the user. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -201,8 +200,6 @@ As expected, buttons can be given a custom width by setting the `width` attribut Large ``` -{% raw %} - ```jsx:react import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -221,8 +218,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Prefix and Suffix Icons Use the `prefix` and `suffix` slots to add icons. diff --git a/docs/pages/components/card.md b/docs/src/content/docs/components/card.md similarity index 97% rename from docs/pages/components/card.md rename to docs/src/content/docs/components/card.md index 56c67c1e8..9a2b95e9c 100644 --- a/docs/pages/components/card.md +++ b/docs/src/content/docs/components/card.md @@ -1,8 +1,7 @@ --- -meta: - title: Card - description: Cards can be used to group related subjects in a container. -layout: component +title: Card +description: Cards can be used to group related subjects in a container. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/carousel-item.md b/docs/src/content/docs/components/carousel-item.md similarity index 94% rename from docs/pages/components/carousel-item.md rename to docs/src/content/docs/components/carousel-item.md index 6fa5d36f5..05ea36154 100644 --- a/docs/pages/components/carousel-item.md +++ b/docs/src/content/docs/components/carousel-item.md @@ -1,8 +1,7 @@ --- -meta: - title: Carousel Item - description: A carousel item represent a slide within a carousel. -layout: component +title: Carousel Item +description: A carousel item represent a slide within a carousel. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/carousel.md b/docs/src/content/docs/components/carousel.md similarity index 99% rename from docs/pages/components/carousel.md rename to docs/src/content/docs/components/carousel.md index 6141cafe1..b8144306a 100644 --- a/docs/pages/components/carousel.md +++ b/docs/src/content/docs/components/carousel.md @@ -1,8 +1,7 @@ --- -meta: - title: Carousel - description: Carousels display an arbitrary number of content slides along a horizontal or vertical axis. -layout: component +title: Carousel +description: Carousels display an arbitrary number of content slides along a horizontal or vertical axis. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -527,8 +526,6 @@ The `slides-per-page` attribute makes it possible to display multiple slides at ``` -{% raw %} - ```jsx:react import WaCarousel from '@shoelace-style/shoelace/dist/react/carousel'; import WaCarouselItem from '@shoelace-style/shoelace/dist/react/carousel-item'; @@ -545,8 +542,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Adding and Removing Slides The content of the carousel can be changed by adding or removing carousel items. The carousel will update itself automatically. @@ -619,8 +614,6 @@ The content of the carousel can be changed by adding or removing carousel items. ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaCarousel from '@shoelace-style/shoelace/dist/react/carousel'; @@ -680,8 +673,6 @@ const App = () => { }; ``` -{% endraw %} - ### Vertical Scrolling Setting the `orientation` attribute to `vertical` will render the carousel in a vertical layout. If the content of your slides vary in height, you will need to set amn explicit `height` or `max-height` on the carousel using CSS. @@ -859,8 +850,6 @@ Use the `--aspect-ratio` custom property to customize the size of the carousel's ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaCarousel from '@shoelace-style/shoelace/dist/react/carousel'; @@ -926,8 +915,6 @@ const App = () => { }; ``` -{% endraw %} - ### Scroll Hint Use the `--scroll-hint` custom property to add inline padding in horizontal carousels and block padding in vertical carousels. This will make the closest slides slightly visible, hinting that there are more items in the carousel. @@ -967,8 +954,6 @@ Use the `--scroll-hint` custom property to add inline padding in horizontal caro ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaCarousel from '@shoelace-style/shoelace/dist/react/carousel'; @@ -1014,8 +999,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Gallery Example The carousel has a robust API that makes it possible to extend and customize. This example syncs the active slide with a set of thumbnails, effectively creating a gallery-style carousel. diff --git a/docs/pages/components/checkbox.md b/docs/src/content/docs/components/checkbox.md similarity index 96% rename from docs/pages/components/checkbox.md rename to docs/src/content/docs/components/checkbox.md index 75239f1bb..425f27305 100644 --- a/docs/pages/components/checkbox.md +++ b/docs/src/content/docs/components/checkbox.md @@ -1,8 +1,7 @@ --- -meta: - title: Checkbox - description: Checkboxes allow the user to toggle an option on or off. -layout: component +title: Checkbox +description: Checkboxes allow the user to toggle an option on or off. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -125,8 +124,6 @@ Use the `setCustomValidity()` method to set a custom validation message. This wi ``` -{% raw %} - ```jsx:react import { useEffect, useRef } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -162,5 +159,3 @@ const App = () => { ); }; ``` - -{% endraw %} diff --git a/docs/pages/components/color-picker.md b/docs/src/content/docs/components/color-picker.md similarity index 97% rename from docs/pages/components/color-picker.md rename to docs/src/content/docs/components/color-picker.md index 3dd36d170..4ea60cfba 100644 --- a/docs/pages/components/color-picker.md +++ b/docs/src/content/docs/components/color-picker.md @@ -1,8 +1,7 @@ --- -meta: - title: Color Picker - description: Color pickers allow the user to select a color. -layout: component +title: Color Picker +description: Color pickers allow the user to select a color. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/copy-button.md b/docs/src/content/docs/components/copy-button.md similarity index 98% rename from docs/pages/components/copy-button.md rename to docs/src/content/docs/components/copy-button.md index 60f4c9e4f..352d7492d 100644 --- a/docs/pages/components/copy-button.md +++ b/docs/src/content/docs/components/copy-button.md @@ -1,8 +1,7 @@ --- -meta: - title: Copy Button - description: Copies data to the clipboard when the user clicks the button. -layout: component +title: Copy Button +description: Copies data to the clipboard when the user clicks the button. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/details.md b/docs/src/content/docs/components/details.md similarity index 97% rename from docs/pages/components/details.md rename to docs/src/content/docs/components/details.md index 429e5dbca..7e03bad70 100644 --- a/docs/pages/components/details.md +++ b/docs/src/content/docs/components/details.md @@ -1,8 +1,7 @@ --- -meta: - title: Details - description: Details show a brief summary and expand to show additional content. -layout: component +title: Details +description: Details show a brief summary and expand to show additional content. +layout: ../../../layouts/ComponentLayout.astro --- diff --git a/docs/pages/components/dialog.md b/docs/src/content/docs/components/dialog.md similarity index 98% rename from docs/pages/components/dialog.md rename to docs/src/content/docs/components/dialog.md index 159a8040b..d31dee2cd 100644 --- a/docs/pages/components/dialog.md +++ b/docs/src/content/docs/components/dialog.md @@ -1,8 +1,7 @@ --- -meta: - title: Dialog - description: 'Dialogs, sometimes called "modals", appear above the page and require the user''s immediate attention.' -layout: component +title: Dialog +description: 'Dialogs, sometimes called "modals", appear above the page and require the user''s immediate attention.' +layout: ../../../layouts/ComponentLayout.astro --- @@ -72,8 +71,6 @@ Use the `--width` custom property to set the dialog's width. ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -97,8 +94,6 @@ const App = () => { }; ``` -{% endraw %} - ### Scrolling By design, a dialog's height will never exceed that of the viewport. As such, dialogs will not scroll with the page ensuring the header and footer are always accessible to the user. @@ -123,8 +118,6 @@ By design, a dialog's height will never exceed that of the viewport. As such, di ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -157,8 +150,6 @@ const App = () => { }; ``` -{% endraw %} - ### Header Actions The header shows a functional close button by default. You can use the `header-actions` slot to add additional [icon buttons](/components/icon-button) if needed. diff --git a/docs/pages/components/divider.md b/docs/src/content/docs/components/divider.md similarity index 86% rename from docs/pages/components/divider.md rename to docs/src/content/docs/components/divider.md index 36344f917..caac024e3 100644 --- a/docs/pages/components/divider.md +++ b/docs/src/content/docs/components/divider.md @@ -1,8 +1,7 @@ --- -meta: - title: Divider - description: Dividers are used to visually separate or group elements. -layout: component +title: Divider +description: Dividers are used to visually separate or group elements. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -25,16 +24,12 @@ Use the `--width` custom property to change the width of the divider. ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; const App = () => ; ``` -{% endraw %} - ### Color Use the `--color` custom property to change the color of the divider. @@ -43,16 +38,12 @@ Use the `--color` custom property to change the color of the divider. ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; const App = () => ; ``` -{% endraw %} - ### Spacing Use the `--spacing` custom property to change the amount of space between the divider and it's neighboring elements. @@ -65,22 +56,6 @@ Use the `--spacing` custom property to change the amount of space between the di ``` -{% raw %} - -```jsx:react -import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; - -const App = () => ( - <> - Above - - Below - -); -``` - -{% endraw %} - ### Vertical Add the `vertical` attribute to draw the divider in a vertical orientation. The divider will span the full height of its container. Vertical dividers work especially well inside of a flex container. @@ -95,8 +70,6 @@ Add the `vertical` attribute to draw the divider in a vertical orientation. The ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; @@ -117,8 +90,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Menu Dividers Use dividers in [menus](/components/menu) to visually group menu items. @@ -135,8 +106,6 @@ Use dividers in [menus](/components/menu) to visually group menu items. ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; @@ -154,5 +123,3 @@ const App = () => ( ); ``` - -{% endraw %} diff --git a/docs/pages/components/drawer.md b/docs/src/content/docs/components/drawer.md similarity index 98% rename from docs/pages/components/drawer.md rename to docs/src/content/docs/components/drawer.md index 40a83ef5c..07f20b922 100644 --- a/docs/pages/components/drawer.md +++ b/docs/src/content/docs/components/drawer.md @@ -1,8 +1,7 @@ --- -meta: - title: Drawer - description: Drawers slide in from a container to expose additional options and information. -layout: component +title: Drawer +description: Drawers slide in from a container to expose additional options and information. +layout: ../../../layouts/ComponentLayout.astro --- @@ -215,8 +214,6 @@ Unlike normal drawers, contained drawers are not modal. This means they do not s ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -259,8 +256,6 @@ const App = () => { }; ``` -{% endraw %} - ### Custom Size Use the `--size` custom property to set the drawer's size. This will be applied to the drawer's width or height depending on its `placement`. @@ -283,8 +278,6 @@ Use the `--size` custom property to set the drawer's size. This will be applied ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -308,8 +301,6 @@ const App = () => { }; ``` -{% endraw %} - ### Scrolling By design, a drawer's height will never exceed 100% of its container. As such, drawers will not scroll with the page to ensure the header and footer are always accessible to the user. @@ -334,8 +325,6 @@ By design, a drawer's height will never exceed 100% of its container. As such, d ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -367,8 +356,6 @@ const App = () => { }; ``` -{% endraw %} - ### Header Actions The header shows a functional close button by default. You can use the `header-actions` slot to add additional [icon buttons](/components/icon-button) if needed. diff --git a/docs/pages/components/dropdown.md b/docs/src/content/docs/components/dropdown.md similarity index 98% rename from docs/pages/components/dropdown.md rename to docs/src/content/docs/components/dropdown.md index cc22b7a1e..107c44221 100644 --- a/docs/pages/components/dropdown.md +++ b/docs/src/content/docs/components/dropdown.md @@ -1,8 +1,7 @@ --- -meta: - title: Dropdown - description: 'Dropdowns expose additional content that "drops down" in a panel.' -layout: component +title: Dropdown +description: 'Dropdowns expose additional content that "drops down" in a panel.' +layout: ../../../layouts/ComponentLayout.astro --- Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it. @@ -396,7 +395,7 @@ const App = () => ( ); ``` -:::warning +:::caution As a UX best practice, avoid using more than one level of submenu when possible. ::: diff --git a/docs/pages/components/format-bytes.md b/docs/src/content/docs/components/format-bytes.md similarity index 96% rename from docs/pages/components/format-bytes.md rename to docs/src/content/docs/components/format-bytes.md index 8df80988c..bda552edb 100644 --- a/docs/pages/components/format-bytes.md +++ b/docs/src/content/docs/components/format-bytes.md @@ -1,8 +1,7 @@ --- -meta: - title: Format Bytes - description: Formats a number as a human readable bytes value. -layout: component +title: Format Bytes +description: Formats a number as a human readable bytes value. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -20,8 +19,6 @@ layout: component ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaButton from '@shoelace-style/shoelace/dist/react/button'; @@ -48,8 +45,6 @@ const App = () => { }; ``` -{% endraw %} - ## Examples ### Formatting Bytes diff --git a/docs/pages/components/format-date.md b/docs/src/content/docs/components/format-date.md similarity index 96% rename from docs/pages/components/format-date.md rename to docs/src/content/docs/components/format-date.md index fa701de87..d5b96f269 100644 --- a/docs/pages/components/format-date.md +++ b/docs/src/content/docs/components/format-date.md @@ -1,8 +1,7 @@ --- -meta: - title: Format Date - description: Formats a date/time using the specified locale and options. -layout: component +title: Format Date +description: Formats a date/time using the specified locale and options. +layout: ../../../layouts/ComponentLayout.astro --- Localization is handled by the browser's [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). No language packs are required. diff --git a/docs/pages/components/format-number.md b/docs/src/content/docs/components/format-number.md similarity index 96% rename from docs/pages/components/format-number.md rename to docs/src/content/docs/components/format-number.md index 570c003f4..8d854439d 100644 --- a/docs/pages/components/format-number.md +++ b/docs/src/content/docs/components/format-number.md @@ -1,8 +1,7 @@ --- -meta: - title: Format Number - description: Formats a number using the specified locale and options. -layout: component +title: Format Number +description: Formats a number using the specified locale and options. +layout: ../../../layouts/ComponentLayout.astro --- Localization is handled by the browser's [`Intl.NumberFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat). No language packs are required. @@ -23,8 +22,6 @@ Localization is handled by the browser's [`Intl.NumberFormat` API](https://devel ``` -{% raw %} - ```jsx:react import { useState } from 'react'; import WaFormatNumber from '@shoelace-style/shoelace/dist/react/format-number'; @@ -50,8 +47,6 @@ const App = () => { }; ``` -{% endraw %} - ## Examples ### Percentages diff --git a/docs/pages/components/icon-button.md b/docs/src/content/docs/components/icon-button.md similarity index 95% rename from docs/pages/components/icon-button.md rename to docs/src/content/docs/components/icon-button.md index 9106a5d4a..32de6b9db 100644 --- a/docs/pages/components/icon-button.md +++ b/docs/src/content/docs/components/icon-button.md @@ -1,8 +1,7 @@ --- -meta: - title: Icon Button - description: Icons buttons are simple, icon-only buttons that can be used for actions and in toolbars. -layout: component +title: Icon Button +description: Icons buttons are simple, icon-only buttons that can be used for actions and in toolbars. +layout: ../../../layouts/ComponentLayout.astro --- For a full list of icons that come bundled with Web Awesome, refer to the [icon component](/components/icon). @@ -29,8 +28,6 @@ Icon buttons inherit their parent element's `font-size`. ``` -{% raw %} - ```jsx:react import WaIconButton from '@shoelace-style/shoelace/dist/react/icon-button'; @@ -43,8 +40,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Colors Icon buttons are designed to have a uniform appearance, so their color is not inherited. However, you can still customize them by styling the `base` part. diff --git a/docs/pages/components/icon.md b/docs/src/content/docs/components/icon.md similarity index 99% rename from docs/pages/components/icon.md rename to docs/src/content/docs/components/icon.md index 5428e8c38..24e9f2dd2 100644 --- a/docs/pages/components/icon.md +++ b/docs/src/content/docs/components/icon.md @@ -1,8 +1,7 @@ --- -meta: - title: Icon - description: Icons are symbols that can be used to represent various options within an application. -layout: component +title: Icon +description: Icons are symbols that can be used to represent various options within an application. +layout: ../../../layouts/ComponentLayout.astro --- Web Awesome comes bundled with over 1,500 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. These icons are part of the `default` icon library. If you prefer, you can register [custom icon libraries](#icon-libraries) as well. @@ -55,8 +54,6 @@ Icons inherit their color from the current text color. Thus, you can set the `co ``` -{% raw %} - ```jsx:react import WaIcon from '@shoelace-style/shoelace/dist/react/icon'; @@ -90,8 +87,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Sizing Icons are sized relative to the current font size. To change their size, set the `font-size` property on the icon itself or on a parent element as shown below. @@ -117,8 +112,6 @@ Icons are sized relative to the current font size. To change their size, set the ``` -{% raw %} - ```jsx:react import WaIcon from '@shoelace-style/shoelace/dist/react/icon'; @@ -144,8 +137,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Labels For non-decorative icons, use the `label` attribute to announce it to assistive devices. @@ -168,16 +159,12 @@ Custom icons can be loaded individually with the `src` attribute. Only SVGs on a ``` -{% raw %} - ```jsx:react import WaIcon from '@shoelace-style/shoelace/dist/react/icon'; const App = () => ; ``` -{% endraw %} - ## Icon Libraries You can register additional icons to use with the `` component through icon libraries. Icon files can exist locally or on a CORS-enabled endpoint (e.g. a CDN). There is no limit to how many icon libraries you can register and there is no cost associated with registering them, as individual icons are only requested when they're used. @@ -630,9 +617,7 @@ As always, make sure to benchmark these changes. When using HTTP/2, it may in fa :::danger When using sprite sheets, the `wa-load` and `wa-error` events will not fire. -::: -:::danger For security reasons, browsers may apply the same-origin policy on `` elements located in the `` shadow DOM and may refuse to load a cross-origin URL. There is currently no defined way to set a cross-origin policy for `` elements. For this reason, sprite sheets should only be used if you're self-hosting them. ::: diff --git a/docs/pages/components/image-comparer.md b/docs/src/content/docs/components/image-comparer.md similarity index 94% rename from docs/pages/components/image-comparer.md rename to docs/src/content/docs/components/image-comparer.md index 339c4499c..ca2ada423 100644 --- a/docs/pages/components/image-comparer.md +++ b/docs/src/content/docs/components/image-comparer.md @@ -1,8 +1,7 @@ --- -meta: - title: Image Comparer - description: Compare visual differences between similar photos with a sliding panel. -layout: component +title: Image Comparer +description: Compare visual differences between similar photos with a sliding panel. +layout: ../../../layouts/ComponentLayout.astro --- For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.) diff --git a/docs/pages/components/include.md b/docs/src/content/docs/components/include.md similarity index 90% rename from docs/pages/components/include.md rename to docs/src/content/docs/components/include.md index 602e65ba9..079ce1a9b 100644 --- a/docs/pages/components/include.md +++ b/docs/src/content/docs/components/include.md @@ -1,8 +1,7 @@ --- -meta: - title: Include - description: Includes give you the power to embed external HTML files into the page. -layout: component +title: Include +description: Includes give you the power to embed external HTML files into the page. +layout: ../../../layouts/ComponentLayout.astro --- Included files are asynchronously requested using `window.fetch()`. Requests are cached, so the same file can be included multiple times, but only one request will be made. diff --git a/docs/pages/components/input.md b/docs/src/content/docs/components/input.md similarity index 98% rename from docs/pages/components/input.md rename to docs/src/content/docs/components/input.md index d9ca7afe2..5d90e779e 100644 --- a/docs/pages/components/input.md +++ b/docs/src/content/docs/components/input.md @@ -1,8 +1,7 @@ --- -meta: - title: Input - description: Inputs collect data from the user. -layout: component +title: Input +description: Inputs collect data from the user. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview diff --git a/docs/pages/components/menu-item.md b/docs/src/content/docs/components/menu-item.md similarity index 96% rename from docs/pages/components/menu-item.md rename to docs/src/content/docs/components/menu-item.md index 633415003..389eeb738 100644 --- a/docs/pages/components/menu-item.md +++ b/docs/src/content/docs/components/menu-item.md @@ -1,8 +1,7 @@ --- -meta: - title: Menu Item - description: Menu items provide options for the user to pick from in a menu. -layout: component +title: Menu Item +description: Menu items provide options for the user to pick from in a menu. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -25,8 +24,6 @@ layout: component ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; import WaIcon from '@shoelace-style/shoelace/dist/react/icon'; @@ -56,8 +53,6 @@ const App = () => ( ); ``` -{% endraw %} - ## Examples ### Prefix & Suffix @@ -86,8 +81,6 @@ Add content to the start and end of menu items using the `prefix` and `suffix` s ``` -{% raw %} - ```jsx:react import WaBadge from '@shoelace-style/shoelace/dist/react/badge'; import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; @@ -120,8 +113,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Disabled Add the `disabled` attribute to disable the menu item so it cannot be selected. @@ -134,8 +125,6 @@ Add the `disabled` attribute to disable the menu item so it cannot be selected. ``` -{% raw %} - ```jsx:react import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; import WaMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; @@ -149,8 +138,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Loading Use the `loading` attribute to indicate that a menu item is busy. Like a disabled menu item, clicks will be suppressed until the loading state is removed. @@ -163,8 +150,6 @@ Use the `loading` attribute to indicate that a menu item is busy. Like a disable ``` -{% raw %} - ```jsx:react import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; import WaMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; @@ -178,8 +163,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Checkbox Menu Items Set the `type` attribute to `checkbox` to create a menu item that will toggle on and off when selected. You can use the `checked` attribute to set the initial state. @@ -194,8 +177,6 @@ Checkbox menu items are visually indistinguishable from regular menu items. Thei ``` -{% raw %} - ```jsx:react import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; import WaMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; @@ -211,8 +192,6 @@ const App = () => ( ); ``` -{% endraw %} - ### Value & Selection The `value` attribute can be used to assign a hidden value, such as a unique identifier, to a menu item. When an item is selected, the `wa-select` event will be emitted and a reference to the item will be available at `event.detail.item`. You can use this reference to access the selected item's value, its checked state, and more. @@ -244,8 +223,6 @@ The `value` attribute can be used to assign a hidden value, such as a unique ide ``` -{% raw %} - ```jsx:react import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; import WaMenuItem from '@shoelace-style/shoelace/dist/react/menu-item'; @@ -270,5 +247,3 @@ const App = () => { ); }; ``` - -{% endraw %} diff --git a/docs/pages/components/menu-label.md b/docs/src/content/docs/components/menu-label.md similarity index 90% rename from docs/pages/components/menu-label.md rename to docs/src/content/docs/components/menu-label.md index f5fbefcd9..610243bf1 100644 --- a/docs/pages/components/menu-label.md +++ b/docs/src/content/docs/components/menu-label.md @@ -1,8 +1,7 @@ --- -meta: - title: Menu Label - description: Menu labels are used to describe a group of menu items. -layout: component +title: Menu Label +description: Menu labels are used to describe a group of menu items. +layout: ../../../layouts/ComponentLayout.astro --- ```html:preview @@ -19,8 +18,6 @@ layout: component ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; @@ -41,5 +38,3 @@ const App = () => ( ); ``` - -{% endraw %} diff --git a/docs/pages/components/menu.md b/docs/src/content/docs/components/menu.md similarity index 96% rename from docs/pages/components/menu.md rename to docs/src/content/docs/components/menu.md index 5c9657e84..45b268627 100644 --- a/docs/pages/components/menu.md +++ b/docs/src/content/docs/components/menu.md @@ -1,8 +1,7 @@ --- -meta: - title: Menu - description: Menus provide a list of options for the user to choose from. -layout: component +title: Menu +description: Menus provide a list of options for the user to choose from. +layout: ../../../layouts/ComponentLayout.astro --- You can use [menu items](/components/menu-item), [menu labels](/components/menu-label), and [dividers](/components/divider) to compose a menu. Menus support keyboard interactions, including type-to-select an option. @@ -19,8 +18,6 @@ You can use [menu items](/components/menu-item), [menu labels](/components/menu- ``` -{% raw %} - ```jsx:react import WaDivider from '@shoelace-style/shoelace/dist/react/divider'; import WaMenu from '@shoelace-style/shoelace/dist/react/menu'; @@ -39,8 +36,6 @@ const App = () => ( ); ``` -{% endraw %} - :::tip Menus are intended for system menus (dropdown menus, select menus, context menus, etc.). They should not be mistaken for navigation menus which serve a different purpose and have a different semantic meaning. If you're building navigation, use `