mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-19 15:34:15 +00:00
Compare commits
33 Commits
kj/selecto
...
wa-fa-elem
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ad868342 | ||
|
|
5e3fed605e | ||
|
|
4b4f2247c5 | ||
|
|
eca15dc7fc | ||
|
|
eca444bbaa | ||
|
|
f39308dbc5 | ||
|
|
fc84e1a50d | ||
|
|
ef7d47e2b9 | ||
|
|
a9af3172ad | ||
|
|
cde8bea97a | ||
|
|
33b4045dad | ||
|
|
bc4ad39f2e | ||
|
|
b868b1e8fc | ||
|
|
e916d771b0 | ||
|
|
bd6fe74c7d | ||
|
|
ac7437894a | ||
|
|
55ebe6e20b | ||
|
|
e6388e7671 | ||
|
|
9a21ae6f52 | ||
|
|
cd3386ce78 | ||
|
|
26b9bbb515 | ||
|
|
bda0ec0313 | ||
|
|
2490fbeaca | ||
|
|
297149021e | ||
|
|
c700c3ec09 | ||
|
|
b383d8bf2d | ||
|
|
1dcf895be1 | ||
|
|
19fd55ca97 | ||
|
|
fa094d924d | ||
|
|
2a957e6316 | ||
|
|
90b6a9a8ac | ||
|
|
99fdd90601 | ||
|
|
ecaa461638 |
2
.github/workflows/client_tests.js.yml
vendored
2
.github/workflows/client_tests.js.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Lint
|
||||
run: npm run prettier
|
||||
- name: Build
|
||||
run: npm run build
|
||||
run: npm run build:alpha
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run CSR tests
|
||||
|
||||
2
.github/workflows/ssr_tests.js.yml
vendored
2
.github/workflows/ssr_tests.js.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
run: npm run prettier
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
run: npm run build:alpha
|
||||
|
||||
- name: Install Playwright
|
||||
run: npx playwright install --with-deps
|
||||
|
||||
@@ -48,6 +48,9 @@ export default function (eleventyConfig) {
|
||||
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + location.replace(/^\//, '');
|
||||
});
|
||||
|
||||
// Paired shortcodes - {% shortCode %}content{% endShortCode %}
|
||||
eleventyConfig.addPairedShortcode('markdown', content => markdown.render(content || ''));
|
||||
|
||||
// Helpers
|
||||
|
||||
// Remove elements that have [data-alpha="remove"]
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
{% for category, pages in allPages | groupByTags(categories) -%}
|
||||
<h2 class="index-category">{{ category | getCategoryTitle(categories) }}</h2>
|
||||
{%- for page in pages -%}
|
||||
{%- if not page.data.unlisted and not page.data.parent -%}
|
||||
{%- if not page.data.parent or listChildren -%}
|
||||
{% include "page-card.njk" %}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
</section>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<a href="{{ page.url }}" data-keywords="{{ page.data.keywords }}">
|
||||
{%- if not page.data.unlisted -%}
|
||||
<a href="{{ page.url }}"{{ page.data.keywords | attr('data-keywords') }}>
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
|
||||
@@ -6,3 +7,4 @@
|
||||
<span class="page-name">{{ page.data.title }}</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
22
docs/_includes/sidebar-group.njk
Normal file
22
docs/_includes/sidebar-group.njk
Normal file
@@ -0,0 +1,22 @@
|
||||
{# Some collections (like "patterns") will not have any items in the alpha build for example. So this checks to make sure the collection exists. #}
|
||||
{% if collections[tag] -%}
|
||||
<wa-details {{ (('/' + tag + '/') in page.url) | attr('open') }}>
|
||||
<h2 slot="summary">
|
||||
{% set groupUrl %}/docs/{{ tag }}/{% endset %}
|
||||
{% if groupUrl | getCollectionItemFromUrl %}
|
||||
<a href="{{ groupUrl }}" title="Overview">{{ title or (tag | capitalize) }}
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
{% else %}
|
||||
{{ title or (tag | capitalize) }}
|
||||
{% endif %}
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections[tag] | sort %}
|
||||
{% if not page.data.parent -%}
|
||||
{% include 'sidebar-link.njk' %}
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</wa-details>
|
||||
{%- endif %}
|
||||
16
docs/_includes/sidebar-link.njk
Normal file
16
docs/_includes/sidebar-link.njk
Normal file
@@ -0,0 +1,16 @@
|
||||
{% if not (isAlpha and page.data.noAlpha) and page.fileSlug != tag and not page.data.unlisted -%}
|
||||
<li>
|
||||
<a href="/docs/{{ tag }}/{{ page.fileSlug }}">{{ page.data.title }}</a>
|
||||
{% if page.data.status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
|
||||
{% if page.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
|
||||
|
||||
{% set children = page.data.children %}
|
||||
{% if children.length > 0 %}
|
||||
<ul>
|
||||
{% for page in children %}
|
||||
{% include 'sidebar-link.njk' %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{%- endif %}
|
||||
@@ -19,121 +19,13 @@
|
||||
<li><a href="/docs/resources/changelog">Changelog</a></li>
|
||||
</ul>
|
||||
|
||||
{# Components #}
|
||||
<wa-details {{ 'open' if '/components/' in page.url }}>
|
||||
<h2 slot=summary>
|
||||
<a href="/docs/components/" title="Overview">Components
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
{% for component in collections.components | sort %}
|
||||
{% if not component.data.parent and not (isAlpha and component.data.noAlpha) and not component.data.unlisted %}
|
||||
<li>
|
||||
<a href="/docs/components/{{ component.fileSlug }}">{{ component.data.title }}</a>
|
||||
|
||||
{% if components[component.fileSlug].status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
|
||||
{% if component.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
|
||||
<ul>
|
||||
{% for child in collections.components | sort %}
|
||||
{% if child.data.parent == component.fileSlug and not (isAlpha and child.data.noAlpha) %}
|
||||
<li>
|
||||
<a href="/docs/components/{{ child.fileSlug }}">{{ child.data.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</wa-details>
|
||||
|
||||
<wa-details {{ 'open' if '/native/' in page.url }}>
|
||||
<h2 slot=summary>
|
||||
<a href="/docs/native/" title="Overview">Native Styles
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections.native | sort %}
|
||||
{% if page.fileSlug != 'native' and not page.unlisted %}
|
||||
<li>
|
||||
<a href="/docs/native/{{ page.fileSlug }}">{{ page.data.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</wa-details>
|
||||
|
||||
<wa-details {{ 'open' if '/utilities/' in page.url }}>
|
||||
<h2 slot=summary>
|
||||
<a href="/docs/utilities/" title="Overview">Style Utilities
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections.utilities | sort %}
|
||||
{% if page.fileSlug != 'utilities' and not page.unlisted %}
|
||||
<li>
|
||||
<a href="/docs/utilities/{{ page.fileSlug }}">{{ page.data.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</wa-details>
|
||||
|
||||
{# Layout #}
|
||||
<h2>
|
||||
<a href="/docs/layout" title="Overview">Layout
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections.layout | sort %}
|
||||
{% if page.fileSlug != 'layout' and not page.unlisted %}
|
||||
<li>
|
||||
<a href="{{ page.url }}">{{ page.data.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{# Patterns #}
|
||||
{% if not isAlpha %}
|
||||
<h2>Patterns</h2>
|
||||
<ul>
|
||||
<li><a href="/docs/patterns/app">Web App</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce">E-commerce</a>
|
||||
<ul>
|
||||
<li><a href="/docs/patterns/ecommerce-product-review">Product Reviews</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-product-list">Product Lists</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-category-preview">Category Previews</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-shopping-cart">Shopping Carts</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-category-filter">Category Filters</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-product-detail">Product Detail</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-order-summary">Order Summaries</a></li>
|
||||
<li><a href="/docs/patterns/ecommerce-order-history">Order History</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/docs/patterns/blog">Blog</a></li>
|
||||
<li><a href="/docs/patterns/news">News</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{# Theming #}
|
||||
<h2>
|
||||
<a href="/docs/theming" title="Overview">Theming
|
||||
<wa-icon name="grid-2"></wa-icon>
|
||||
</a>
|
||||
</h2>
|
||||
<ul>
|
||||
{% for page in collections.theming | sort %}
|
||||
{% if page.fileSlug != 'theming' and not page.unlisted %}
|
||||
<li>
|
||||
<a href="/docs/theming/{{ page.fileSlug }}">{{ page.data.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for tag, title in {
|
||||
'components': 'Components',
|
||||
'native': 'Native Styles',
|
||||
'utilities': 'Style Utilities',
|
||||
'layout': 'Layout',
|
||||
'patterns': 'Patterns',
|
||||
'theming': 'Theming'
|
||||
} %}
|
||||
{% include 'sidebar-group.njk' %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 337 B |
37
docs/_layouts/block.njk
Normal file
37
docs/_layouts/block.njk
Normal file
@@ -0,0 +1,37 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
|
||||
{# Component header #}
|
||||
{% block beforeContent %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<div class="block-info">
|
||||
{% set snippets = (elements or element or snippets or snippet) | dict %}
|
||||
|
||||
{% for snippet, link in snippets %}
|
||||
{% if snippet %}
|
||||
<code class="class">
|
||||
{%- if link -%}
|
||||
<a href="{{ link }}">{{ snippet }}</a>
|
||||
{%- else -%}
|
||||
{{ snippet }}
|
||||
{%- endif-%}
|
||||
</code>
|
||||
{%- endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% include '../_includes/status.njk' %}
|
||||
</div>
|
||||
{% if description %}
|
||||
<p class="summary">
|
||||
{{ description | inlineMarkdown | safe }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% block notes %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{# Content #}
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
@@ -1,23 +1,8 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
{% extends '../_layouts/block.njk' %}
|
||||
{% set component = components[page.fileSlug] %}
|
||||
{% set description = component.summary %}
|
||||
{% set status = component.status %}
|
||||
{% set since = component.since %}
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
|
||||
{# Component header #}
|
||||
{% block beforeContent %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<div class="component-info">
|
||||
<code class="tag"><{{ component.tagName }}></code>
|
||||
|
||||
{% include '../_includes/status.njk' %}
|
||||
</div>
|
||||
<p class="summary">
|
||||
{{ component.summary | inlineMarkdown | safe }}
|
||||
</p>
|
||||
{% block notes %}
|
||||
{% if native %}
|
||||
<wa-callout variant="success">
|
||||
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
|
||||
@@ -27,11 +12,6 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{# Content #}
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
|
||||
{# Component API #}
|
||||
{% block afterContent %}
|
||||
{# Slots #}
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
{% extends '../_layouts/block.njk' %}
|
||||
|
||||
{# Component header #}
|
||||
{% block beforeContent %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<div class="component-info">
|
||||
{% for tag, url in elements %}
|
||||
<code class="tag"><a href="{{ url }}">{{ tag }}</a></code>
|
||||
{% endfor %}
|
||||
{% include '../_includes/status.njk' %}
|
||||
</div>
|
||||
{% if description -%}
|
||||
<p class="summary">{{ description | inlineMarkdown | safe }}</p>
|
||||
{%- endif %}
|
||||
{% block notes %}
|
||||
{% if component %}
|
||||
<wa-callout variant="success">
|
||||
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
|
||||
Want to do more?
|
||||
Check out the {% for name in (component | toArray) -%}
|
||||
Check out the {% for name in (component | toList) -%}
|
||||
{{ ' and ' if loop.last and not loop.first }}<a href="/docs/components/{{ name }}"><code><wa-{{ name }}></code></a>{{ ', ' if not loop.last }}
|
||||
{%- endfor %} component{{ 's' if (component | isArray) }}</a>!
|
||||
{%- endfor %} component{{ 's' if (component | isList) }}</a>!
|
||||
</wa-callout>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{# Content #}
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
|
||||
{# Component API #}
|
||||
{% block afterContent %}
|
||||
{# Slots #}
|
||||
{% if css_file %}
|
||||
|
||||
25
docs/_layouts/overview.njk
Normal file
25
docs/_layouts/overview.njk
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: page-outline
|
||||
tags: ["overview"]
|
||||
---
|
||||
{% set forTag = forTag or (page.url | split('/') | last) %}
|
||||
{% if description %}
|
||||
<div class="index-summary">{{ description | markdown | safe }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="block-filter">
|
||||
<wa-input type="search" placeholder="Search {{ title }}" clearable autofocus>
|
||||
<wa-icon slot="prefix" name="search"></wa-icon>
|
||||
</wa-input>
|
||||
</div>
|
||||
|
||||
{% set allPages = collections[forTag] %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
|
||||
<link href="/assets/styles/filter.css" rel="stylesheet">
|
||||
<script type="module" src="/assets/scripts/filter.js"></script>
|
||||
|
||||
{% if content | trim %}
|
||||
<br> {# Temp fix for spacing issue #}
|
||||
{{ content | safe }}
|
||||
{% endif %}
|
||||
@@ -1,4 +0,0 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
|
||||
{% extends "../_includes/base.njk" %}
|
||||
@@ -1,25 +0,0 @@
|
||||
{% set hasSidebar = true %}
|
||||
{% set hasOutline = true %}
|
||||
|
||||
{% extends '../_includes/base.njk' %}
|
||||
|
||||
{# Component header #}
|
||||
{% block beforeContent %}
|
||||
<h1 class="title">{{ title }}</h1>
|
||||
<div class="component-info">
|
||||
|
||||
{% for className in classes %}
|
||||
<code class="class">.{{ className }}</code>
|
||||
{% endfor %}
|
||||
{% include '../_includes/status.njk' %}
|
||||
</div>
|
||||
{% if description -%}
|
||||
<p class="summary">{{ description | inlineMarkdown | safe }}</p>
|
||||
{%- endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{# Content #}
|
||||
{% block content %}
|
||||
{{ content | safe }}
|
||||
{% endblock %}
|
||||
@@ -38,8 +38,12 @@ export function getTitleFromUrl(url, collection) {
|
||||
return item?.data.title || '';
|
||||
}
|
||||
|
||||
export function split(text, separator) {
|
||||
return (text + '').split(separator).filter(Boolean);
|
||||
}
|
||||
|
||||
export function breadcrumbs(url, { withCurrent = false } = {}) {
|
||||
const parts = url.split('/').filter(Boolean);
|
||||
const parts = split(url, '/');
|
||||
const ret = [];
|
||||
|
||||
while (parts.length) {
|
||||
@@ -70,12 +74,30 @@ export function breadcrumbs(url, { withCurrent = false } = {}) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function isArray(value) {
|
||||
return Array.isArray(value);
|
||||
export function isObject(value) {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function toArray(value) {
|
||||
return isArray(value) ? value : [value];
|
||||
export function isList(value) {
|
||||
return Array.isArray(value) || value instanceof Set;
|
||||
}
|
||||
|
||||
/** Get an Array or Set */
|
||||
export function toList(value) {
|
||||
return isList(value) ? value : [value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any value to something that can be iterated over with a for key, value loop.
|
||||
* Arrays and sets will be converted to a Map of value -> undefined
|
||||
*/
|
||||
export function dict(value) {
|
||||
if (value instanceof Map || isObject(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
let list = toList(value);
|
||||
return new Map([...list].map(item => [item, undefined]));
|
||||
}
|
||||
|
||||
export function deepValue(obj, key) {
|
||||
@@ -83,11 +105,15 @@ export function deepValue(obj, key) {
|
||||
return key.reduce((subObj, property) => subObj?.[property], obj);
|
||||
}
|
||||
|
||||
function isNumeric(value) {
|
||||
export function isNumeric(value) {
|
||||
return typeof value === 'number' || (typeof value === 'string' && !isNaN(value));
|
||||
}
|
||||
|
||||
function isEmpty(value) {
|
||||
export function isString(value) {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
export function isEmpty(value) {
|
||||
return value === null || value === undefined || value === '';
|
||||
}
|
||||
|
||||
@@ -113,13 +139,13 @@ function compare(a, b) {
|
||||
return (a + '').localeCompare(b);
|
||||
}
|
||||
|
||||
/** Sort an array of objects */
|
||||
export function sort(arr, keys = ['data.order', 'data.title']) {
|
||||
keys = toArray(keys);
|
||||
/** Sort an array of objects by one or more of their properties */
|
||||
export function sort(arr, by = { 'data.order': 1, 'data.title': '' }) {
|
||||
let keys = Array.isArray(by) ? by : Object.keys(by);
|
||||
|
||||
return arr.sort((a, b) => {
|
||||
let aValues = keys.map(key => deepValue(a, key));
|
||||
let bValues = keys.map(key => deepValue(b, key));
|
||||
let aValues = keys.map(key => deepValue(a, key) ?? by[key]);
|
||||
let bValues = keys.map(key => deepValue(b, key) ?? by[key]);
|
||||
|
||||
for (let i = 0; i < aValues.length; i++) {
|
||||
let aVal = aValues[i];
|
||||
@@ -198,3 +224,41 @@ export function getCategoryTitle(category, categories) {
|
||||
// Capitalized
|
||||
return category.charAt(0).toUpperCase() + category.slice(1);
|
||||
}
|
||||
|
||||
const IDENTITY = x => x;
|
||||
|
||||
/**
|
||||
* Helper to print out one or more HTML attributes, especially conditional ones.
|
||||
* Usage in 11ty:
|
||||
* - Single attribute: `<foo{{ value | attr(name) }}>`
|
||||
* - Multiple attributes: `<foo{{ { name1: value1, name2: value2 } | attr }}>`
|
||||
*
|
||||
* @overload
|
||||
* @param {any} value - The attribute value If falsey, the attribute is not printed. If `true` the attribute is printed without a value.
|
||||
* @param {string} name - The name of the attribute
|
||||
*
|
||||
* @overload
|
||||
* @param {Object<string, any>} obj - Map of attribute names to values
|
||||
*
|
||||
* @returns {string} The attribute string. No `| safe` is needed.
|
||||
*/
|
||||
export function attr(value, name) {
|
||||
const safe = this?.env.filters.safe ?? IDENTITY;
|
||||
|
||||
if (arguments.length === 1 && value && typeof value === 'object') {
|
||||
// Called with a single object argument of names to values
|
||||
let ret = Object.entries(obj)
|
||||
.map(([name, value]) => attr(value, name))
|
||||
.join('');
|
||||
return safe(ret);
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
// false, "", null, undefined
|
||||
return '';
|
||||
}
|
||||
|
||||
let ret = ' ' + name + (value === true ? '' : `="${value}"`);
|
||||
|
||||
return safe(ret);
|
||||
}
|
||||
|
||||
25
docs/assets/scripts/filter.js
Normal file
25
docs/assets/scripts/filter.js
Normal file
@@ -0,0 +1,25 @@
|
||||
function updateResults(input) {
|
||||
const filter = input.value.toLowerCase().trim();
|
||||
let filtered = Boolean(filter);
|
||||
|
||||
for (let grid of document.querySelectorAll('.index-grid')) {
|
||||
grid.classList.toggle('filtered', filtered);
|
||||
|
||||
for (let item of grid.querySelectorAll('a:has(> wa-card)')) {
|
||||
let isMatch = true;
|
||||
|
||||
if (filter) {
|
||||
const content = item.textContent.toLowerCase() + ' ' + (item.getAttribute('data-keywords') + ' ');
|
||||
isMatch = content.includes(filter);
|
||||
}
|
||||
|
||||
item.hidden = !isMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.documentElement.addEventListener('wa-input', e => {
|
||||
if (e.target?.matches('#block-filter wa-input')) {
|
||||
updateResults(e.target);
|
||||
}
|
||||
});
|
||||
@@ -230,7 +230,7 @@ h1.title wa-badge {
|
||||
}
|
||||
}
|
||||
|
||||
.component-info {
|
||||
.block-info {
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
}
|
||||
|
||||
|
||||
37
docs/assets/styles/filter.css
Normal file
37
docs/assets/styles/filter.css
Normal file
@@ -0,0 +1,37 @@
|
||||
wa-card#drawer-card::part(header) {
|
||||
--spacing: 0;
|
||||
justify-content: flex-end;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#block-filter {
|
||||
margin-block-end: var(--wa-space-xl);
|
||||
}
|
||||
|
||||
.index-grid.filtered {
|
||||
h2 {
|
||||
/* Hide headings while filtering */
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:not(:has(> a:not([hidden]))) {
|
||||
/* We’re filtering and there are no results */
|
||||
|
||||
&::before {
|
||||
content: var(--empty-message);
|
||||
grid-column: 1 / -1;
|
||||
color: var(--wa-color-on-quiet);
|
||||
font-style: italic;
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
}
|
||||
|
||||
/* Show empty state when there's a search filter and no results */
|
||||
&[data-empty] {
|
||||
--empty-message: attr(data-empty);
|
||||
}
|
||||
|
||||
&:not([data-empty]) {
|
||||
--empty-message: 'No results';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,71 @@ Set the `variant` attribute to change the callout's variant.
|
||||
</wa-callout>
|
||||
```
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the `appearance` attribute to change the callout's visual appearance (the default is `outlined filled`).
|
||||
|
||||
```html {.example}
|
||||
<wa-callout variant="brand" appearance="outlined accent">
|
||||
<wa-icon slot="icon" name="check-to-slot"></wa-icon>
|
||||
This <strong>accent</strong> callout is also <strong>outlined</strong>
|
||||
</wa-callout>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-callout variant="brand" appearance="accent">
|
||||
<wa-icon slot="icon" name="square-check"></wa-icon>
|
||||
This <strong>accent</strong> callout draws attention without an outline
|
||||
</wa-callout>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-callout variant="brand" appearance="outlined filled">
|
||||
<wa-icon slot="icon" name="fill-drip" variant="regular"></wa-icon>
|
||||
This callout is both <strong>filled</strong> and <strong>outlined</strong>
|
||||
</wa-callout>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-callout variant="brand" appearance="filled">
|
||||
<wa-icon slot="icon" name="fill" variant="regular"></wa-icon>
|
||||
This callout is only <strong>filled</strong>
|
||||
</wa-callout>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-callout variant="brand" appearance="outlined">
|
||||
<wa-icon slot="icon" name="lines-leaning" variant="regular"></wa-icon>
|
||||
Here's an <strong>outlined</strong> callout
|
||||
</wa-callout>
|
||||
|
||||
<br />
|
||||
|
||||
<wa-callout variant="brand" appearance="plain">
|
||||
<wa-icon slot="icon" name="font" variant="regular"></wa-icon>
|
||||
No bells and whistles on this <strong>plain</strong> callout
|
||||
</wa-callout>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` attribute to change a callout's size.
|
||||
|
||||
```html {.example}
|
||||
<wa-callout variant="brand" appearance="outlined accent" size="large">
|
||||
<wa-icon slot="icon" name="circle-info" variant="solid"></wa-icon>
|
||||
This is meant to be very emphasized.
|
||||
</wa-callout>
|
||||
<wa-callout>
|
||||
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
|
||||
Normal-sized callout.
|
||||
</wa-callout>
|
||||
<wa-callout variant="plain" appearance="plain" size="small">
|
||||
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
|
||||
Just a small tip!
|
||||
</wa-callout>
|
||||
```
|
||||
|
||||
### Without Icons
|
||||
|
||||
Icons are optional. Simply omit the `icon` slot if you don't want them.
|
||||
|
||||
@@ -60,7 +60,8 @@ Basic cards aren't very exciting, but they can display any content you want them
|
||||
|
||||
### Card with Header
|
||||
|
||||
Headers can be used to display titles and more. Use the `with-header` attribute to add a header to the card.
|
||||
Headers can be used to display titles and more.
|
||||
If using SSR, you need to also use the `with-header` attribute to add a header to the card (if not, it is added automatically).
|
||||
|
||||
```html {.example}
|
||||
<wa-card with-header class="card-header">
|
||||
@@ -95,7 +96,8 @@ Headers can be used to display titles and more. Use the `with-header` attribute
|
||||
|
||||
### Card with Footer
|
||||
|
||||
Footers can be used to display actions, summaries, or other relevant content. Use the `with-footer` attribute to add a footer to the card.
|
||||
Footers can be used to display actions, summaries, or other relevant content.
|
||||
If using SSR, you need to also use the `with-footer` attribute to add a footer to the card (if not, it is added automatically).
|
||||
|
||||
```html {.example}
|
||||
<wa-card with-footer class="card-footer">
|
||||
@@ -122,7 +124,8 @@ Footers can be used to display actions, summaries, or other relevant content. Us
|
||||
|
||||
### Images
|
||||
|
||||
Card images are displayed atop the card and will stretch to fit. Use the `with-image` attribute to add an image to the card.
|
||||
Card images are displayed atop the card and will stretch to fit.
|
||||
If using SSR, you need to also use the `with-image` attribute to add an image to the card (if not, it is added automatically).
|
||||
|
||||
```html {.example}
|
||||
<wa-card with-image class="card-image">
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
{
|
||||
"layout": "component.njk",
|
||||
"tags": ["components"]
|
||||
"tags": ["components"],
|
||||
"eleventyComputed": {
|
||||
"component": "{{ components[page.fileSlug] }}",
|
||||
"description": "{{ components[page.fileSlug].summary }}",
|
||||
"status": "{{ components[page.fileSlug].status }}",
|
||||
"since": "{{ components[page.fileSlug].since }}",
|
||||
"element": "<{{ components[page.fileSlug].tagName }}>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
---
|
||||
title: Components
|
||||
description: Components are the essential building blocks to create intuitive, cohesive experiences. Browse the library of customizable, framework-friendly web components included in Web Awesome.
|
||||
layout: page-outline
|
||||
categories:
|
||||
- actions
|
||||
- feedback: 'Feedback & Status'
|
||||
- imagery
|
||||
- inputs
|
||||
- navigation
|
||||
- organization
|
||||
- helpers: 'Utilities'
|
||||
override:tags: []
|
||||
---
|
||||
|
||||
<div id="component-filter">
|
||||
<wa-input type="search" placeholder="Search components" clearable autofocus></wa-input>
|
||||
</div>
|
||||
|
||||
{% set allPages = collections.components %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
|
||||
<div id="component-filter-empty" hidden>
|
||||
No results
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
const container = document.getElementById('component-filter');
|
||||
const empty = document.getElementById('component-filter-empty');
|
||||
const grid = document.getElementById('content');
|
||||
const input = container.querySelector('wa-input');
|
||||
|
||||
function updateResults() {
|
||||
const filter = input.value.toLowerCase().trim();
|
||||
|
||||
// Hide headings while filtering
|
||||
grid.querySelectorAll('h2').forEach(heading => {
|
||||
heading.hidden = filter === '' ? false : true;
|
||||
});
|
||||
|
||||
// Show matching components
|
||||
grid.querySelectorAll('a:has(> wa-card)').forEach(link => {
|
||||
console.log(link);
|
||||
const content = link.textContent.toLowerCase();
|
||||
const keywords = link.getAttribute('data-keywords') || '';
|
||||
const isMatch = filter === '' || (content + keywords).includes(filter);
|
||||
link.hidden = !isMatch;
|
||||
});
|
||||
|
||||
// Show empty state when there's a search filter and no results
|
||||
if (filter !== '' && grid.querySelector('a:not([hidden])') === null) {
|
||||
empty.hidden = false;
|
||||
} else {
|
||||
empty.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
input.addEventListener('wa-input', updateResults);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
wa-card#drawer-card::part(header) {
|
||||
--spacing: 0;
|
||||
justify-content: flex-end;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#component-filter {
|
||||
margin-block-end: var(--wa-space-xl);
|
||||
}
|
||||
|
||||
#component-filter-empty {
|
||||
border: dashed var(--wa-border-width-m) var(--wa-color-neutral-border-quiet);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
font-size: var(--wa-font-size-l);
|
||||
color: var(--wa-color-text-quiet);
|
||||
text-align: center;
|
||||
padding-block: var(--wa-space-2xl);
|
||||
margin-block-start: 0
|
||||
}
|
||||
</style>
|
||||
14
docs/docs/components/index.njk
Normal file
14
docs/docs/components/index.njk
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Components
|
||||
description: Components are the essential building blocks to create intuitive, cohesive experiences. Browse the library of customizable, framework-friendly web components included in Web Awesome.
|
||||
layout: overview
|
||||
categories:
|
||||
- actions
|
||||
- feedback: 'Feedback & Status'
|
||||
- imagery
|
||||
- inputs
|
||||
- navigation
|
||||
- organization
|
||||
- helpers: 'Utilities'
|
||||
override:tags: []
|
||||
---
|
||||
@@ -3,7 +3,7 @@ title: Page
|
||||
description: Pages offer an easy way to scaffold entire page layouts using minimal markup.
|
||||
tags: [organization, layout]
|
||||
isPro: true
|
||||
order: 1
|
||||
order: 0
|
||||
# icon: page
|
||||
---
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ Use the `distance` attribute to change the distance between the popup and its an
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
|
||||
<wa-range min="-50" max="50" step="1" value="0" label="Distance"></wa-range>
|
||||
<wa-slider min="-50" max="50" step="1" value="0" label="Distance"></wa-slider>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -267,7 +267,7 @@ Use the `distance` attribute to change the distance between the popup and its an
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.popup-distance wa-range {
|
||||
.popup-distance wa-slider {
|
||||
max-width: 260px;
|
||||
}
|
||||
</style>
|
||||
@@ -275,7 +275,7 @@ Use the `distance` attribute to change the distance between the popup and its an
|
||||
<script>
|
||||
const container = document.querySelector('.popup-distance');
|
||||
const popup = container.querySelector('wa-popup');
|
||||
const distance = container.querySelector('wa-range');
|
||||
const distance = container.querySelector('wa-slider');
|
||||
|
||||
distance.addEventListener('wa-input', () => (popup.distance = distance.value));
|
||||
</script>
|
||||
@@ -292,7 +292,7 @@ The `skidding` attribute is similar to `distance`, but instead allows you to off
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
|
||||
<wa-range min="-50" max="50" step="1" value="0" label="Skidding"></wa-range>
|
||||
<wa-slider min="-50" max="50" step="1" value="0" label="Skidding"></wa-slider>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -311,7 +311,7 @@ The `skidding` attribute is similar to `distance`, but instead allows you to off
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.popup-skidding wa-range {
|
||||
.popup-skidding wa-slider {
|
||||
max-width: 260px;
|
||||
}
|
||||
</style>
|
||||
@@ -319,7 +319,7 @@ The `skidding` attribute is similar to `distance`, but instead allows you to off
|
||||
<script>
|
||||
const container = document.querySelector('.popup-skidding');
|
||||
const popup = container.querySelector('wa-popup');
|
||||
const skidding = container.querySelector('wa-range');
|
||||
const skidding = container.querySelector('wa-slider');
|
||||
|
||||
skidding.addEventListener('wa-input', () => (popup.skidding = skidding.value));
|
||||
</script>
|
||||
@@ -747,8 +747,8 @@ When a gap exists between the anchor and the popup element, this option will add
|
||||
</wa-popup>
|
||||
<br>
|
||||
<wa-switch checked>Hover Bridge</wa-switch><br>
|
||||
<wa-range min="0" max="50" step="1" value="10" label="Distance"></wa-range>
|
||||
<wa-range min="-50" max="50" step="1" value="0" label="Skidding"></wa-range>
|
||||
<wa-slider min="0" max="50" step="1" value="10" label="Distance"></wa-slider>
|
||||
<wa-slider min="-50" max="50" step="1" value="0" label="Skidding"></wa-slider>
|
||||
</div>
|
||||
<style>
|
||||
.popup-hover-bridge span[slot='anchor'] {
|
||||
@@ -766,7 +766,7 @@ When a gap exists between the anchor and the popup element, this option will add
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.popup-hover-bridge wa-range {
|
||||
.popup-hover-bridge wa-slider {
|
||||
max-width: 260px;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
@@ -780,8 +780,8 @@ When a gap exists between the anchor and the popup element, this option will add
|
||||
const container = document.querySelector('.popup-hover-bridge');
|
||||
const popup = container.querySelector('wa-popup');
|
||||
const hoverBridge = container.querySelector('wa-switch');
|
||||
const distance = container.querySelector('wa-range[label="Distance"]');
|
||||
const skidding = container.querySelector('wa-range[label="Skidding"]');
|
||||
const distance = container.querySelector('wa-slider[label="Distance"]');
|
||||
const skidding = container.querySelector('wa-slider[label="Skidding"]');
|
||||
distance.addEventListener('wa-input', () => (popup.distance = distance.value));
|
||||
skidding.addEventListener('wa-input', () => (popup.skidding = skidding.value));
|
||||
hoverBridge.addEventListener('wa-change', () => (popup.hoverBridge = hoverBridge.checked));
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: Range
|
||||
title: Slider
|
||||
description: Ranges allow the user to select a single value within a given range using a slider.
|
||||
tags: [inputs, forms]
|
||||
native: slider
|
||||
icon: range
|
||||
icon: slider
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
<wa-range></wa-range>
|
||||
<wa-slider></wa-slider>
|
||||
```
|
||||
|
||||
:::info
|
||||
@@ -21,7 +21,7 @@ This component works with standard `<form>` elements. Please refer to the sectio
|
||||
Use the `label` attribute to give the range an accessible label. For labels that contain HTML, use the `label` slot instead.
|
||||
|
||||
```html {.example}
|
||||
<wa-range label="Volume" min="0" max="100"></wa-range>
|
||||
<wa-slider label="Volume" min="0" max="100"></wa-slider>
|
||||
```
|
||||
|
||||
### Hint
|
||||
@@ -29,7 +29,7 @@ Use the `label` attribute to give the range an accessible label. For labels that
|
||||
Add descriptive hint to a range with the `hint` attribute. For hints that contain HTML, use the `hint` slot instead.
|
||||
|
||||
```html {.example}
|
||||
<wa-range label="Volume" hint="Controls the volume of the current song." min="0" max="100"></wa-range>
|
||||
<wa-slider label="Volume" hint="Controls the volume of the current song." min="0" max="100"></wa-slider>
|
||||
```
|
||||
|
||||
### Min, Max, and Step
|
||||
@@ -37,7 +37,7 @@ Add descriptive hint to a range with the `hint` attribute. For hints that contai
|
||||
Use the `min` and `max` attributes to set the range's minimum and maximum values, respectively. The `step` attribute determines the value's interval when increasing and decreasing.
|
||||
|
||||
```html {.example}
|
||||
<wa-range min="0" max="10" step="1"></wa-range>
|
||||
<wa-slider min="0" max="10" step="1"></wa-slider>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
@@ -45,7 +45,7 @@ Use the `min` and `max` attributes to set the range's minimum and maximum values
|
||||
Use the `disabled` attribute to disable a slider.
|
||||
|
||||
```html {.example}
|
||||
<wa-range disabled></wa-range>
|
||||
<wa-slider disabled></wa-slider>
|
||||
```
|
||||
|
||||
### Tooltip Placement
|
||||
@@ -53,7 +53,7 @@ Use the `disabled` attribute to disable a slider.
|
||||
By default, the tooltip is shown on top. Set `tooltip` to `bottom` to show it below the slider.
|
||||
|
||||
```html {.example}
|
||||
<wa-range tooltip="bottom"></wa-range>
|
||||
<wa-slider tooltip="bottom"></wa-slider>
|
||||
```
|
||||
|
||||
### Disable the Tooltip
|
||||
@@ -61,7 +61,7 @@ By default, the tooltip is shown on top. Set `tooltip` to `bottom` to show it be
|
||||
To disable the tooltip, set `tooltip` to `none`.
|
||||
|
||||
```html {.example}
|
||||
<wa-range tooltip="none"></wa-range>
|
||||
<wa-slider tooltip="none"></wa-slider>
|
||||
```
|
||||
|
||||
### Custom Track Colors
|
||||
@@ -69,12 +69,12 @@ To disable the tooltip, set `tooltip` to `none`.
|
||||
You can customize the active and inactive portions of the track using the `--track-color-active` and `--track-color-inactive` custom properties.
|
||||
|
||||
```html {.example}
|
||||
<wa-range
|
||||
<wa-slider
|
||||
style="
|
||||
--track-color-active: var(--wa-color-brand-fill-loud);
|
||||
--track-color-inactive: var(--wa-color-brand-fill-normal);
|
||||
"
|
||||
></wa-range>
|
||||
></wa-slider>
|
||||
```
|
||||
|
||||
### Custom Track Offset
|
||||
@@ -82,7 +82,7 @@ You can customize the active and inactive portions of the track using the `--tra
|
||||
You can customize the initial offset of the active track using the `--track-active-offset` custom property.
|
||||
|
||||
```html {.example}
|
||||
<wa-range
|
||||
<wa-slider
|
||||
min="-100"
|
||||
max="100"
|
||||
style="
|
||||
@@ -90,7 +90,7 @@ You can customize the initial offset of the active track using the `--track-acti
|
||||
--track-color-inactive: var(--wa-color-brand-fill-normal);
|
||||
--track-active-offset: 50%;
|
||||
"
|
||||
></wa-range>
|
||||
></wa-slider>
|
||||
```
|
||||
|
||||
### Custom Tooltip Formatter
|
||||
@@ -98,7 +98,7 @@ You can customize the initial offset of the active track using the `--track-acti
|
||||
You can change the tooltip's content by setting the `tooltipFormatter` property to a function that accepts the range's value as an argument.
|
||||
|
||||
```html {.example}
|
||||
<wa-range min="0" max="100" step="1" class="range-with-custom-formatter"></wa-range>
|
||||
<wa-slider min="0" max="100" step="1" class="range-with-custom-formatter"></wa-slider>
|
||||
|
||||
<script>
|
||||
const range = document.querySelector('.range-with-custom-formatter');
|
||||
@@ -111,8 +111,8 @@ You can change the tooltip's content by setting the `tooltipFormatter` property
|
||||
The component adapts to right-to-left (RTL) languages as you would expect.
|
||||
|
||||
```html {.example}
|
||||
<wa-range dir="rtl"
|
||||
<wa-slider dir="rtl"
|
||||
label="مقدار"
|
||||
hint="التحكم في مستوى صوت الأغنية الحالية."
|
||||
style="--track-color-active: var(--wa-color-brand-fill-loud)" value="10"></wa-range>
|
||||
style="--track-color-active: var(--wa-color-brand-fill-loud)" value="10"></wa-slider>
|
||||
```
|
||||
@@ -15,9 +15,50 @@ icon: tag
|
||||
|
||||
## Examples
|
||||
|
||||
### Appearance
|
||||
|
||||
Use the `size` attribute to change a tag's visual appearance.
|
||||
The default appearance is `outlined filled`.
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-stack">
|
||||
<p>
|
||||
<wa-tag variant="brand" appearance="outlined accent">Outlined accent</wa-tag>
|
||||
<wa-tag variant="brand" appearance="accent">Accent</wa-tag>
|
||||
<wa-tag variant="brand" appearance="outlined">Outlined</wa-tag>
|
||||
<wa-tag variant="brand" appearance="filled">Filled</wa-tag>
|
||||
<wa-tag variant="brand" appearance="outlined filled">Outlined Filled</wa-tag>
|
||||
</p>
|
||||
<p>
|
||||
<wa-tag variant="success" appearance="outlined accent">Outlined accent</wa-tag>
|
||||
<wa-tag variant="success" appearance="accent">Accent</wa-tag>
|
||||
<wa-tag variant="success" appearance="outlined">Outlined</wa-tag>
|
||||
<wa-tag variant="success" appearance="filled">Filled</wa-tag>
|
||||
<wa-tag variant="success" appearance="outlined filled">Outlined Filled</wa-tag>
|
||||
<p>
|
||||
<wa-tag variant="neutral" appearance="outlined accent">Outlined accent</wa-tag>
|
||||
<wa-tag variant="neutral" appearance="accent">Accent</wa-tag>
|
||||
<wa-tag variant="neutral" appearance="outlined">Outlined</wa-tag>
|
||||
<wa-tag variant="neutral" appearance="filled">Filled</wa-tag>
|
||||
<wa-tag variant="neutral" appearance="outlined filled">Outlined Filled</wa-tag>
|
||||
<p>
|
||||
<wa-tag variant="warning" appearance="outlined accent">Outlined accent</wa-tag>
|
||||
<wa-tag variant="warning" appearance="accent">Accent</wa-tag>
|
||||
<wa-tag variant="warning" appearance="outlined">Outlined</wa-tag>
|
||||
<wa-tag variant="warning" appearance="filled">Filled</wa-tag>
|
||||
<wa-tag variant="warning" appearance="outlined filled">Outlined Filled</wa-tag>
|
||||
<p>
|
||||
<wa-tag variant="danger" appearance="outlined accent">Outlined accent</wa-tag>
|
||||
<wa-tag variant="danger" appearance="accent">Accent</wa-tag>
|
||||
<wa-tag variant="danger" appearance="outlined">Outlined</wa-tag>
|
||||
<wa-tag variant="danger" appearance="filled">Filled</wa-tag>
|
||||
<wa-tag variant="danger" appearance="outlined filled">Outlined Filled</wa-tag>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Sizes
|
||||
|
||||
Use the `size` attribute to change a tab's size.
|
||||
Use the `size` attribute to change a tag's size.
|
||||
|
||||
```html {.example}
|
||||
<wa-tag size="small">Small</wa-tag>
|
||||
|
||||
10
docs/docs/docs.11tydata.js
Normal file
10
docs/docs/docs.11tydata.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
eleventyComputed: {
|
||||
children(data) {
|
||||
let mainTag = data.tags?.[0];
|
||||
let collection = data.collections[mainTag] ?? [];
|
||||
|
||||
return collection.filter(item => item.data.parent === data.page.fileSlug);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -15,7 +15,7 @@ Adding the `wa-valid` or `wa-invalid` class to a form control will change its ap
|
||||
<wa-option>Well, maybe two is OK</wa-option>
|
||||
</wa-select>
|
||||
<wa-textarea class="wa-valid" label="Bio" hint="Tell us about yourself" placeholder="Enter a bio"></wa-textarea><br>
|
||||
<wa-range class="wa-valid" value="50" label="Volume" hint="Crank it up"></wa-range><br>
|
||||
<wa-slider class="wa-valid" value="50" label="Volume" hint="Crank it up"></wa-slider><br>
|
||||
<wa-checkbox class="wa-valid" checked>I am awesome</wa-checkbox><br>
|
||||
<wa-checkbox class="wa-valid">So am I</wa-checkbox><br><br>
|
||||
<wa-switch class="wa-valid" checked>Still awesome</wa-switch><br>
|
||||
@@ -35,7 +35,7 @@ Adding the `wa-valid` or `wa-invalid` class to a form control will change its ap
|
||||
<wa-option>Well, maybe two is OK</wa-option>
|
||||
</wa-select>
|
||||
<wa-textarea class="wa-invalid" label="Bio" hint="Tell us about yourself" placeholder="Enter a bio"></wa-textarea><br>
|
||||
<wa-range class="wa-invalid" value="50" label="Volume" hint="Crank it up"></wa-range><br>
|
||||
<wa-slider class="wa-invalid" value="50" label="Volume" hint="Crank it up"></wa-slider><br>
|
||||
<wa-checkbox class="wa-invalid" checked>I am awesome</wa-checkbox><br>
|
||||
<wa-checkbox class="wa-invalid">So am I</wa-checkbox><br><br>
|
||||
<wa-switch class="wa-invalid" checked>Still awesome</wa-switch><br>
|
||||
|
||||
@@ -132,7 +132,7 @@ layout: page
|
||||
<br />
|
||||
<wa-switch checked>Switch on</wa-switch>
|
||||
<br /><br />
|
||||
<wa-range label="Range" hint="Here's a bit of handy content." min="0" max="100"></wa-range>
|
||||
<wa-slider label="Range" hint="Here's a bit of handy content." min="0" max="100"></wa-slider>
|
||||
<br /><br />
|
||||
<wa-input label="Label" hint="Super helpful and/or contextual content" placeholder="Placeholder"></wa-input>
|
||||
<br />
|
||||
@@ -239,7 +239,7 @@ layout: page
|
||||
<wa-badge>OCBS</wa-badge>
|
||||
<wa-avatar></wa-avatar>
|
||||
<wa-rating></wa-rating>
|
||||
<wa-range></wa-range>
|
||||
<wa-slider></wa-slider>
|
||||
<wa-icon-button name="gear" label="Settings"></wa-icon-button>
|
||||
<wa-progress-bar value="50" style="width: 8rem;"></wa-progress-bar>
|
||||
<wa-spinner></wa-spinner>
|
||||
|
||||
@@ -661,10 +661,10 @@ hasOutline: false
|
||||
<wa-option value="dotted">Dotted</wa-option>
|
||||
<wa-option value="double">Double</wa-option>
|
||||
</wa-select>
|
||||
<wa-range name="border-width" label="Border width" min="1" max="5" value="1" step="1" tooltip="none"></wa-range>
|
||||
<wa-range name="spacing" label="Spacing" min=".5" max="1.5" value="1" step="0.125" tooltip="none"></wa-range>
|
||||
<wa-range name="corners" label="Corners" min="0" max="1.5" value=".25" step=".125" tooltip="none"></wa-range>
|
||||
<wa-range name="depth" label="Depth" min="0" max="4" value="0" step="1" tooltip="none"></wa-range>
|
||||
<wa-slider name="border-width" label="Border width" min="1" max="5" value="1" step="1" tooltip="none"></wa-slider>
|
||||
<wa-slider name="spacing" label="Spacing" min=".5" max="1.5" value="1" step="0.125" tooltip="none"></wa-slider>
|
||||
<wa-slider name="corners" label="Corners" min="0" max="1.5" value=".25" step=".125" tooltip="none"></wa-slider>
|
||||
<wa-slider name="depth" label="Depth" min="0" max="4" value="0" step="1" tooltip="none"></wa-slider>
|
||||
</wa-details>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
title: Layout
|
||||
description: Browse Web Awesome's components and utilities for creating responsive web layouts.
|
||||
layout: page-outline
|
||||
categories: ["components", "utilities"]
|
||||
---
|
||||
|
||||
<style>
|
||||
wa-page > main {
|
||||
max-width: 120ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
.index-grid wa-card::part(header) {
|
||||
background-color: var(--wa-color-neutral-fill-quiet);
|
||||
border-bottom: none;
|
||||
}
|
||||
wa-card .component-name,
|
||||
wa-card .page-name {
|
||||
font-size: var(--wa-font-size-s);
|
||||
font-weight: var(--wa-font-weight-action);
|
||||
}
|
||||
</style>
|
||||
|
||||
<p style="max-width: 80ch">Layout components and utility classes help you organize content that can adapt to any device or screen size. Browse the collection of responsive layout tools included in Web Awesome Pro.</p>
|
||||
|
||||
{% set allPages = collections.layout %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
7
docs/docs/layout.njk
Normal file
7
docs/docs/layout.njk
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Layout
|
||||
description: Layout components and utility classes help you organize content that can adapt to any device or screen size. Browse the collection of responsive layout tools included in Web Awesome Pro.
|
||||
layout: overview
|
||||
categories: ["components", "utilities"]
|
||||
override:tags: []
|
||||
---
|
||||
@@ -4,6 +4,9 @@ description: 'Button styles apply your Web Awesome theme to native HTML buttons.
|
||||
tags: forms
|
||||
component: button
|
||||
icon: button
|
||||
snippets:
|
||||
'<button>': https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button
|
||||
'.wa-button': false
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
---
|
||||
title: Native Styles
|
||||
description: Native Styles use your theme to style native HTML elements to match the look and feel of Web Awesome components.
|
||||
layout: page-outline
|
||||
layout: overview
|
||||
categories: ['forms', 'apps', 'content']
|
||||
override:tags: []
|
||||
---
|
||||
|
||||
{% markdown %}
|
||||
Web Awesome works _with_ the platform, rather than trying to reinvent it.
|
||||
If all you need is styles, you don’t need to use new `<wa-*>` elements!
|
||||
We also provide styles that make native HTML elements look good so you can continue using what you know and gradually adopt Web Awesome as you see fit.
|
||||
|
||||
{% set allPages = collections.native %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
|
||||
<br> {# Temp fix for spacing issue #}
|
||||
|
||||
## Installation
|
||||
|
||||
To use all Web Awesome page styles (including [utilities](/docs/utilities/)), include the following stylesheet in your project:
|
||||
@@ -86,3 +82,4 @@ E.g. to opt-out of `<details>` styling:
|
||||
|
||||
If you find yourself opting out of entire element types too much, you could consider only including the parts of Native Styles you need instead of the whole thing.
|
||||
You can find instructions for how to do that on the individual Native Styles pages.
|
||||
{% endmarkdown %}
|
||||
@@ -3,8 +3,8 @@ title: Slider
|
||||
description: Sliders allow the user to select a single value within a given range using a slider.
|
||||
tags: forms
|
||||
layout: element
|
||||
icon: range
|
||||
component: range
|
||||
icon: slider
|
||||
component: slider
|
||||
elements:
|
||||
"<input type=range>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range
|
||||
---
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: App
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -1045,4 +1044,4 @@ TODO Page Description
|
||||
```
|
||||
### With templates
|
||||
|
||||
### With recommendations grid
|
||||
### With recommendations grid
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: Blog
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -367,4 +366,4 @@ TODO Page Description
|
||||
}
|
||||
|
||||
</style>
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Business
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Category Filter
|
||||
title: Category Filter
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -9,4 +10,4 @@ TODO Page Description
|
||||
## With inline actions and expandable sidebar filters
|
||||
```html{.example}
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
---
|
||||
title: E-commerce - Category Preview
|
||||
title: Category Preview
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Three Column (WIP)
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Order History
|
||||
title: Order History
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -10,4 +11,4 @@ TODO Page Description
|
||||
|
||||
```html{.example}
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Product List
|
||||
title: Product List
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -9,4 +10,4 @@ TODO Page Description
|
||||
## With split image
|
||||
```html{.example}
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Product Detail
|
||||
title: Product Detail
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Product Lists
|
||||
title: Product Lists
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
title: E-commerce - Product Reviews
|
||||
title: Product Reviews
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
---
|
||||
title: E-commerce - Shopping Cart
|
||||
title: Shopping Cart
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
parent: ecommerce
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: E-commerce
|
||||
description: TODO
|
||||
layout: page
|
||||
tags: e-commerce
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Business
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Entertainment
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: Patterns
|
||||
description: Browse the library of customizable, framework-friendly web components included in Web Awesome.
|
||||
layout: page-outline
|
||||
---
|
||||
8
docs/docs/patterns/index.njk
Normal file
8
docs/docs/patterns/index.njk
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Patterns
|
||||
description: Patterns are reusable solutions to common design problems.
|
||||
layout: overview
|
||||
categories: ["e-commerce"]
|
||||
listChildren: true
|
||||
override:tags: []
|
||||
---
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Membership
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
title: News
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -157,4 +156,4 @@ TODO Page Description
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Non-profit
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
5
docs/docs/patterns/patterns.json
Normal file
5
docs/docs/patterns/patterns.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"layout": "block.njk",
|
||||
"tags": ["patterns"],
|
||||
"noAlpha": true
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Portfolio
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
title: Product Landing
|
||||
description: TODO
|
||||
layout: pattern.njk
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
|
||||
@@ -14,6 +14,8 @@ During the alpha period, things might break! We take breaking changes very serio
|
||||
|
||||
## Next
|
||||
|
||||
- Simplified the internal structure and CSS properties of `<wa-card>`, removed `base` part.
|
||||
- Added `appearance` to `<wa-callout>` and `<wa-tag>`
|
||||
- Fixed a bug in `<wa-switch>` where it would not properly change its "checked" state when its property changed.
|
||||
- Fixed a bug in the `wa-split` CSS utility that caused it to behave incorrectly
|
||||
- Improved performance of `<wa-select>` when using a large number of options
|
||||
@@ -147,4 +149,4 @@ Here's a list of some of the things that have changed since Shoelace v2. For que
|
||||
|
||||
Did we miss something? [Let us know!](https://github.com/shoelace-style/webawesome-alpha/discussions)
|
||||
|
||||
Are you coming from Shoelace? [The 2.x changelog can be found here.](https://shoelace.style/resources/changelog/)
|
||||
Are you coming from Shoelace? [The 2.x changelog can be found here.](https://shoelace.style/resources/changelog/)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Component Groups
|
||||
description: Style groups of components that share similar qualities with these Web Awesome custom properties.
|
||||
order: 9999
|
||||
---
|
||||
|
||||
For components that share similar qualities, Web Awesome includes custom properties to change the appearance of these related components all at once.
|
||||
@@ -49,7 +50,7 @@ Not every form control uses all of these custom properties. For example, `<wa-ra
|
||||
</wa-radio-group>
|
||||
<wa-checkbox>Checkbox</wa-checkbox>
|
||||
<wa-switch>Switch</wa-switch>
|
||||
<wa-range label="Range"></wa-range>
|
||||
<wa-slider label="Range"></wa-slider>
|
||||
<wa-button>Button</wa-button>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
---
|
||||
title: Theming
|
||||
description: Browse the library of customizable, framework-friendly web components included in Web Awesome.
|
||||
---
|
||||
|
||||
<p class="index-summary">A theme is a collection of pre-defined CSS custom properties that control global styles from color to shadows. These custom properties thread through all Web Awesome components for a consistent look and feel.</p>
|
||||
|
||||
<div class="index-grid">
|
||||
<a href="/docs/theming/color">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/color.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Color</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/typography">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/typography.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Typography</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/space">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/space.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Space</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/borders">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/borders.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Borders</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/focus">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/focus.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Focus</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/shadows">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/shadows.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Shadows</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/transitions">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/transitions.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Transitions</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
<a href="/docs/theming/component-groups">
|
||||
<wa-card with-header>
|
||||
<div slot="header">
|
||||
{% include "svgs/theming/component-groups.njk" %}
|
||||
</div>
|
||||
<span class="page-name">Component Groups</span>
|
||||
</wa-card>
|
||||
</a>
|
||||
</div>
|
||||
6
docs/docs/theming/index.njk
Normal file
6
docs/docs/theming/index.njk
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Theming
|
||||
description: A theme is a collection of pre-defined CSS custom properties that control global styles from color to shadows. These custom properties thread through all Web Awesome components for a consistent look and feel.
|
||||
layout: overview
|
||||
override:tags: []
|
||||
---
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"layout": "page-outline.njk",
|
||||
"tags": ["theming"]
|
||||
"tags": ["theming"],
|
||||
"eleventyComputed": {
|
||||
"icon": "theming/{{ page.fileSlug }}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
title: Appearance Variants
|
||||
description: Appearance utilities apply a collection of properties to achieve certain effects, like making elements accented, outlined, filled, or plain.
|
||||
classes:
|
||||
- wa-accent
|
||||
- wa-outlined
|
||||
- wa-filled
|
||||
- wa-plain
|
||||
snippets:
|
||||
- .wa-accent
|
||||
- .wa-outlined
|
||||
- .wa-filled
|
||||
- .wa-plain
|
||||
---
|
||||
|
||||
Some Web Awesome components, like `<wa-button>`, allow you to change their overall style by using an `appearance` attribute:
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
title: Color Variants
|
||||
description: Color utilities allow you to apply the brand, neutral, success, warning, and danger colors from your theme to any element.
|
||||
icon: theming/color
|
||||
classes:
|
||||
- wa-brand
|
||||
- wa-neutral
|
||||
- wa-success
|
||||
- wa-warning
|
||||
- wa-danger
|
||||
snippets:
|
||||
- .wa-brand
|
||||
- .wa-neutral
|
||||
- .wa-success
|
||||
- .wa-warning
|
||||
- .wa-danger
|
||||
---
|
||||
|
||||
Some Web Awesome components, like `<wa-button>`, allow you to change the color by using a `variant` attribute:
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
title: Style Utilities
|
||||
description: Web Awesome provides a few style utilities to customize styles in ways that cannot necessarily be described by semantic HTML.
|
||||
Some of these correspond to component attributes, but we also expose utility classes so you can apply these styles to native elements too.
|
||||
layout: page-outline
|
||||
override:tags: []
|
||||
layout: overview
|
||||
categories: ["layout"]
|
||||
override:tags: []
|
||||
---
|
||||
|
||||
{% set allPages = collections.utilities %}
|
||||
{% include "grouped-pages.njk" %}
|
||||
|
||||
<br> {# Temp fix for spacing issue #}
|
||||
|
||||
{% markdown %}
|
||||
## Installation
|
||||
|
||||
To use all Web Awesome page styles (including [native styles](/docs/native/)), include the following stylesheet in your project:
|
||||
@@ -27,3 +23,4 @@ Or, to _only_ include utilities:
|
||||
```
|
||||
|
||||
You can also include individual utilities following the instructions in their pages.
|
||||
{% endmarkdown %}
|
||||
@@ -3,10 +3,10 @@ title: Size
|
||||
description: Size utilities give elements one of three preset sizes (small, medium, or large).
|
||||
icon: theming/space
|
||||
status: experimental
|
||||
classes:
|
||||
- wa-size-s
|
||||
- wa-size-m
|
||||
- wa-size-l
|
||||
snippets:
|
||||
- .wa-size-s
|
||||
- .wa-size-m
|
||||
- .wa-size-l
|
||||
---
|
||||
|
||||
Some Web Awesome components, like `<wa-button>`, allow you to change their size to one of three presets: `small`, `medium`, and `large` by using a `size` attribute:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"layout": "utilities",
|
||||
"layout": "block",
|
||||
"tags": ["utilities"]
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
title: Visually Hidden
|
||||
description: The visually hidden utility makes content accessible to assistive devices without displaying it on the screen.
|
||||
icon: visually-hidden
|
||||
classes:
|
||||
- wa-visually-hidden
|
||||
- wa-visually-hidden-force
|
||||
snippets:
|
||||
- .wa-visually-hidden
|
||||
- .wa-visually-hidden-force
|
||||
---
|
||||
|
||||
> "there are real world situations where visually hiding content may be appropriate, while the content should remain available to assistive technologies, such as screen readers. For instance, hiding a search field's label as a common magnifying glass icon is used in its stead."
|
||||
|
||||
@@ -3,8 +3,6 @@ import { html } from 'lit';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import type WaAvatar from './avatar.js';
|
||||
|
||||
// The default avatar background just misses AA contrast, but the next step up is way too dark. Since avatars aren't
|
||||
// used to display text, we're going to relax this rule.
|
||||
const ignoredRules = ['color-contrast'];
|
||||
|
||||
describe('<wa-avatar>', () => {
|
||||
@@ -22,9 +20,7 @@ describe('<wa-avatar>', () => {
|
||||
});
|
||||
|
||||
it('should default to circle styling', () => {
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(el.getAttribute('shape')).to.eq('circle');
|
||||
expect(part.classList.value.trim()).to.eq('avatar avatar--circle');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,25 +32,12 @@ describe('<wa-avatar>', () => {
|
||||
});
|
||||
|
||||
it('should pass accessibility tests', async () => {
|
||||
/**
|
||||
* The image element itself is ancillary, because it's parent container contains the
|
||||
* aria-label which dictates what "wa-avatar" is. This also implies that label text will
|
||||
* resolve to "" when not provided and ignored by readers. This is why we use alt="" on
|
||||
* the image element to pass accessibility.
|
||||
* https://html.spec.whatwg.org/multipage/images.html#ancillary-images
|
||||
*/
|
||||
await expect(el).to.be.accessible({ ignoredRules });
|
||||
});
|
||||
|
||||
it('renders "image" part, with src and a role of presentation', () => {
|
||||
it('renders "image" part with src and proper aria-label', () => {
|
||||
const part = el.shadowRoot!.querySelector('[part~="image"]')!;
|
||||
|
||||
expect(part.getAttribute('src')).to.eq(image);
|
||||
});
|
||||
|
||||
it('renders the label attribute in the "base" part', () => {
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
|
||||
expect(part.getAttribute('aria-label')).to.eq(label);
|
||||
});
|
||||
});
|
||||
@@ -69,50 +52,10 @@ describe('<wa-avatar>', () => {
|
||||
await expect(el).to.be.accessible({ ignoredRules });
|
||||
});
|
||||
|
||||
it('renders "initials" part, with initials as the text node', () => {
|
||||
it('renders "initials" part with initials and proper aria-label', () => {
|
||||
const part = el.shadowRoot!.querySelector<HTMLElement>('[part~="initials"]')!;
|
||||
|
||||
expect(part.innerText).to.eq(initials);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when image is present, the initials or icon part should not render', () => {
|
||||
const initials = 'SL';
|
||||
const image = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
const label = 'Small transparent square';
|
||||
beforeEach(async () => {
|
||||
el = await fixture<WaAvatar>(
|
||||
html`<wa-avatar image="${image}" label="${label}" initials="${initials}"></wa-avatar>`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should pass accessibility tests', async () => {
|
||||
/**
|
||||
* The image element itself is ancillary, because it's parent container contains the
|
||||
* aria-label which dictates what "wa-avatar" is. This also implies that label text will
|
||||
* resolve to "" when not provided and ignored by readers. This is why we use alt="" on
|
||||
* the image element to pass accessibility.
|
||||
* https://html.spec.whatwg.org/multipage/images.html#ancillary-images
|
||||
*/
|
||||
await expect(el).to.be.accessible({ ignoredRules });
|
||||
});
|
||||
|
||||
it('renders "image" part, with src and a role of presentation', () => {
|
||||
const part = el.shadowRoot!.querySelector('[part~="image"]')!;
|
||||
|
||||
expect(part.getAttribute('src')).to.eq(image);
|
||||
});
|
||||
|
||||
it('should not render the initials part', () => {
|
||||
const part = el.shadowRoot!.querySelector<HTMLElement>('[part~="initials"]')!;
|
||||
|
||||
expect(part).to.not.exist;
|
||||
});
|
||||
|
||||
it('should not render the icon part', () => {
|
||||
const slot = el.shadowRoot!.querySelector<HTMLSlotElement>('slot[name=icon]')!;
|
||||
|
||||
expect(slot).to.not.exist;
|
||||
expect(part.getAttribute('aria-label')).to.eq('Avatar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -126,11 +69,8 @@ describe('<wa-avatar>', () => {
|
||||
await expect(el).to.be.accessible({ ignoredRules });
|
||||
});
|
||||
|
||||
it('appends the appropriate class on the "base" part', () => {
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
|
||||
it('reflects the shape attribute', () => {
|
||||
expect(el.getAttribute('shape')).to.eq(shape);
|
||||
expect(part.classList.value.trim()).to.eq(`avatar avatar--${shape}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -149,11 +89,8 @@ describe('<wa-avatar>', () => {
|
||||
it('should accept as an assigned child in the shadow root', () => {
|
||||
const slot = el.shadowRoot!.querySelector<HTMLSlotElement>('slot[name=icon]')!;
|
||||
const childNodes = slot.assignedNodes({ flatten: true }) as HTMLElement[];
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
|
||||
const span = childNodes[0];
|
||||
expect(span.innerHTML).to.eq('random content');
|
||||
expect(childNodes[0].innerHTML).to.eq('random content');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -161,11 +98,9 @@ describe('<wa-avatar>', () => {
|
||||
el = await fixture<WaAvatar>(html`<wa-avatar></wa-avatar>`);
|
||||
el.image = 'bad_image';
|
||||
|
||||
await aTimeout(0);
|
||||
await el.updateComplete;
|
||||
|
||||
await waitUntil(() => el.shadowRoot!.querySelector('img') === null);
|
||||
expect(el.shadowRoot!.querySelector('img')).to.be.null;
|
||||
await waitUntil(() => el.shadowRoot?.querySelector('img') === null);
|
||||
expect(el.shadowRoot?.querySelector('img')).to.be.null;
|
||||
});
|
||||
|
||||
it('should show a valid image after being passed an invalid image initially', async () => {
|
||||
@@ -173,7 +108,6 @@ describe('<wa-avatar>', () => {
|
||||
|
||||
await aTimeout(0);
|
||||
await el.updateComplete;
|
||||
// await waitUntil(() => el.shadowRoot!.querySelector('img') === null);
|
||||
expect(el.shadowRoot!.querySelector('img')).to.be.null;
|
||||
|
||||
el.image = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
|
||||
@@ -66,7 +66,7 @@ export default class WaAvatar extends WebAwesomeElement {
|
||||
class="image"
|
||||
src="${this.image}"
|
||||
loading="${this.loading}"
|
||||
alt=""
|
||||
role="img"
|
||||
aria-label=${this.label}
|
||||
@error="${this.handleImageLoadError}"
|
||||
/>
|
||||
|
||||
@@ -3,8 +3,6 @@ import { html } from 'lit';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import type WaBadge from './badge.js';
|
||||
|
||||
// The default badge background just misses AA contrast, but the next step up is way too dark. We're going to relax this
|
||||
// rule for now.
|
||||
const ignoredRules = ['color-contrast'];
|
||||
|
||||
describe('<wa-badge>', () => {
|
||||
@@ -16,7 +14,7 @@ describe('<wa-badge>', () => {
|
||||
expect(el.innerText).to.eq('Badge');
|
||||
});
|
||||
|
||||
it('should pass accessibility tests with a role of status on the base part.', async () => {
|
||||
it('should pass accessibility tests with a role of status on the base part', async () => {
|
||||
const el = await fixture<WaBadge>(html` <wa-badge>Badge</wa-badge> `);
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(part.getAttribute('role')).to.eq('status');
|
||||
@@ -25,8 +23,7 @@ describe('<wa-badge>', () => {
|
||||
|
||||
it('should default to square styling, with the brand color', async () => {
|
||||
const el = await fixture<WaBadge>(html` <wa-badge>Badge</wa-badge> `);
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--brand');
|
||||
expect(el.getAttribute('variant')).to.eq('brand');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,10 +33,9 @@ describe('<wa-badge>', () => {
|
||||
await expect(el).to.be.accessible({ ignoredRules });
|
||||
});
|
||||
|
||||
it('should append the pill class to the classlist to render a pill', async () => {
|
||||
it('should have the pill attribute', async () => {
|
||||
const el = await fixture<WaBadge>(html` <wa-badge pill>Badge</wa-badge> `);
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--brand badge--pill');
|
||||
expect(el.hasAttribute('pill')).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,10 +46,9 @@ describe('<wa-badge>', () => {
|
||||
await aTimeout(1);
|
||||
});
|
||||
|
||||
it('should append the pulse class to the classlist to render a pulse', async () => {
|
||||
it('should have the pulse attribute', async () => {
|
||||
const el = await fixture<WaBadge>(html` <wa-badge pulse>Badge</wa-badge> `);
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--brand badge--pulse');
|
||||
expect(el.hasAttribute('pulse')).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,10 +60,9 @@ describe('<wa-badge>', () => {
|
||||
await aTimeout(1);
|
||||
});
|
||||
|
||||
it('should default to square styling, with the correct color', async () => {
|
||||
it('should have the correct variant attribute', async () => {
|
||||
const el = await fixture<WaBadge>(html`<wa-badge variant="${variant}">Badge</wa-badge>`);
|
||||
const part = el.shadowRoot!.querySelector('[part~="base"]')!;
|
||||
expect(part.classList.value.trim()).to.eq(`badge badge--${variant}`);
|
||||
expect(el.getAttribute('variant')).to.eq(variant);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('<wa-button>', () => {
|
||||
|
||||
expect(el.title).to.equal('');
|
||||
expect(el.variant).to.equal('neutral');
|
||||
expect(el.appearance).to.equal('filled');
|
||||
expect(el.appearance).to.equal('accent');
|
||||
expect(el.size).to.equal('medium');
|
||||
expect(el.disabled).to.equal(false);
|
||||
expect(el.caret).to.equal(false);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { WaFocusEvent } from '../../events/focus.js';
|
||||
import { WaInvalidEvent } from '../../events/invalid.js';
|
||||
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import nativeStyles from '../../styles/native/button.css';
|
||||
import appearanceStyles from '../../styles/utilities/appearance.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
align-items: stretch;
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
background-color: var(--background-color, var(--wa-color-fill-quiet));
|
||||
border-color: var(--border-color, var(--wa-color-border-quiet));
|
||||
border-color: var(--border-color, transparent);
|
||||
border-style: var(--wa-panel-border-style);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
color: var(--text-color, var(--wa-color-on-normal));
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
:host([appearance~='accent']) {
|
||||
font-weight: var(--wa-font-weight-semibold);
|
||||
}
|
||||
|
||||
[part~='icon'] {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import appearanceStyles from '../../styles/utilities/appearance.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
import styles from './callout.css';
|
||||
|
||||
@@ -22,11 +24,23 @@ import styles from './callout.css';
|
||||
*/
|
||||
@customElement('wa-callout')
|
||||
export default class WaCallout extends WebAwesomeElement {
|
||||
static shadowStyle = [variantStyles, styles];
|
||||
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, styles];
|
||||
|
||||
/** The callout's theme variant. */
|
||||
@property({ reflect: true }) variant: 'brand' | 'success' | 'neutral' | 'warning' | 'danger' = 'brand';
|
||||
|
||||
/** The callout's visual appearance. */
|
||||
@property({ reflect: true }) appearance:
|
||||
| 'accent'
|
||||
| 'filled'
|
||||
| 'outlined'
|
||||
| 'plain'
|
||||
| 'outlined filled'
|
||||
| 'outlined accent' = 'outlined filled';
|
||||
|
||||
/** The callout's size. */
|
||||
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div part="icon">
|
||||
|
||||
@@ -1,45 +1,30 @@
|
||||
:host {
|
||||
--background-color: var(--wa-color-surface-default);
|
||||
--border-color: var(--wa-color-surface-border);
|
||||
--border-radius: var(--wa-panel-border-radius);
|
||||
--border-style: var(--wa-panel-border-style);
|
||||
--border-width: var(--wa-panel-border-width);
|
||||
--box-shadow: var(--wa-shadow-s);
|
||||
--spacing: var(--wa-space-xl);
|
||||
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--background-color);
|
||||
border-color: var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
border-style: var(--border-style);
|
||||
border-width: var(--border-width);
|
||||
box-shadow: var(--box-shadow);
|
||||
background-color: var(--wa-color-surface-default);
|
||||
border-color: var(--wa-color-surface-border);
|
||||
border-radius: var(--wa-panel-border-radius);
|
||||
border-style: var(--wa-panel-border-style);
|
||||
border-width: var(--wa-panel-border-width);
|
||||
box-shadow: var(--wa-shadow-s);
|
||||
color: var(--wa-color-text-normal);
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.image {
|
||||
display: flex;
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
border-top-left-radius: inherit;
|
||||
border-top-right-radius: inherit;
|
||||
margin: calc(-1 * var(--border-width));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image::slotted(img) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
.card:not(.card--has-image) .image {
|
||||
display: none;
|
||||
&::slotted(img) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -48,13 +33,9 @@
|
||||
padding: calc(var(--spacing) / 2) var(--spacing);
|
||||
}
|
||||
|
||||
.card:not(.card--has-header) .header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card:not(.card--has-image) .header {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
:host(:not([with-image])) .header {
|
||||
border-top-left-radius: inherit;
|
||||
border-top-right-radius: inherit;
|
||||
}
|
||||
|
||||
.body {
|
||||
@@ -62,14 +43,16 @@
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
.card--has-footer .footer {
|
||||
.footer {
|
||||
display: block;
|
||||
border-top: inherit;
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
border-bottom-right-radius: var(--border-radius);
|
||||
border-bottom-left-radius: inherit;
|
||||
border-bottom-right-radius: inherit;
|
||||
padding: var(--spacing);
|
||||
}
|
||||
|
||||
.card:not(.card--has-footer) .footer {
|
||||
:host(:not([with-header])) .header,
|
||||
:host(:not([with-footer])) .footer,
|
||||
:host(:not([with-image])) .image {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -22,14 +22,6 @@ describe('<wa-card>', () => {
|
||||
`);
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should contain the class card.', async () => {
|
||||
const el = await fixture<WaCard>(html`
|
||||
<wa-card>This is just a basic card. No image, no header, and no footer. Just your content.</wa-card>
|
||||
`);
|
||||
const card = el.shadowRoot!.querySelector('.card')!;
|
||||
expect(card.classList.value.trim()).to.eq('card');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "header" to render a header', () => {
|
||||
@@ -76,17 +68,6 @@ describe('<wa-card>', () => {
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-header.', async () => {
|
||||
const el = await fixture<WaCard>(
|
||||
html`<wa-card with-header>
|
||||
<div slot="header">Header Title</div>
|
||||
This card has a header. You can put all sorts of things in it!
|
||||
</wa-card>`,
|
||||
);
|
||||
const card = el.shadowRoot!.querySelector('.card')!;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-header');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "footer" to render a footer', () => {
|
||||
@@ -137,19 +118,6 @@ describe('<wa-card>', () => {
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-footer.', async () => {
|
||||
const el = await fixture<WaCard>(
|
||||
html`<wa-card with-footer>
|
||||
This card has a footer. You can put all sorts of things in it!
|
||||
|
||||
<div slot="footer">Footer Content</div>
|
||||
</wa-card>`,
|
||||
);
|
||||
|
||||
const card = el.shadowRoot!.querySelector('.card')!;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-footer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "image" to render a image', () => {
|
||||
@@ -201,22 +169,6 @@ describe('<wa-card>', () => {
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-image.', async () => {
|
||||
const el = await fixture<WaCard>(
|
||||
html`<wa-card with-image>
|
||||
<img
|
||||
slot="image"
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="A kitten walks towards camera on top of pallet."
|
||||
/>
|
||||
This is a kitten, but not just any kitten. This kitten likes walking along pallets.
|
||||
</wa-card>`,
|
||||
);
|
||||
|
||||
const card = el.shadowRoot!.querySelector('.card')!;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-image');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './card.css';
|
||||
|
||||
@@ -15,49 +14,32 @@ import styles from './card.css';
|
||||
* @slot footer - An optional footer for the card.
|
||||
* @slot image - An optional image to render at the start of the card.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart image - The container that wraps the card's image.
|
||||
* @csspart header - The container that wraps the card's header.
|
||||
* @csspart body - The container that wraps the card's main content.
|
||||
* @csspart footer - The container that wraps the card's footer.
|
||||
*
|
||||
* @cssproperty --background-color - The card's background color.
|
||||
* @cssproperty --border-color - The card's border color, including borders that occur inside the card.
|
||||
* @cssproperty --border-radius - The radius for the card's corners. Expects a single value.
|
||||
* @cssproperty --border-style - The style of the card's borders.
|
||||
* @cssproperty --border-width - The width of the card's borders. Expects a single value.
|
||||
* @cssproperty --box-shadow - The shadow effects around the edges of the card.
|
||||
* @cssproperty --spacing - The amount of space around and between sections of the card. Expects a single value.
|
||||
*/
|
||||
@customElement('wa-card')
|
||||
export default class WaCard extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
|
||||
/** Renders the card with a header */
|
||||
/** Renders the card with a header. Only needed for SSR, otherwise is automatically added. */
|
||||
@property({ attribute: 'with-header', type: Boolean }) withHeader = false;
|
||||
|
||||
/** Renders the card with an image */
|
||||
/** Renders the card with an image. Only needed for SSR, otherwise is automatically added. */
|
||||
@property({ attribute: 'with-image', type: Boolean }) withImage = false;
|
||||
|
||||
/** Renders the card with a footer */
|
||||
/** Renders the card with a footer. Only needed for SSR, otherwise is automatically added. */
|
||||
@property({ attribute: 'with-footer', type: Boolean }) withFooter = false;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
card: true,
|
||||
'card--has-footer': this.withFooter,
|
||||
'card--has-image': this.withImage,
|
||||
'card--has-header': this.withHeader,
|
||||
})}
|
||||
>
|
||||
<slot name="image" part="image" class="image"></slot>
|
||||
<slot name="header" part="header" class="header"></slot>
|
||||
<slot part="body" class="body"></slot>
|
||||
<slot name="footer" part="footer" class="footer"></slot>
|
||||
</div>
|
||||
<slot name="image" part="image" class="image"></slot>
|
||||
<slot name="header" part="header" class="header"></slot>
|
||||
<slot part="body" class="body"></slot>
|
||||
<slot name="footer" part="footer" class="footer"></slot>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('<wa-carousel>', () => {
|
||||
});
|
||||
|
||||
describe('and user clicks on a pagination button', () => {
|
||||
it('should scroll the carousel to the nth slide', async () => {
|
||||
it.skip('should scroll the carousel to the nth slide', async () => {
|
||||
// Arrange
|
||||
const el = await fixture<WaCarousel>(html`
|
||||
<wa-carousel pagination>
|
||||
@@ -215,7 +215,7 @@ describe('<wa-carousel>', () => {
|
||||
const paginationItem = el.shadowRoot!.querySelectorAll('.pagination-item')[2] as HTMLElement;
|
||||
await clickOnElement(paginationItem);
|
||||
|
||||
expect(el.goToSlide).to.have.been.calledWith(2);
|
||||
expect(el.goToSlide).to.have.been.calledWith(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,7 +110,7 @@ describe('<wa-checkbox>', () => {
|
||||
// See: https://github.com/shoelace-style/shoelace/issues/1169
|
||||
//
|
||||
const el = await fixture<WaCheckbox>(html` <wa-checkbox></wa-checkbox> `);
|
||||
const label = el.shadowRoot!.querySelector('.checkbox')!;
|
||||
const label = el.shadowRoot!.querySelector('label')!;
|
||||
const input = el.shadowRoot!.querySelector('.input')!;
|
||||
|
||||
const labelPosition = getComputedStyle(label).position;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { WaInputEvent } from '../../events/input.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { RequiredValidator } from '../../internal/validators/required-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import nativeStyles from '../../styles/native/checkbox.css';
|
||||
import formControlStyles from '../../styles/shadow/form-control.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
|
||||
@@ -4,12 +4,12 @@ import { html } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import { clickOnElement, dragElement } from '../../internal/test.js';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import { runFormControlBaseTests } from '../../internal/test/form-control-base-tests.js';
|
||||
// import { runFormControlBaseTests } from '../../internal/test/form-control-base-tests.js';
|
||||
import { serialize } from '../../utilities/form.js';
|
||||
import type WaColorPicker from './color-picker.js';
|
||||
|
||||
describe('<wa-color-picker>', () => {
|
||||
runFormControlBaseTests('wa-color-picker');
|
||||
// runFormControlBaseTests('wa-color-picker');
|
||||
|
||||
for (const fixture of fixtures) {
|
||||
describe(`with "${fixture.type}" rendering`, () => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { clamp } from '../../internal/math.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { RequiredValidator } from '../../internal/validators/required-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import formControlStyles from '../../styles/shadow/form-control.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import visuallyHidden from '../../styles/utilities/visually-hidden.css';
|
||||
|
||||
@@ -196,8 +196,8 @@ describe('<wa-details>', () => {
|
||||
await first.show();
|
||||
await second.show();
|
||||
|
||||
expect(firstBody.clientHeight).to.equal(232); // 200 + 16px + 16px (vertical padding)
|
||||
expect(secondBody.clientHeight).to.equal(432); // 400 + 16px + 16px (vertical padding)
|
||||
expect(firstBody.clientHeight).to.equal(200);
|
||||
expect(secondBody.clientHeight).to.equal(400);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { html, literal } from 'lit/static-html.js';
|
||||
import { WaBlurEvent } from '../../events/blur.js';
|
||||
import { WaFocusEvent } from '../../events/focus.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './icon-button.css';
|
||||
|
||||
|
||||
@@ -170,9 +170,7 @@ describe('<wa-icon>', () => {
|
||||
});
|
||||
|
||||
describe('svg sprite sheets', () => {
|
||||
// For some reason ESLint wants to fail in CI here, but works locally.
|
||||
// TODO: this test is skipped because Bootstrap sprite.svg doesn't seem to be available in CI. Will fix in a future PR. [Konnor]
|
||||
/* eslint-disable */
|
||||
it.skip('Should properly grab an SVG and render it from bootstrap icons', async () => {
|
||||
registerIconLibrary('sprite', {
|
||||
resolver: name => `/docs/assets/images/sprite.svg#${name}`,
|
||||
|
||||
@@ -30,6 +30,7 @@ input {
|
||||
background-color: rgb(118 118 118 / 0); /* ensures proper placeholder styles in webkit's date input */
|
||||
height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
|
||||
padding-block: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input::-webkit-search-decoration,
|
||||
|
||||
@@ -28,45 +28,31 @@ describe('<wa-input>', () => {
|
||||
expect(el.value).to.equal(null);
|
||||
expect(el.defaultValue).to.equal(null);
|
||||
expect(el.title).to.equal('');
|
||||
expect(el.filled).to.be.false;
|
||||
expect(el.pill).to.be.false;
|
||||
expect(el.appearance).to.equal('outlined'); // Added
|
||||
expect(el.pill).to.equal(false);
|
||||
expect(el.label).to.equal('');
|
||||
expect(el.hint).to.equal('');
|
||||
expect(el.clearable).to.be.false;
|
||||
expect(el.passwordToggle).to.be.false;
|
||||
expect(el.passwordVisible).to.be.false;
|
||||
expect(el.noSpinButtons).to.be.false;
|
||||
expect(el.clearable).to.equal(false);
|
||||
expect(el.passwordToggle).to.equal(false);
|
||||
expect(el.passwordVisible).to.equal(false);
|
||||
expect(el.noSpinButtons).to.equal(false);
|
||||
expect(el.placeholder).to.equal('');
|
||||
expect(el.disabled).to.be.false;
|
||||
expect(el.readonly).to.be.false;
|
||||
expect(el.minlength).to.be.undefined;
|
||||
expect(el.maxlength).to.be.undefined;
|
||||
expect(el.min).to.be.undefined;
|
||||
expect(el.max).to.be.undefined;
|
||||
expect(el.step).to.be.undefined;
|
||||
expect(el.pattern).to.be.undefined;
|
||||
expect(el.required).to.be.false;
|
||||
expect(el.autocapitalize).to.be.undefined;
|
||||
expect(el.autocorrect).to.be.undefined;
|
||||
expect(el.autocomplete).to.be.undefined;
|
||||
expect(el.autofocus).to.be.undefined;
|
||||
expect(el.enterkeyhint).to.be.undefined;
|
||||
expect(el.spellcheck).to.be.true;
|
||||
expect(el.inputmode).to.be.undefined;
|
||||
expect(el.disabled).to.equal(false);
|
||||
expect(el.readonly).to.equal(false);
|
||||
});
|
||||
|
||||
it('should have title if title attribute is set', async () => {
|
||||
const el = await fixture<WaInput>(html` <wa-input title="Test"></wa-input> `);
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('[part~="input"]')!;
|
||||
|
||||
await el.updateComplete;
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
||||
expect(input.title).to.equal('Test');
|
||||
});
|
||||
|
||||
it('should be disabled with the disabled attribute', async () => {
|
||||
const el = await fixture<WaInput>(html` <wa-input disabled></wa-input> `);
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('[part~="input"]')!;
|
||||
|
||||
expect(input.disabled).to.be.true;
|
||||
await el.updateComplete;
|
||||
const input = el.shadowRoot!.querySelector<HTMLInputElement>('input')!;
|
||||
expect(input.disabled).to.equal(true);
|
||||
});
|
||||
|
||||
it('should focus the input when clicking on the label', async () => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { WaInputEvent } from '../../events/input.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import nativeStyles from '../../styles/native/input.css';
|
||||
import formControlStyles from '../../styles/shadow/form-control.css';
|
||||
import appearanceStyles from '../../styles/utilities/appearance.css';
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { expect, waitUntil } from '@open-wc/testing';
|
||||
import { aTimeout, expect, waitUntil } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { html } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import type { WaSelectEvent } from '../../events/select.js';
|
||||
import { clickOnElement } from '../../internal/test.js';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import type WaMenuItem from './menu-item.js';
|
||||
|
||||
@@ -143,6 +144,8 @@ describe('<wa-menu-item>', () => {
|
||||
menu.addEventListener('wa-select', selectHandler);
|
||||
|
||||
const submenu = menu.querySelector<WaMenuItem>('wa-menu-item')!;
|
||||
// Sometimes Chrome fails if we dont click before triggering focus.
|
||||
await clickOnElement(submenu);
|
||||
submenu.focus();
|
||||
await menu.updateComplete;
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
@@ -173,6 +176,9 @@ describe('<wa-menu-item>', () => {
|
||||
});
|
||||
|
||||
const outerItem = menu.querySelector<WaMenuItem>('#outer')!;
|
||||
// Silly fix for CI + Chrome to focus properly.
|
||||
await clickOnElement(outerItem);
|
||||
|
||||
outerItem.focus();
|
||||
await menu.updateComplete;
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
|
||||
@@ -35,11 +35,11 @@ describe('<wa-progress-bar>', () => {
|
||||
});
|
||||
|
||||
it('uses the value parameter on the base, as aria-valuenow', () => {
|
||||
expect(base).attribute('aria-valuenow', '25');
|
||||
expect(base.getAttribute('aria-valuenow')).to.equal('25');
|
||||
});
|
||||
|
||||
it('appends a % to the value, and uses it as the the value parameter to determine the width on the "indicator" part', () => {
|
||||
expect(indicator).attribute('style', 'width:25%;');
|
||||
it('uses the value parameter to set the custom property on the indicator', () => {
|
||||
expect(indicator.style.getPropertyValue('--value')).to.equal('25');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,8 +57,8 @@ describe('<wa-progress-bar>', () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should append a progress-bar--indeterminate class to the "base" part.', () => {
|
||||
expect(base.classList.value.trim()).to.eq('progress-bar progress-bar--indeterminate');
|
||||
it('should set the indeterminate attribute on the host', () => {
|
||||
expect(el.hasAttribute('indeterminate')).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export default class WaProgressBar extends WebAwesomeElement {
|
||||
aria-label=${this.label.length > 0 ? this.label : this.localize.term('progress')}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
${this.indeterminate ? 0 : `aria-valuenow="${this.value}"`}
|
||||
aria-valuenow=${this.indeterminate ? '0' : this.value}
|
||||
>
|
||||
<div part="indicator" class="indicator" style="--value: ${this.value}">
|
||||
${!this.indeterminate ? html` <slot part="label" class="label"></slot> ` : ''}
|
||||
|
||||
@@ -23,33 +23,6 @@ describe('<wa-radio-button>', () => {
|
||||
expect(radio1.checked).to.be.true;
|
||||
expect(radio2.checked).to.be.false;
|
||||
});
|
||||
|
||||
it('should receive positional classes from <wa-button-group>', async () => {
|
||||
const radioGroup = await fixture<WaRadioGroup>(html`
|
||||
<wa-radio-group value="1">
|
||||
<wa-radio-button id="radio-1" value="1"></wa-radio-button>
|
||||
<wa-radio-button id="radio-2" value="2"></wa-radio-button>
|
||||
<wa-radio-button id="radio-3" value="3"></wa-radio-button>
|
||||
</wa-radio-group>
|
||||
`);
|
||||
const radio1 = radioGroup.querySelector<WaRadioButton>('#radio-1')!;
|
||||
const radio2 = radioGroup.querySelector<WaRadioButton>('#radio-2')!;
|
||||
const radio3 = radioGroup.querySelector<WaRadioButton>('#radio-3')!;
|
||||
|
||||
await Promise.all([
|
||||
radioGroup.updateComplete,
|
||||
radio1.updateComplete,
|
||||
radio2.updateComplete,
|
||||
radio3.updateComplete,
|
||||
]);
|
||||
|
||||
expect(radio1.classList.contains('button')).to.be.true;
|
||||
expect(radio1.classList.contains('button--first')).to.be.true;
|
||||
expect(radio2.classList.contains('button')).to.be.true;
|
||||
expect(radio2.classList.contains('button--inner')).to.be.true;
|
||||
expect(radio3.classList.contains('button')).to.be.true;
|
||||
expect(radio3.classList.contains('button--last')).to.be.true;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { WaBlurEvent } from '../../events/blur.js';
|
||||
import { WaFocusEvent } from '../../events/focus.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import nativeStyles from '../../styles/native/button.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { uniqueId } from '../../internal/math.js';
|
||||
import { HasSlotController } from '../../internal/slot.js';
|
||||
import { RequiredValidator } from '../../internal/validators/required-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import formControlStyles from '../../styles/shadow/form-control.css';
|
||||
import buttonGroupStyles from '../../styles/utilities/button-group.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
|
||||
import { WaBlurEvent } from '../../events/blur.js';
|
||||
import { WaFocusEvent } from '../../events/focus.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-element.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-formassociated-element.js';
|
||||
import nativeStyles from '../../styles/native/radio.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import '../icon/icon.js';
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
:host([appearance='filled']) {
|
||||
--background-color: var(--wa-color-neutral-fill-quiet);
|
||||
--border-color: var(--background-color);
|
||||
}
|
||||
|
||||
/** The popup */
|
||||
.select {
|
||||
flex: 1 1 auto;
|
||||
@@ -40,16 +35,12 @@
|
||||
min-height: var(--wa-form-control-height);
|
||||
|
||||
:host([size='small']) & {
|
||||
min-height: var(--wa-form-control-height-s);
|
||||
|
||||
&:not(.placeholder-visible *) {
|
||||
padding-block: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
:host([size='large']) & {
|
||||
min-height: var(--wa-form-control-height-l);
|
||||
|
||||
&:not(.placeholder-visible *) {
|
||||
padding-block: 4px;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ describe('<wa-select>', () => {
|
||||
describe(`with "${fixture.type}" rendering`, () => {
|
||||
describe('accessibility', () => {
|
||||
it('should pass accessibility tests when closed', async () => {
|
||||
await customElements.whenDefined('wa-option');
|
||||
const select = await fixture<WaSelect>(html`
|
||||
<wa-select label="Select one">
|
||||
<wa-option value="option-1">Option 1</wa-option>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user