mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-19 07:29:14 +00:00
Compare commits
51 Commits
kj/first-p
...
icon-fetch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b001f144c8 | ||
|
|
8a7a7dc3b0 | ||
|
|
eefa57f61a | ||
|
|
c69cabf413 | ||
|
|
7de111341e | ||
|
|
5558a0f2cd | ||
|
|
de4221365a | ||
|
|
b85e6bcdf3 | ||
|
|
ad539a00f2 | ||
|
|
1559b08a63 | ||
|
|
400db9a608 | ||
|
|
1f280b3b9f | ||
|
|
e9f2104f15 | ||
|
|
ad53a0aa56 | ||
|
|
d94589d113 | ||
|
|
3508bf6339 | ||
|
|
61e65ffcb9 | ||
|
|
d79d753f4c | ||
|
|
6306955c74 | ||
|
|
cff9d56b3f | ||
|
|
9fde4a820e | ||
|
|
34c0b562fe | ||
|
|
f499a932f9 | ||
|
|
85cca22d71 | ||
|
|
c261f25c65 | ||
|
|
ac1d412a8f | ||
|
|
aed28adbe4 | ||
|
|
15b8bde81b | ||
|
|
9ee3fb5d28 | ||
|
|
47aa376c08 | ||
|
|
69ba974a50 | ||
|
|
8dfb411e5e | ||
|
|
a35a8fd2ad | ||
|
|
2503005bbd | ||
|
|
78027170ea | ||
|
|
a20aa48992 | ||
|
|
ac8accd664 | ||
|
|
c571573063 | ||
|
|
e813440315 | ||
|
|
cfc3f181a3 | ||
|
|
7545f04c46 | ||
|
|
38bd6528fe | ||
|
|
2202ea9642 | ||
|
|
58fbcede51 | ||
|
|
971200cc88 | ||
|
|
b75d3b615c | ||
|
|
9d1c47449e | ||
|
|
003fd28cb0 | ||
|
|
2f300d8930 | ||
|
|
f13deb87bb | ||
|
|
deb9fd70b3 |
@@ -36,10 +36,16 @@ const globalData = {
|
||||
},
|
||||
};
|
||||
|
||||
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
|
||||
const passThrough = [...passThroughExtensions.map(ext => 'docs/**/*.' + ext)];
|
||||
|
||||
export default function (eleventyConfig) {
|
||||
/**
|
||||
* If you plan to add or remove any of these extensions, make sure to let either Konnor or Cory know as these passthrough extensions
|
||||
* will also need to be updated in the Web Awesome App.
|
||||
*/
|
||||
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
|
||||
|
||||
const baseDir = process.env.BASE_DIR || 'docs';
|
||||
const passThrough = [...passThroughExtensions.map(ext => path.join(baseDir, '**/*.' + ext))];
|
||||
|
||||
/**
|
||||
* This is the guard we use for now to make sure our final built files dont need a 2nd pass by the server. This keeps us able to still deploy the bare HTML files on Vercel until the app is ready.
|
||||
*/
|
||||
|
||||
9
docs/_data/systemIcons.js
Normal file
9
docs/_data/systemIcons.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { inlined } from '../../dist/components/icon/library.wa.js';
|
||||
|
||||
let { classic } = inlined;
|
||||
let { solid, regular } = classic;
|
||||
|
||||
export default [
|
||||
...Object.entries(solid).map(([name, svg]) => ({ name, family: 'solid', variant: 'solid', svg })),
|
||||
...Object.entries(regular).map(([name, svg]) => ({ name, family: 'regular', variant: 'regular', svg })),
|
||||
];
|
||||
@@ -4,7 +4,6 @@
|
||||
{% include 'head.njk' %}
|
||||
<meta name="theme-color" content="#f36944">
|
||||
|
||||
<script type="module" src="/assets/scripts/code-examples.js"></script>
|
||||
|
||||
<script type="module" src="/assets/scripts/scroll.js"></script>
|
||||
<script type="module" src="/assets/scripts/turbo.js"></script>
|
||||
@@ -20,7 +19,7 @@
|
||||
</head>
|
||||
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
|
||||
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
|
||||
<wa-page view="desktop" disable-navigation-toggle="">
|
||||
<wa-page view="desktop" disable-navigation-toggle="" mobile-breakpoint="1140">
|
||||
<header slot="header" class="wa-split">
|
||||
{# Logo #}
|
||||
<div id="docs-branding">
|
||||
@@ -33,13 +32,13 @@
|
||||
<span class="wa-desktop-only">{% include "logo.njk" %}</span>
|
||||
<span class="wa-mobile-only">{% include "logo-simple.njk" %}</span>
|
||||
</a>
|
||||
<small id="version-number" class="only-desktop">{{ package.version }}</small>
|
||||
<wa-badge variant="warning" appearance="filled" class="only-desktop">Alpha</wa-badge>
|
||||
<small id="version-number" class="wa-desktop-only">{{ package.version }}</small>
|
||||
<wa-badge variant="warning" appearance="filled" class="wa-desktop-only">Alpha</wa-badge>
|
||||
</div>
|
||||
|
||||
<div id="docs-toolbar" class="wa-cluster wa-gap-xs">
|
||||
{# Desktop selectors #}
|
||||
<div class="only-desktop wa-cluster wa-gap-xs">
|
||||
<div class="wa-desktop-only wa-cluster wa-gap-xs">
|
||||
{% include "preset-theme-selector.njk" %}
|
||||
{% include "color-scheme-selector.njk" %}
|
||||
</div>
|
||||
@@ -48,7 +47,7 @@
|
||||
<wa-button id="search-trigger" appearance="outlined" size="small" data-search>
|
||||
<wa-icon slot="prefix" name="magnifying-glass"></wa-icon>
|
||||
Search
|
||||
<kbd slot="suffix" class="only-desktop">/</kbd>
|
||||
<kbd slot="suffix" class="wa-desktop-only">/</kbd>
|
||||
</wa-button>
|
||||
|
||||
{# Login #}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -255,7 +255,7 @@
|
||||
{# Importing #}
|
||||
<h2>Importing</h2>
|
||||
<p>
|
||||
The <a href="/docs/installation/#quick-start-autoloading-via-cdn">autoloader</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
|
||||
The <a href="/docs/#quick-start-autoloading-via-cdn">autoloader</a> is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
|
||||
</p>
|
||||
|
||||
<wa-tab-group label="How would you like to import this component?">
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
{% for h in hues -%}
|
||||
{%- if h !== 'gray' -%}
|
||||
<wa-radio-button id="gray-undertone-{{ h }}" value="{{ h }}" label="{{ h | capitalize }}" style="--color: var(--wa-color-{{ h }})"></wa-radio-button>
|
||||
<wa-tooltip for="gray-undertone-{{ h }}" hoist>
|
||||
<wa-tooltip for="gray-undertone-{{ h }}">
|
||||
{{ h | capitalize }}
|
||||
</wa-tooltip>
|
||||
{%- endif -%}
|
||||
@@ -141,7 +141,7 @@
|
||||
@input="tweaking.grayChroma = true" @change="tweaking.grayChroma = false">
|
||||
<div slot="label">
|
||||
Gray colorfulness
|
||||
<wa-icon-button @click="grayChroma = originalGrayChroma" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
|
||||
<wa-icon-button @click="grayChroma = originalGrayChroma" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
|
||||
</div>
|
||||
</wa-slider>
|
||||
<div class="label-min">Neutral</div>
|
||||
@@ -160,7 +160,7 @@
|
||||
@change="tweaking.hue = tweaking.{{ hue }} = false">
|
||||
<div slot="label">
|
||||
Tweak {{ hue }} hue
|
||||
<wa-icon-button @click="hueShifts.{{ hue }} = 0" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
|
||||
<wa-icon-button @click="hueShifts.{{ hue }} = 0" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
|
||||
</div>
|
||||
</wa-slider>
|
||||
<div class="label-min">More {{hueBefore}}</div>
|
||||
@@ -204,7 +204,7 @@ style="--min: {{ chromaScaleBounds[0] }}; --max: {{ chromaScaleBounds[1] }};">
|
||||
@change="tweaking.chroma = false">
|
||||
<div slot="label">
|
||||
Overall colorfulness
|
||||
<wa-icon-button @click="chromaScale = 1" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
|
||||
<wa-icon-button @click="chromaScale = 1" class="clear-button" name="system:circle-xmark" variant="regular" label="Reset"></wa-icon-button>
|
||||
</div>
|
||||
</wa-slider>
|
||||
<div class="label-min">More muted</div>
|
||||
|
||||
@@ -25,8 +25,8 @@ wa_data.palettes = {
|
||||
{% endfor %}
|
||||
};
|
||||
</script>
|
||||
<link href="{{ page.url }}../remix.css" rel="stylesheet">
|
||||
<script src="{{ page.url }}../remix.js" type="module"></script>
|
||||
<link href="/docs/themes/remix.css" rel="stylesheet">
|
||||
<script src="/docs/themes/remix.js" type="module"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
|
||||
@@ -102,12 +102,7 @@ const templates = {
|
||||
export function codeExamplesPlugin(eleventyConfig, options = {}) {
|
||||
const defaultOptions = {
|
||||
container: 'body',
|
||||
defaultOpen: (code, { outputPathIndex }) => {
|
||||
return (
|
||||
outputPathIndex === 1 && // is first
|
||||
code.textContent.length < 500
|
||||
); // is short
|
||||
},
|
||||
defaultOpen: () => false,
|
||||
};
|
||||
options = { ...defaultOptions, ...options };
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export function copyCodePlugin(eleventyConfig, options = {}) {
|
||||
|
||||
// Add a copy button
|
||||
pre.innerHTML += `<wa-icon-button href="#${preId}" class="block-link-icon" name="link"></wa-icon-button>
|
||||
<wa-copy-button from="${codeId}" class="copy-button" hoist></wa-copy-button>`;
|
||||
<wa-copy-button from="${codeId}" class="copy-button"></wa-copy-button>`;
|
||||
});
|
||||
|
||||
return doc.toString();
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
document.addEventListener('click', event => {
|
||||
const toggle = event.target?.closest('.code-example-toggle');
|
||||
const pen = event.target?.closest('.code-example-pen');
|
||||
|
||||
// Toggle source
|
||||
if (toggle) {
|
||||
const codeExample = toggle.closest('.code-example');
|
||||
const isOpen = !codeExample.classList.contains('open');
|
||||
|
||||
toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||
codeExample.classList.toggle('open', isOpen);
|
||||
}
|
||||
|
||||
// Edit in CodePen
|
||||
if (pen) {
|
||||
const codeExample = pen.closest('.code-example');
|
||||
const code = codeExample.querySelector('code');
|
||||
const cdnUrl = document.documentElement.dataset.cdnUrl;
|
||||
const html =
|
||||
`<script data-fa-kit-code="b10bfbde90" type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
|
||||
`<link rel="stylesheet" href="${cdnUrl}styles/themes/default.css">\n` +
|
||||
`<link rel="stylesheet" href="${cdnUrl}styles/webawesome.css">\n` +
|
||||
`<link rel="stylesheet" href="${cdnUrl}styles/utilities.css">\n\n` +
|
||||
`${code.textContent}`;
|
||||
const css = 'html > body {\n padding: 2rem !important;\n}';
|
||||
const js = '';
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.action = 'https://codepen.io/pen/define';
|
||||
form.method = 'POST';
|
||||
form.target = '_blank';
|
||||
|
||||
const data = {
|
||||
title: '',
|
||||
description: '',
|
||||
tags: ['webawesome'],
|
||||
editors: '1000',
|
||||
head: '<meta name="viewport" content="width=device-width">',
|
||||
html_classes: '',
|
||||
css_external: '',
|
||||
js_external: '',
|
||||
js_module: true,
|
||||
js_pre_processor: 'none',
|
||||
html,
|
||||
css,
|
||||
js,
|
||||
};
|
||||
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'data';
|
||||
input.value = JSON.stringify(data);
|
||||
form.append(input);
|
||||
|
||||
document.documentElement.append(form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
}
|
||||
});
|
||||
@@ -1,34 +1,5 @@
|
||||
let initialPageLoadComplete = document.readyState === 'complete';
|
||||
|
||||
if (!initialPageLoadComplete) {
|
||||
window.addEventListener('load', () => {
|
||||
initialPageLoadComplete = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper for view transitions
|
||||
export function domChange(fn, { behavior = 'smooth', ignoreInitialLoad = true } = {}) {
|
||||
const canUseViewTransitions =
|
||||
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// Skip transitions on initial page load
|
||||
if (!initialPageLoadComplete && ignoreInitialLoad) {
|
||||
fn(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (canUseViewTransitions && behavior === 'smooth') {
|
||||
const transition = document.startViewTransition(() => {
|
||||
fn(true);
|
||||
// Wait a brief delay before finishing the transition to prevent jumpiness
|
||||
return new Promise(resolve => setTimeout(resolve, 200));
|
||||
});
|
||||
return transition;
|
||||
} else {
|
||||
fn(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
import { domChange } from './util/dom-change.js';
|
||||
export { domChange };
|
||||
|
||||
export function nextFrame() {
|
||||
return new Promise(resolve => requestAnimationFrame(resolve));
|
||||
@@ -135,6 +106,6 @@ document.addEventListener('keydown', event => {
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
colorScheme.set(theming.colorScheme.resolvedValue === 'dark' ? 'light' : 'dark');
|
||||
colorScheme.set(colorScheme.get() === 'dark' ? 'light' : 'dark');
|
||||
}
|
||||
});
|
||||
|
||||
37
docs/assets/scripts/util/dom-change.js
Normal file
37
docs/assets/scripts/util/dom-change.js
Normal file
@@ -0,0 +1,37 @@
|
||||
let initialPageLoadComplete = document.readyState === 'complete';
|
||||
|
||||
if (!initialPageLoadComplete) {
|
||||
window.addEventListener('load', () => {
|
||||
initialPageLoadComplete = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for performing a DOM change using a view transition, wherever supported and reduced motion is not desired.
|
||||
* @param {function} fn - Function to perform the DOM change. If async, must resolve when the change is complete.
|
||||
* @param {object} [options] - Options for the transition
|
||||
* @param {'smooth' | 'instant'} [options.behavior] - Transition behavior. Defaults to 'smooth'. 'instant' will skip the transition.
|
||||
* @param {boolean} [options.ignoreInitialLoad] - If true, will skip the transition on initial page load. Defaults to true.
|
||||
*/
|
||||
export function domChange(fn, { behavior = 'smooth', ignoreInitialLoad = true } = {}) {
|
||||
const canUseViewTransitions =
|
||||
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// Skip transitions on initial page load
|
||||
if (!initialPageLoadComplete && ignoreInitialLoad) {
|
||||
fn(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (canUseViewTransitions && behavior === 'smooth') {
|
||||
const transition = document.startViewTransition(() => {
|
||||
fn(true);
|
||||
// Wait a brief delay before finishing the transition to prevent jumpiness
|
||||
return new Promise(resolve => setTimeout(resolve, 200));
|
||||
});
|
||||
return transition;
|
||||
} else {
|
||||
fn(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
.code-example {
|
||||
border: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
color: var(--wa-color-text-normal);
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
}
|
||||
|
||||
.code-example-preview {
|
||||
padding: 2rem;
|
||||
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
|
||||
|
||||
> :first-child {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.code-example-source {
|
||||
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
|
||||
}
|
||||
|
||||
.code-example:not(.open) .code-example-source {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code-example.open .code-example-toggle wa-icon {
|
||||
rotate: 180deg;
|
||||
}
|
||||
|
||||
.code-example-source pre {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.code-example-source:not(:has(+ .code-example-buttons)) {
|
||||
border-bottom: none;
|
||||
|
||||
pre {
|
||||
border-bottom-right-radius: var(--wa-border-radius-l);
|
||||
border-bottom-left-radius: var(--wa-border-radius-l);
|
||||
}
|
||||
}
|
||||
|
||||
.code-example-buttons {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
button {
|
||||
all: unset;
|
||||
flex: 1 0 auto;
|
||||
font-size: 0.875rem;
|
||||
color: var(--wa-color-text-quiet);
|
||||
border-left: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-of-type {
|
||||
border-left: none;
|
||||
border-bottom-left-radius: var(--wa-border-radius-l);
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom-right-radius: var(--wa-border-radius-l);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--wa-focus-ring);
|
||||
}
|
||||
}
|
||||
|
||||
.code-example-pen {
|
||||
flex: 0 0 100px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
wa-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -2px;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
@import 'code-examples.css';
|
||||
@import 'code-highlighter.css';
|
||||
@import 'copy-code.css';
|
||||
@import 'outline.css';
|
||||
@@ -608,13 +607,6 @@ table.colors {
|
||||
margin-block-end: var(--wa-flow-spacing);
|
||||
}
|
||||
|
||||
/** mobile */
|
||||
@media screen and (max-width: 768px) {
|
||||
wa-page .only-desktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/** desktop */
|
||||
@media screen and not (max-width: 768px) {
|
||||
/* Navigation sidebar */
|
||||
|
||||
@@ -167,7 +167,7 @@ Other elements can also be placed inside button groups:
|
||||
<wa-button-group label="Example Button Group">
|
||||
<wa-button>Button</wa-button>
|
||||
<button>Native Button</button>
|
||||
<wa-dropdown hoist>
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret>Dropdown</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>Item 1</wa-menu-item>
|
||||
@@ -185,7 +185,7 @@ Create a split button using a button and a dropdown. Use a [visually hidden](/do
|
||||
```html {.example}
|
||||
<wa-button-group label="Example Button Group">
|
||||
<wa-button variant="brand">Save</wa-button>
|
||||
<wa-dropdown placement="bottom-end" hoist>
|
||||
<wa-dropdown placement="bottom-end">
|
||||
<wa-button slot="trigger" variant="brand" caret>
|
||||
<span class="wa-visually-hidden">More options</span>
|
||||
</wa-button>
|
||||
|
||||
@@ -3,6 +3,7 @@ title: Code Demo
|
||||
description: Code demos can be used to render code examples as inline live demos.
|
||||
tags: component
|
||||
noAlpha: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
---
|
||||
title: Image Comparer
|
||||
description: Compare visual differences between similar photos with a sliding panel.
|
||||
title: Comparer
|
||||
description: Compare visual differences between similar content with a sliding panel.
|
||||
tags: [imagery, niche]
|
||||
icon: image-comparer
|
||||
icon: comparer
|
||||
---
|
||||
|
||||
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
This is especially useful for comparing images, but can be used for comparing any type of content (for an example of using it to compare entire UIs, check out our [theme pages](/docs/themes/default/)).
|
||||
For best results, use content that shares the same dimensions.
|
||||
The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
|
||||
|
||||
```html {.example}
|
||||
<wa-image-comparer>
|
||||
<wa-comparer>
|
||||
<img
|
||||
slot="before"
|
||||
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&sat=-100&bri=-5"
|
||||
@@ -19,7 +21,7 @@ For best results, use images that share the same dimensions. The slider can be c
|
||||
src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80"
|
||||
alt="Color version of kittens in a basket looking around."
|
||||
/>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -29,7 +31,7 @@ For best results, use images that share the same dimensions. The slider can be c
|
||||
Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`.
|
||||
|
||||
```html {.example}
|
||||
<wa-image-comparer position="25">
|
||||
<wa-comparer position="25">
|
||||
<img
|
||||
slot="before"
|
||||
src="https://images.unsplash.com/photo-1520903074185-8eca362b3dce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80"
|
||||
@@ -40,5 +42,5 @@ Use the `position` attribute to set the initial position of the slider. This is
|
||||
src="https://images.unsplash.com/photo-1520640023173-50a135e35804?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80"
|
||||
alt="A person sitting on a yellow curb tying shoelaces on a boot."
|
||||
/>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
```
|
||||
@@ -88,10 +88,10 @@ You can add the special `data-dialog="close"` attribute to a button inside the d
|
||||
|
||||
### Custom Width
|
||||
|
||||
Just use the CSS `width` property to set the dialog's width.
|
||||
Just use the `--width` custom property to set the dialog's width.
|
||||
|
||||
```html {.example}
|
||||
<wa-dialog label="Dialog" with-header with-footer class="dialog-width" style="width: 50vw;">
|
||||
<wa-dialog label="Dialog" with-header with-footer class="dialog-width" style="--width: 50vw;">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<wa-button slot="footer" variant="brand" data-dialog="close">Close</wa-button>
|
||||
</wa-dialog>
|
||||
|
||||
@@ -180,38 +180,3 @@ To create a submenu, nest an `<wa-menu slot="submenu">` element in a [menu item]
|
||||
:::warning
|
||||
As a UX best practice, avoid using more than one level of submenu when possible.
|
||||
:::
|
||||
|
||||
### Hoisting
|
||||
|
||||
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
|
||||
|
||||
```html {.example}
|
||||
<div class="dropdown-hoist">
|
||||
<wa-dropdown>
|
||||
<wa-button slot="trigger" caret>No Hoist</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>Item 1</wa-menu-item>
|
||||
<wa-menu-item>Item 2</wa-menu-item>
|
||||
<wa-menu-item>Item 3</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
|
||||
<wa-dropdown hoist>
|
||||
<wa-button slot="trigger" caret>Hoist</wa-button>
|
||||
<wa-menu>
|
||||
<wa-menu-item>Item 1</wa-menu-item>
|
||||
<wa-menu-item>Item 2</wa-menu-item>
|
||||
<wa-menu-item>Item 3</wa-menu-item>
|
||||
</wa-menu>
|
||||
</wa-dropdown>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dropdown-hoist {
|
||||
position: relative;
|
||||
border: solid 2px var(--wa-color-surface-border);
|
||||
padding: var(--wa-space-m);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
@@ -17,11 +17,94 @@ Not sure which icon to use? [Find the perfect icon over at Font Awesome!](https:
|
||||
|
||||
The default icon library is Font Awesome Free, which comes with two icon families: `classic` and `brands`. Use the `family` attribute to set the icon family.
|
||||
|
||||
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/installation/#using-font-awesome-kit-codes) to unlock additional families, including `sharp` and `duotone`. For these icon families, use the `variant` attribute to set the variant.
|
||||
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/#using-font-awesome-kit-codes) to unlock additional families, including `sharp`, `duotone`, and `sharp-duotone`. For these icon families, use the `variant` attribute to set the variant.
|
||||
|
||||
```html {.example}
|
||||
<wa-icon family="brands" name="font-awesome"></wa-icon>
|
||||
<wa-icon family="brands" name="web-awesome"></wa-icon>
|
||||
<wa-icon family="brands" name="font-awesome"></wa-icon>
|
||||
<wa-icon family="brands" name="web-awesome"></wa-icon>
|
||||
<wa-icon family="classic" variant="light" name="sparkles"></wa-icon>
|
||||
<wa-icon family="sharp" variant="solid" name="fire"></wa-icon>
|
||||
<wa-icon family="duotone" variant="regular" name="cake-slice"></wa-icon>
|
||||
```
|
||||
|
||||
### Setting defaults via CSS
|
||||
|
||||
You can use certain CSS custom properties to set icon defaults, not just on the icon itself, but any ancestor.
|
||||
This can be useful when you want certain parameters to vary based on context, e.g. icons inside callouts or all icons for a given theme.
|
||||
|
||||
:::warning
|
||||
These CSS properties are intended to set **defaults**, and thus only make a difference when the corresponding attributes are not set.
|
||||
In future versions of Web Awesome, we may change this behavior to allow CSS properties to override attributes if `!important` is used.
|
||||
:::
|
||||
|
||||
For example, here is how you can use CSS custom properties to set a default icon for each type of callout:
|
||||
|
||||
```html {.example}
|
||||
<wa-callout>
|
||||
<!-- Look ma, no attributes! -->
|
||||
<wa-icon slot="icon"></wa-icon>
|
||||
This is a normal callout.
|
||||
</wa-callout>
|
||||
|
||||
<wa-callout variant="danger">
|
||||
<wa-icon slot="icon" name="dumpster-fire" variant="solid"></wa-icon>
|
||||
This is a callout with an explicit icon, which overrides these defaults.
|
||||
</wa-callout>
|
||||
|
||||
<wa-callout variant="warning">
|
||||
<!-- Look ma, no attributes! -->
|
||||
<wa-icon slot="icon"></wa-icon>
|
||||
Here be dragons.
|
||||
</wa-callout>
|
||||
|
||||
<wa-callout variant="danger">
|
||||
<!-- Look ma, no attributes! -->
|
||||
<wa-icon slot="icon"></wa-icon>
|
||||
Here be more dragons.
|
||||
</wa-callout>
|
||||
|
||||
<wa-callout variant="success">
|
||||
<!-- Look ma, no attributes! -->
|
||||
<wa-icon slot="icon"></wa-icon>
|
||||
Success!
|
||||
</wa-callout>
|
||||
|
||||
<style>
|
||||
wa-callout {
|
||||
--wa-icon-variant: regular;
|
||||
--wa-icon-name: info-circle;
|
||||
|
||||
&[variant="warning"] {
|
||||
--wa-icon-name: triangle-exclamation;
|
||||
}
|
||||
|
||||
&[variant="danger"] {
|
||||
--wa-icon-name: circle-exclamation;
|
||||
}
|
||||
|
||||
&[variant="success"] {
|
||||
--wa-icon-name: circle-check;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
You can even set icons dynamically, as a response to user interaction or media queries.
|
||||
For example, here's how we can change the icon on hover:
|
||||
|
||||
```html {.example}
|
||||
<wa-button class="github" href="https://github.com/webawesome/webawesome"><wa-icon slot="prefix" fixed-width></wa-icon> GitHub Repo</wa-button>
|
||||
<style>
|
||||
.github {
|
||||
--wa-icon-name: github;
|
||||
--wa-icon-family: brands;
|
||||
|
||||
&:hover {
|
||||
--wa-icon-name: arrow-up-right-from-square;
|
||||
--wa-icon-family: classic;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Colors
|
||||
@@ -103,7 +186,8 @@ Custom icons can be loaded individually with the `src` attribute. Only SVGs on a
|
||||
|
||||
You can register additional icons to use with the `<wa-icon>` component through icon libraries. Icon files can exist locally or on a CORS-enabled endpoint (e.g. a CDN). There is no limit to how many icon libraries you can register and there is no cost associated with registering them, as individual icons are only requested when they're used.
|
||||
|
||||
Web Awesome ships with two built-in icon libraries, `default` and `system`. The [default icon library](#customizing-the-default-library) is provided courtesy of [Font Awesome](https://fontawesome.com/). The [system icon library](#customizing-the-system-library) contains only a small subset of icons that are used internally by Web Awesome components.
|
||||
Web Awesome ships with one built-in icon library: `default`.
|
||||
The [default icon library](#customizing-the-default-library) is provided courtesy of [Font Awesome](https://fontawesome.com/).
|
||||
|
||||
To register an additional icon library, use the `registerIconLibrary()` function that's exported from `dist/webawesome.js`. At a minimum, you must provide a name and a resolver function. The resolver function translates an icon name to a URL where the corresponding SVG file exists. Refer to the examples below to better understand how it works.
|
||||
|
||||
@@ -115,8 +199,9 @@ Here's an example that registers an icon library located in the `/assets/icons`
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('my-icons', {
|
||||
resolver: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
registerIconLibrary({
|
||||
name: 'my-icons',
|
||||
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
mutator: svg => svg.setAttribute('fill', 'currentColor')
|
||||
});
|
||||
</script>
|
||||
@@ -131,6 +216,289 @@ To display an icon, set the `library` and `name` attributes of an `<wa-icon>` el
|
||||
|
||||
If an icon is used before registration occurs, it will be empty initially but shown when registered.
|
||||
|
||||
### Customizing the Default Icon Library
|
||||
|
||||
The default icon library contains over 2,000 icons courtesy of [Font Awesome](https://fontawesome.com/).
|
||||
These are the icons that display when you use `<wa-icon>` without the `library` attribute.
|
||||
If you prefer to have these icons resolve to a different icon library, simply register it using the `default` name:
|
||||
|
||||
For example, this will change the default icon library to use [Bootstrap Icons](https://icons.getbootstrap.com/) loaded from the jsDelivr CDN.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('default', {
|
||||
name: 'default',
|
||||
getUrl: (name, family) => {
|
||||
const suffix = family === 'filled' ? '-fill' : '';
|
||||
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
You can also register an existing library as the default:
|
||||
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
let myIcons = registerIconLibrary({
|
||||
name: 'my-icons',
|
||||
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
mutator: svg => svg.setAttribute('fill', 'currentColor')
|
||||
});
|
||||
|
||||
// Alias of my-icons to default
|
||||
registerIconLibrary('default', myIcons);
|
||||
</script>
|
||||
```
|
||||
|
||||
This allows you to have multiple libraries that co-exist, only one of which is the default.
|
||||
|
||||
### Customizing system icons
|
||||
|
||||
Web Awesome components use a number of icons internally.
|
||||
For example, the checkmark icon in `<wa-checkbox>` or the chevron used in `<wa-details>`.
|
||||
These icons have a `system:` prefix in their name, e.g. `system:check` or `system:chevron-down`.
|
||||
|
||||
To specify how these map to your icon library, you can define a `system()` function that maps Web Awesome’s system icons to your library’s icons.
|
||||
The `system()` function receives the icon name, family and variant as arguments and returns an object with the new `name`, `family`, and `variant`.
|
||||
For example, here is how to define system icon mappings for the Bootstrap Icons library:
|
||||
|
||||
```js
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
let system = {
|
||||
filled: ['circle', 'pause', 'play', 'star', 'user'],
|
||||
nameMap: {
|
||||
'check': 'check-lg',
|
||||
'circle': 'circle',
|
||||
'circle-xmark': 'x-circle',
|
||||
'eye-dropper': 'eyedropper',
|
||||
'eye': 'eye',
|
||||
'eye-slash': 'eye-slash',
|
||||
'grip-vertical': 'grip-vertical',
|
||||
'indeterminate': 'dash-lg',
|
||||
'minus': 'dash-lg',
|
||||
'pause': 'pause',
|
||||
'play': 'play',
|
||||
'user': 'person',
|
||||
'xmark': 'x-lg',
|
||||
}
|
||||
};
|
||||
|
||||
registerIconLibrary({
|
||||
name: 'bootstrap-icons',
|
||||
system(name, family) {
|
||||
return {
|
||||
// Transform names where different
|
||||
name: system.nameMap[name] || name,
|
||||
|
||||
// Default to non-filled as many of system's "solid" icons are not filled in Bootstrap Icons
|
||||
family: system.filled.includes(name) ? 'filled' : ''
|
||||
};
|
||||
},
|
||||
getUrl: (name, family) => {
|
||||
const suffix = family === 'filled' ? '-fill' : '';
|
||||
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
You can also specify a `library` key to resolve a system icon through a different library, e.g. WA’s default icon library.
|
||||
For example, the code above will try to resolve any system icons through your library and only fall back to WA's default library if they fail to load.
|
||||
This maximizes the odds that icons from your library are used, but can also be unpredictable.
|
||||
To resolve any system icon you have not vetted via the Web Awesome default library, you can use the `library` key:
|
||||
|
||||
```js
|
||||
let system = {
|
||||
filled: ['circle', 'pause', 'play', 'star', 'user'],
|
||||
nameMap: {
|
||||
'chevron-down': 'chevron-down',
|
||||
'chevron-left': 'chevron-left',
|
||||
'chevron-right': 'chevron-right',
|
||||
'check': 'check-lg',
|
||||
'circle': 'circle',
|
||||
'eye-dropper': 'eyedropper',
|
||||
'grip-vertical': 'grip-vertical',
|
||||
'indeterminate': 'dash-lg',
|
||||
'pause': 'pause',
|
||||
'play': 'play',
|
||||
'circle-xmark': 'x-circle',
|
||||
'grip-vertical': 'grip-vertical',
|
||||
'eye-slash': 'eye-slash',
|
||||
'eye': 'eye',
|
||||
'user': 'person',
|
||||
'xmark': 'x-lg',
|
||||
}
|
||||
};
|
||||
|
||||
registerIconLibrary({
|
||||
name: 'bootstrap-icons',
|
||||
system(name, family) {
|
||||
if (!system.nameMap[name]) {
|
||||
// If the icon is not known, use the default library
|
||||
return { library: 'wa', name, family, variant };
|
||||
}
|
||||
|
||||
return {
|
||||
name: system.nameMap[name],
|
||||
family: system.filled.includes(name) ? 'filled' : ''
|
||||
};
|
||||
},
|
||||
getUrl: (name, family) => {
|
||||
const suffix = family === 'filled' ? '-fill' : '';
|
||||
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Index of All System Icons { #system-icons-index }
|
||||
|
||||
These are all system icons used currently by Web Awesome components (`system:` prefix omitted for readability):
|
||||
|
||||
| Name | Variant | Icon |
|
||||
| --- | --- | --- |
|
||||
{%- for icon in systemIcons %}
|
||||
| `{{ icon.name }}` | `{{ icon.variant }}` | <wa-icon library="wa" name="system:{{ icon.name }}" family="classic" variant="{{ icon.variant }}"></wa-icon> |
|
||||
{%- endfor %}
|
||||
|
||||
### Inlined icons { #inlined }
|
||||
|
||||
Inlined icons are SVG icons that are loaded directly from code rather than from HTTP requests, making them load faster in your application.
|
||||
Inlining critical icons improves performance by eliminating HTTP requests, reducing load times, and ensuring they are immediately available.
|
||||
As an example, all of [Web Awesome’s default system icons](#system-icons-index) are inlined, and we strongly advise you inline the corresponding icons in your custom icon libraries as well.
|
||||
|
||||
#### How to Use Inlined Icons
|
||||
|
||||
The `inlined` property allows you to provide icon SVG markup directly in your code.
|
||||
This creates a mapping of `(name, family, variant)` to SVG markup.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
getUrl: name => `/path/to/custom/icons/${name}.svg`,
|
||||
inlined: {
|
||||
check: '<svg xmlns="http://www.w3.org/2000/svg">...</svg>',
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
The structure of the `inlined` property is as follows:
|
||||
- For simple libraries (no families or variants): `{ name: svg }`
|
||||
- For libraries with families (no variants): `{ family: { name: svg } }`
|
||||
- For complex libraries (with both family and variant): `{ family: { variant: { name: svg } } }`
|
||||
|
||||
#### Adding More Inlined Icons
|
||||
|
||||
To add additional icons to an existing library, use the `inline()` method:
|
||||
|
||||
```js
|
||||
import { getIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
let defaultLibrary = getIconLibrary('default');
|
||||
defaultLibrary.inline({
|
||||
classic: { // family
|
||||
regular: { // variant
|
||||
'circle-info': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>',
|
||||
'triangle-exclamation': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>'
|
||||
// ...
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Best Practice
|
||||
|
||||
When using custom icon libraries with Web Awesome components, always inline system icons to ensure optimal performance.
|
||||
|
||||
### Customize icon markup, for SVG sprites and more
|
||||
|
||||
By default, icon markup is produced by fetching the URL returned by the `getUrl()` function.
|
||||
You can provide a `getMarkup()` function to customize this.
|
||||
|
||||
A common use case for that is SVG sprites, often used to improve performance by avoiding multiple trips for each SVG.
|
||||
The browser will load the sprite sheet once and then you reference the particular SVG within the sprite sheet using its id:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary({
|
||||
name: 'sprite',
|
||||
getUrl: name => `/assets/images/sprite.svg#${name}`,
|
||||
getMarkup: url => `<svg fill="currentColor"><use href="${url}"></use></svg>`
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
As always, make sure to benchmark these changes. When using HTTP/2, it may in fact be more bandwidth-friendly to use multiple small requests instead of 1 large sprite sheet.
|
||||
|
||||
:::warning
|
||||
When using sprite sheets, the `wa-load` and `wa-error` events will not fire.
|
||||
|
||||
For security reasons, browsers may apply the same-origin policy on `<use>` elements located in the `<wa-icon>` shadow DOM and may refuse to load a cross-origin URL. There is currently no defined way to set a cross-origin policy for `<use>` elements. For this reason, sprite sheets should only be used if you're self-hosting them.
|
||||
:::
|
||||
|
||||
### Fallbacks
|
||||
|
||||
By default, if an icon fails to load, WA will retry using the WA default icon library, and if that also fails, a blank icon will be displayed.
|
||||
You can provide a `fallback()` function to customize this behavior.
|
||||
Some examples for common use cases follow.
|
||||
|
||||
If you never want icons outside your library to display:
|
||||
|
||||
```js
|
||||
registerIconLibrary({
|
||||
name: 'my-icons',
|
||||
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
fallback: (name, family, variant) => {
|
||||
// Don't show anything if an icon is not found
|
||||
return null;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
If you want to display a certain designated "missing icon" icon:
|
||||
|
||||
```js
|
||||
registerIconLibrary({
|
||||
name: 'my-icons',
|
||||
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
inlined: {
|
||||
// Make sure the missing icon never fails by inlining it:
|
||||
'missing-icon': '<svg xmlns="http://www.w3.org/2000/svg">...</svg>'
|
||||
}
|
||||
fallback: (name, family, variant) => {
|
||||
return {name: 'missing-icon'};
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
If you want to retry with the default family and variant:
|
||||
|
||||
```js
|
||||
registerIconLibrary({
|
||||
name: 'my-icons',
|
||||
getUrl: (name, family, variant) => `/assets/icons/${name}.svg`,
|
||||
fallback: (name, family, variant) => {
|
||||
if (family !== 'classic' || variant !== 'solid') {
|
||||
return { name, family: 'classic', variant: 'solid' };
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Icon Library Examples { #icon-libraries }
|
||||
|
||||
The following examples demonstrate how to register a number of popular, open source icon libraries via CDN. Feel free to adapt the code as you see fit to use your own origin or naming conventions.
|
||||
|
||||
### Bootstrap Icons
|
||||
@@ -143,8 +511,42 @@ Icons in this library are licensed under the [MIT License](https://github.com/tw
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('default', {
|
||||
resolver: (name, family) => {
|
||||
let system = {
|
||||
filled: ['circle', 'pause', 'play', 'star', 'user'],
|
||||
nameMap: {
|
||||
'chevron-down': 'chevron-down',
|
||||
'chevron-left': 'chevron-left',
|
||||
'chevron-right': 'chevron-right',
|
||||
'check': 'check-lg',
|
||||
'circle': 'circle',
|
||||
'eye-dropper': 'eyedropper',
|
||||
'grip-vertical': 'grip-vertical',
|
||||
'indeterminate': 'dash-lg',
|
||||
'pause': 'pause',
|
||||
'play': 'play',
|
||||
'circle-xmark': 'x-circle',
|
||||
'grip-vertical': 'grip-vertical',
|
||||
'eye-slash': 'eye-slash',
|
||||
'eye': 'eye',
|
||||
'user': 'person',
|
||||
'xmark': 'x-lg',
|
||||
}
|
||||
};
|
||||
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
system(name, family) {
|
||||
if (!system.nameMap[name]) {
|
||||
// If the icon is not known, use the default library
|
||||
return { library: 'wa', name: name, family, variant };
|
||||
}
|
||||
|
||||
return {
|
||||
name: system.nameMap[name],
|
||||
family: system.filled.includes(name) ? 'filled' : ''
|
||||
};
|
||||
},
|
||||
getUrl: (name, family) => {
|
||||
const suffix = family === 'filled' ? '-fill' : '';
|
||||
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
|
||||
}
|
||||
@@ -162,8 +564,9 @@ Icons in this library are licensed under the [Creative Commons 4.0 License](http
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('boxicons', {
|
||||
resolver: name => {
|
||||
registerIconLibrary({
|
||||
name: 'boxicons',
|
||||
getUrl: name => {
|
||||
let folder = 'regular';
|
||||
if (name.substring(0, 4) === 'bxs-') folder = 'solid';
|
||||
if (name.substring(0, 4) === 'bxl-') folder = 'logos';
|
||||
@@ -216,8 +619,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('lucide', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`
|
||||
registerIconLibrary({
|
||||
name: 'lucide',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`
|
||||
});
|
||||
</script>
|
||||
```
|
||||
@@ -232,8 +636,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/ta
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('heroicons', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`
|
||||
registerIconLibrary({
|
||||
name: 'heroicons',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -257,8 +662,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('iconoir', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`
|
||||
registerIconLibrary({
|
||||
name: 'iconoir',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -282,8 +688,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/io
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('ionicons', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`,
|
||||
registerIconLibrary({
|
||||
name: 'ionicons',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/npm/ionicons@5.1.2/dist/ionicons/svg/${name}.svg`,
|
||||
mutator: svg => {
|
||||
svg.setAttribute('fill', 'currentColor');
|
||||
svg.setAttribute('stroke', 'currentColor');
|
||||
@@ -327,8 +734,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/mi
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('jam', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`,
|
||||
registerIconLibrary({
|
||||
name: 'jam',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`,
|
||||
mutator: svg => svg.setAttribute('fill', 'currentColor')
|
||||
});
|
||||
</script>
|
||||
@@ -360,8 +768,9 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('material', {
|
||||
resolver: name => {
|
||||
registerIconLibrary({
|
||||
name: 'material',
|
||||
getUrl: name => {
|
||||
const match = name.match(/^(.*?)(_(round|sharp))?$/);
|
||||
return `https://cdn.jsdelivr.net/npm/@material-icons/svg@1.0.5/svg/${match[1]}/${match[3] || 'outline'}.svg`;
|
||||
},
|
||||
@@ -403,8 +812,9 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('remixicon', {
|
||||
resolver: name => {
|
||||
registerIconLibrary({
|
||||
name: 'remixicon',
|
||||
getUrl: name => {
|
||||
const match = name.match(/^(.*?)\/(.*?)?$/);
|
||||
match[1] = match[1].charAt(0).toUpperCase() + match[1].slice(1);
|
||||
return `https://cdn.jsdelivr.net/npm/remixicon@2.5.0/icons/${match[1]}/${match[2]}.svg`;
|
||||
@@ -440,8 +850,9 @@ Icons in this library are licensed under the [MIT License](https://github.com/ta
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('tabler', {
|
||||
resolver: name => `https://cdn.jsdelivr.net/npm/@tabler/icons@1.68.0/icons/${name}.svg`,
|
||||
registerIconLibrary({
|
||||
name: 'tabler',
|
||||
getUrl: name => `https://cdn.jsdelivr.net/npm/@tabler/icons@1.68.0/icons/${name}.svg`,
|
||||
mutator: svg => {
|
||||
svg.style.fill = 'none';
|
||||
svg.setAttribute('stroke', 'currentColor');
|
||||
@@ -476,8 +887,9 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('unicons', {
|
||||
resolver: name => {
|
||||
registerIconLibrary({
|
||||
name: 'unicons',
|
||||
getUrl: name => {
|
||||
const match = name.match(/^(.*?)(-s)?$/);
|
||||
return `https://cdn.jsdelivr.net/npm/@iconscout/unicons@3.0.3/svg/${match[2] === '-s' ? 'solid' : 'line'}/${
|
||||
match[1]
|
||||
@@ -504,61 +916,6 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
</div>
|
||||
```
|
||||
|
||||
### Customizing the Default Library
|
||||
|
||||
The default icon library contains over 2,000 icons courtesy of [Font Awesome](https://fontawesome.com/). These are the icons that display when you use `<wa-icon>` without the `library` attribute. If you prefer to have these icons resolve elsewhere or to a different icon library, register an icon library using the `default` name and a custom resolver.
|
||||
|
||||
For example, this will change the default icon library to use [Bootstrap Icons](https://icons.getbootstrap.com/) loaded from the jsDelivr CDN.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('default', {
|
||||
resolver: (name, family) => {
|
||||
const suffix = family === 'filled' ? '-fill' : '';
|
||||
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Customize the default library to use SVG sprites
|
||||
|
||||
To improve performance you can use a SVG sprites to avoid multiple trips for each SVG. The browser will load the sprite sheet once and then you reference the particular SVG within the sprite sheet using hash selector.
|
||||
|
||||
As always, make sure to benchmark these changes. When using HTTP/2, it may in fact be more bandwidth-friendly to use multiple small requests instead of 1 large sprite sheet.
|
||||
|
||||
:::warning
|
||||
When using sprite sheets, the `wa-load` and `wa-error` events will not fire.
|
||||
|
||||
For security reasons, browsers may apply the same-origin policy on `<use>` elements located in the `<wa-icon>` shadow DOM and may refuse to load a cross-origin URL. There is currently no defined way to set a cross-origin policy for `<use>` elements. For this reason, sprite sheets should only be used if you're self-hosting them.
|
||||
:::
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('sprite', {
|
||||
resolver: name => `/assets/images/sprite.svg#${name}`,
|
||||
mutator: svg => svg.setAttribute('fill', 'currentColor'),
|
||||
spriteSheet: true
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Customizing the System Library
|
||||
|
||||
The system library contains only the icons used internally by Web Awesome components. Unlike the default icon library, the system library does not rely on physical assets. Instead, its icons are hard-coded as data URIs into the resolver to ensure their availability.
|
||||
|
||||
If you want to change the icons Web Awesome uses internally, you can register an icon library using the `system` name and a custom resolver. If you choose to do this, it's your responsibility to provide all of the icons that are required by components. You can reference `src/components/library.system.ts` for a complete list of system icons used by Web Awesome.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
registerIconLibrary('system', {
|
||||
resolver: name => `/path/to/custom/icons/${name}.svg`
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -468,75 +468,20 @@ Use the `sync` attribute to make the popup the same width or height as the ancho
|
||||
</script>
|
||||
```
|
||||
|
||||
### Positioning Strategy
|
||||
|
||||
By default, the popup is positioned using an absolute positioning strategy. However, if your anchor is fixed or exists within a container that has `overflow: auto|hidden`, the popup risks being clipped. To work around this, you can use a fixed positioning strategy by setting the `strategy` attribute to `fixed`.
|
||||
|
||||
The fixed positioning strategy reduces jumpiness when the anchor is fixed and allows the popup to break out containers that clip. When using this strategy, it's important to note that the content will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
|
||||
|
||||
In this example, you can see how the popup breaks out of the overflow container when it's fixed. The fixed positioning strategy tends to be less performant than absolute, so avoid using it unnecessarily.
|
||||
|
||||
Toggle the switch and scroll the container to see the difference.
|
||||
|
||||
```html {.example}
|
||||
<div class="popup-strategy">
|
||||
<div class="overflow">
|
||||
<wa-popup placement="top" strategy="fixed" active>
|
||||
<span slot="anchor"></span>
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
</div>
|
||||
|
||||
<wa-switch checked>Fixed</wa-switch>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.popup-strategy .overflow {
|
||||
position: relative;
|
||||
height: 300px;
|
||||
border: solid 2px var(--wa-color-surface-border);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.popup-strategy span[slot='anchor'] {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: dashed 2px var(--wa-color-neutral-fill-loud);
|
||||
margin: 150px 50px;
|
||||
}
|
||||
|
||||
.popup-strategy .box {
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
background: var(--wa-color-brand-fill-loud);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.popup-strategy wa-switch {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.popup-strategy');
|
||||
const popup = container.querySelector('wa-popup');
|
||||
const fixed = container.querySelector('wa-switch');
|
||||
|
||||
fixed.addEventListener('change', () => (popup.strategy = fixed.checked ? 'fixed' : 'absolute'));
|
||||
</script>
|
||||
```
|
||||
|
||||
### Flip
|
||||
|
||||
When the popup doesn't have enough room in its preferred placement, it can automatically flip to keep it in view. To enable this, use the `flip` attribute. By default, the popup will flip to the opposite placement, but you can configure preferred fallback placements using `flip-fallback-placement` and `flip-fallback-strategy`. Additional options are available to control the flip behavior's boundary and padding.
|
||||
When the popup doesn't have enough room in its preferred placement, it can automatically flip to keep it in view and visually connected to its anchor.
|
||||
To enable this, use the `flip` attribute. By default, the popup will flip to the opposite placement, but you can configure preferred fallback placements using `flip-fallback-placement` and `flip-fallback-strategy`. Additional options are available to control the flip behavior's boundary and padding.
|
||||
|
||||
By default, flip takes effect when the popup would overflow the viewport.
|
||||
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
|
||||
|
||||
Scroll the container to see how the popup flips to prevent clipping.
|
||||
|
||||
```html {.example}
|
||||
<div class="popup-flip">
|
||||
<div class="overflow">
|
||||
<wa-popup placement="top" flip active>
|
||||
<wa-popup placement="top" flip active boundary="scroll">
|
||||
<span slot="anchor"></span>
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
@@ -592,7 +537,7 @@ Scroll the container to see how the popup changes it's fallback placement to pre
|
||||
```html {.example}
|
||||
<div class="popup-flip-fallbacks">
|
||||
<div class="overflow">
|
||||
<wa-popup placement="top" flip flip-fallback-placements="right bottom" flip-fallback-strategy="initial" active>
|
||||
<wa-popup placement="top" flip flip-fallback-placements="right bottom" flip-fallback-strategy="initial" active boundary="scroll">
|
||||
<span slot="anchor"></span>
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
@@ -626,14 +571,18 @@ Scroll the container to see how the popup changes it's fallback placement to pre
|
||||
|
||||
### Shift
|
||||
|
||||
When a popup is longer than its anchor, it risks being clipped by an overflowing container. In this case, use the `shift` attribute to shift the popup along its axis and back into view. You can customize the shift behavior using `shiftBoundary` and `shift-padding`.
|
||||
When a popup is longer than its anchor, it risks overflowing.
|
||||
In this case, use the `shift` attribute to shift the popup along its axis and back into view. You can customize the shift behavior using `shiftBoundary` and `shift-padding`.
|
||||
|
||||
By default, auto-size takes effect when the popup would overflow the viewport.
|
||||
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
|
||||
|
||||
Toggle the switch to see the difference.
|
||||
|
||||
```html {.example}
|
||||
<div class="popup-shift">
|
||||
<div class="overflow">
|
||||
<wa-popup placement="top" shift shift-padding="10" active>
|
||||
<wa-popup placement="top" shift shift-padding="10" active boundary="scroll">
|
||||
<span slot="anchor"></span>
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
@@ -676,7 +625,11 @@ Toggle the switch to see the difference.
|
||||
|
||||
### Auto-size
|
||||
|
||||
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from getting clipped. Possible values are `horizontal`, `vertical`, and `both`. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
|
||||
Use the `auto-size` attribute to tell the popup to resize when necessary to prevent it from overflowing.
|
||||
Possible values are `horizontal`, `vertical`, and `both`. You can use `autoSizeBoundary` and `auto-size-padding` to customize the behavior of this option. Auto-size works well with `flip`, but if you're using `auto-size-padding` make sure `flip-padding` is the same value.
|
||||
|
||||
By default, auto-size takes effect when the popup would overflow the viewport.
|
||||
You can use `boundary="scroll"` to make the popup resize when it overflows its nearest scrollable container instead.
|
||||
|
||||
When using `auto-size`, one or both of `--auto-size-available-width` and `--auto-size-available-height` will be applied to the host element. These values determine the available space the popover has before clipping will occur. Since they cascade, you can use them to set a max-width/height on your popup's content and easily control its overflow.
|
||||
|
||||
@@ -685,7 +638,7 @@ Scroll the container to see the popup resize as its available space changes.
|
||||
```html {.example}
|
||||
<div class="popup-auto-size">
|
||||
<div class="overflow">
|
||||
<wa-popup placement="top" auto-size="both" auto-size-padding="10" active>
|
||||
<wa-popup placement="top" auto-size="both" auto-size-padding="10" active boundary="scroll">
|
||||
<span slot="anchor"></span>
|
||||
<div class="box"></div>
|
||||
</wa-popup>
|
||||
|
||||
@@ -425,11 +425,3 @@ This can be hard to conceptualize, so heres a fairly large example showing how l
|
||||
</script>
|
||||
```
|
||||
|
||||
<script type="module">
|
||||
//
|
||||
// TODO - remove once we switch to the Popover API
|
||||
//
|
||||
customElements.whenDefined('wa-select').then(() => {
|
||||
document.querySelectorAll('wa-code-demo [slot="preview"] wa-select').forEach(select => select.hoist = true);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -129,7 +129,7 @@ Set a matching width and height to make a circle, square, or rounded avatar skel
|
||||
|
||||
<style>
|
||||
.skeleton-avatars wa-skeleton {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin-right: 0.5rem;
|
||||
|
||||
@@ -152,25 +152,3 @@ Use the `--max-width` custom property to change the width the tooltip can grow t
|
||||
<wa-button id="wrapping-tooltip">Hover me</wa-button>
|
||||
```
|
||||
|
||||
### Hoisting
|
||||
|
||||
Tooltips will be clipped if they're inside a container that has `overflow: auto|hidden|scroll`. The `hoist` attribute forces the tooltip to use a fixed positioning strategy, allowing it to break out of the container. In this case, the tooltip will be positioned relative to its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
|
||||
|
||||
```html {.example}
|
||||
<div class="tooltip-hoist">
|
||||
<wa-tooltip for="no-hoist">This is a tooltip</wa-tooltip>
|
||||
<wa-button id="no-hoist">No Hoist</wa-button>
|
||||
|
||||
<wa-tooltip for="hoist" hoist>This is a tooltip</wa-tooltip>
|
||||
<wa-button id="hoist">Hoist</wa-button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tooltip-hoist {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: solid 2px var(--wa-color-surface-border);
|
||||
padding: var(--wa-space-m);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ title: Viewport Demo
|
||||
description: Viewport demos can be used to display an iframe as a resizable, zoomable preview.
|
||||
tags: component
|
||||
noAlpha: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
```html {.example}
|
||||
|
||||
@@ -10,7 +10,7 @@ You can customize the look and feel of Web Awesome at a high level with themes.
|
||||
|
||||
Web Awesome uses [themes](/docs/themes) to apply a cohesive look and feel across the entire library. Themes are built with a collection of predefined CSS custom properties, which we call [design tokens](/docs/tokens), and there are many premade themes you can choose from.
|
||||
|
||||
To use a theme, simply add a link to the theme's stylesheet to the `<head>` of your page. For example, you can replace the link to `default.css` in the [installation code](/docs/installation/#quick-start-autoloading-via-cdn) with this snippet to use the *Awesome* theme:
|
||||
To use a theme, simply add a link to the theme's stylesheet to the `<head>` of your page. For example, you can replace the link to `default.css` in the [installation code](/docs/#quick-start-autoloading-via-cdn) with this snippet to use the *Awesome* theme:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{% cdnUrl 'styles/themes/awesome.css' %}" />
|
||||
@@ -197,7 +197,7 @@ For example, we can give all outlined callouts a thick left border, regardless o
|
||||
|
||||
<style>
|
||||
wa-callout:is(
|
||||
[appearance~="outlined"],
|
||||
[appearance~="outlined"],
|
||||
.wa-outlined
|
||||
) {
|
||||
border-left-width: var(--wa-panel-border-radius);
|
||||
|
||||
@@ -1412,7 +1412,8 @@ hasOutline: false
|
||||
import { registerIconLibrary } from '/dist/webawesome.js';
|
||||
|
||||
// Ensure regular icons are always available for the knobs
|
||||
registerIconLibrary('fa-classic-regular', {
|
||||
registerIconLibrary({
|
||||
name: 'fa-classic-regular',
|
||||
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/regular/${name}.svg`
|
||||
});
|
||||
|
||||
@@ -1453,36 +1454,47 @@ hasOutline: false
|
||||
break;
|
||||
case 'premium':
|
||||
iconFamily.value = 'custom';
|
||||
registerIconLibrary('default', {
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
resolver: name => `/assets/icons/chunk/${name}.svg`,
|
||||
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
|
||||
});
|
||||
registerIconLibrary('system', {
|
||||
registerIconLibrary({
|
||||
name: 'system',
|
||||
resolver: name => `/assets/icons/chunk/${name}.svg`,
|
||||
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
|
||||
});
|
||||
break;
|
||||
case 'playful':
|
||||
iconFamily.value = 'custom';
|
||||
registerIconLibrary('default', {
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
resolver: name => `/assets/icons/jelly/${name}.svg`,
|
||||
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
|
||||
});
|
||||
registerIconLibrary('system', {
|
||||
registerIconLibrary({
|
||||
name: 'system',
|
||||
name: 'system',
|
||||
name: 'system',
|
||||
resolver: name => `/assets/icons/jelly/${name}.svg`,
|
||||
mutator: svg => {[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));}
|
||||
});
|
||||
break;
|
||||
case 'brutalist':
|
||||
caregisterIconLibrary({
|
||||
registerIconLibrary({
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
iconFamily.value = 'custom';
|
||||
registerIconLibrary('default', {
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
resolver: name => `/assets/icons/utility/${name}.svg`,
|
||||
mutator: svg => {
|
||||
[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));
|
||||
[...svg.querySelectorAll('[stroke="black"]')].map(el => el.setAttribute('stroke', 'currentColor'));
|
||||
}
|
||||
});
|
||||
registerIconLibrary('system', {
|
||||
registerIconLibrary({
|
||||
name: 'system',
|
||||
resolver: name => `/assets/icons/utility/${name}.svg`,
|
||||
mutator: svg => {
|
||||
[...svg.querySelectorAll('[fill="black"]')].map(el => el.setAttribute('fill', 'currentColor'));
|
||||
@@ -1497,10 +1509,12 @@ hasOutline: false
|
||||
break;
|
||||
case 'classic':
|
||||
iconFamily.value = 'custom';
|
||||
registerIconLibrary('default', {
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
resolver: name => `/assets/icons/bootstrap/${name}.svg`,
|
||||
});
|
||||
registerIconLibrary('system', {
|
||||
registerIconLibrary({
|
||||
name: 'system',
|
||||
resolver: name => `/assets/icons/bootstrap/${name}.svg`,
|
||||
});
|
||||
break;
|
||||
@@ -1531,7 +1545,8 @@ hasOutline: false
|
||||
iconLibrary = 'sharp-solid';
|
||||
}
|
||||
// Ensures sharp-solid variations are available for ratings, etc.
|
||||
registerIconLibrary('always-solid', {
|
||||
registerIconLibrary({
|
||||
name: 'always-solid',
|
||||
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/sharp-solid/${name}.svg`
|
||||
});
|
||||
solidifyRatingStars();
|
||||
@@ -1557,15 +1572,18 @@ hasOutline: false
|
||||
iconLibrary = 'solid';
|
||||
}
|
||||
// Ensures solid variations are available for radios, ratings, etc.
|
||||
registerIconLibrary('always-solid', {
|
||||
registerIconLibrary({
|
||||
name: 'always-solid',
|
||||
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/solid/${name}.svg`
|
||||
});
|
||||
solidifyRatingStars();
|
||||
}
|
||||
registerIconLibrary('default', {
|
||||
registerIconLibrary({
|
||||
name: 'default',
|
||||
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/${iconLibrary}/${name}.svg`
|
||||
});
|
||||
registerIconLibrary('system', {
|
||||
registerIconLibrary({
|
||||
name: 'system',
|
||||
resolver: name => `https://ka-f.fontawesome.com/releases/v6.5.1/svgs/${iconLibrary}/${name}.svg`
|
||||
});
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ override:tags: []
|
||||
{% markdown %}
|
||||
## Installation
|
||||
|
||||
Layout components are included in Web Awesome's [autoloader](/docs/installation/#quick-start-autoloading-via-cdn). You can also import them individually via [cherry picking](/docs/installation/#cherry-picking).
|
||||
Layout components are included in Web Awesome's [autoloader](/docs/#quick-start-autoloading-via-cdn). You can also import them individually via [cherry picking](/docs/#cherry-picking).
|
||||
|
||||
Layout utilities are bundled with all [style utilities](/docs/utilities). You can import all Web Awesome page styles (including [native styles](/docs/native/)) by including the following stylesheet in your project:
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ file: styles/native/radio.css
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-cluster">
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="a" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="a" value="2"> Option 2</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -24,9 +24,9 @@ To set the initial value and checked state, use the `checked` attribute on the c
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-cluster">
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
|
||||
<label><input type="radio" name="b" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="b" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="b" value="3"> Option 3</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -36,9 +36,9 @@ Use the `disabled` attribute to disable a radio.
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-cluster">
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2" disabled> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
<label><input type="radio" name="c" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="c" value="2" disabled> Option 2</label>
|
||||
<label><input type="radio" name="c" value="3"> Option 3</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -49,26 +49,26 @@ Use the [size utilities](/docs/utilities/size) to change the radios' size.
|
||||
```html {.example}
|
||||
<fieldset class="wa-size-s wa-cluster">
|
||||
<legend>Small</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
<label><input type="radio" name="d" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="d" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="d" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
|
||||
<br />
|
||||
<fieldset class="wa-size-m wa-cluster">
|
||||
<legend>Medium</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
<label><input type="radio" name="e" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="e" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="e" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
|
||||
<br />
|
||||
|
||||
<fieldset class="wa-size-l wa-cluster">
|
||||
<legend>Large</legend>
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3"> Option 3</label>
|
||||
<label><input type="radio" name="f" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="f" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="f" value="3"> Option 3</label>
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
@@ -78,16 +78,16 @@ You can wrap native radios in a flex container to give them a horizontal or vert
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-cluster">
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
|
||||
<label><input type="radio" name="g" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="g" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="g" value="3"> Option 3</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-stack">
|
||||
<label><input type="radio" name="radio" value="1"> Option 1</label>
|
||||
<label><input type="radio" name="radio" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="radio" value="3" checked> Option 3</label>
|
||||
<label><input type="radio" name="h" value="1" checked> Option 1</label>
|
||||
<label><input type="radio" name="h" value="2"> Option 2</label>
|
||||
<label><input type="radio" name="h" value="3"> Option 3</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Action Panel
|
||||
description: 'Help users complete tasks efficiently with quick access to key actions.'
|
||||
icon: action-panel
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Activity Log
|
||||
description: 'Track and organize recent user actions or events.'
|
||||
|
||||
---
|
||||
|
||||
## Simple
|
||||
@@ -260,7 +261,7 @@ description: 'Track and organize recent user actions or events.'
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Comments
|
||||
description: 'Enable users to engage in discussions, provide feedback, or record their thoughts.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Card with Header & Footer
|
||||
@@ -91,7 +92,7 @@ description: 'Enable users to engage in discussions, provide feedback, or record
|
||||
<wa-icon-button name="face-smile" label="Add Sticker" id="sticker-button"></wa-icon-button>
|
||||
<wa-tooltip for="sticker-button">Add Sticker</wa-tooltip>
|
||||
</div>
|
||||
<wa-button variant="brand">Comment</wa-button>
|
||||
<wa-button variant="brand">Comment</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -107,9 +108,9 @@ description: 'Enable users to engage in discussions, provide feedback, or record
|
||||
<div class="wa-stack">
|
||||
<div class="wa-flank" style="--flank-size: 3rem">
|
||||
<div class="wa-frame:portrait wa-border-radius-s">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1607675742178-f616ae75044b?q=80&w=3435&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="the cover image for the film"
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1607675742178-f616ae75044b?q=80&w=3435&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="the cover image for the film"
|
||||
/>
|
||||
</div>
|
||||
<span class="wa-heading-l">Heretic</span>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
---
|
||||
title: Data Display
|
||||
description: 'Convey insights, metrics, and aggregate data at a glance.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
|
||||
## Simple
|
||||
## Simple
|
||||
```html {.example}
|
||||
<wa-card>
|
||||
<div class="wa-grid wa-gap-3xl" style="--min-column-size: 24ch;">
|
||||
@@ -170,4 +171,4 @@ description: 'Convey insights, metrics, and aggregate data at a glance.'
|
||||
</article>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Description List
|
||||
description: 'Help users digest detailed information in a structured, easy-to-scan format.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Left Aligned
|
||||
@@ -249,4 +250,4 @@ description: 'Help users digest detailed information in a structured, easy-to-sc
|
||||
</a>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Empty State
|
||||
description: 'Guide users with helpful prompts and visuals when no content is available.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple
|
||||
@@ -125,7 +126,7 @@ description: 'Guide users with helpful prompts and visuals when no content is av
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
## Add people
|
||||
## Add people
|
||||
```html {.example}
|
||||
<wa-card style="max-width: 60ch; margin: 0 auto;">
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
@@ -146,7 +147,7 @@ description: 'Guide users with helpful prompts and visuals when no content is av
|
||||
<span class="wa-caption-m">DevOps</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
@@ -162,7 +163,7 @@ description: 'Guide users with helpful prompts and visuals when no content is av
|
||||
<span class="wa-caption-m">Captain</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
@@ -178,7 +179,7 @@ description: 'Guide users with helpful prompts and visuals when no content is av
|
||||
<span class="wa-caption-m">Cloud Engineer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
@@ -193,7 +194,7 @@ description: 'Guide users with helpful prompts and visuals when no content is av
|
||||
<span class="wa-caption-m">UX Writer</span>
|
||||
</div>
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
<wa-icon name="user-plus" slot="prefix"></wa-icon>
|
||||
Invite
|
||||
</wa-button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: FAQ
|
||||
description: 'Empower users to learn more with a structured list of questions and answers.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## With Flanked Heading & Description
|
||||
@@ -86,7 +87,7 @@ description: 'Empower users to learn more with a structured list of questions an
|
||||
<dt class="wa-heading-m">How often do you update your courses?</dt>
|
||||
<dd>A course is updated once there is a fundamental shift in the language or library’s underlying API. You can check our <a href="#">workshop</a> list to see if a new version of a given course is on the schedule. You may also write to us as <a href="#">support@frontendmasters.com</a> with suggestions for updates.</dd>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt class="wa-heading-m">Do you offer certificates of completion?</dt>
|
||||
<dd>You can download certificates of completion from the <a href="#">Completed Courses</a> list in your Learning Library. Click the diploma icon next to the course to download the certificate in light or dark mode. A link to your Public Profile is included on each certificate if you’ve created one. Public Profiles showcase your learning journey and are a fantastic way to share progress with friends, co-workers, or employers. Public Profiles are available to members with an active Frontend Masters subscription who have watched ten or more hours of content. Visit the <a href="#">Public Profile</a> section in My Account to get started.</dd>
|
||||
@@ -103,16 +104,16 @@ description: 'Empower users to learn more with a structured list of questions an
|
||||
</ul>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt class="wa-heading-m">Do you have discounts for students?</dt>
|
||||
<dd>We are part of the <a href="#">GitHub Student Developer Pack</a>, allowing students six months of free access to the entire platform.</dd>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="wa-stack wa-gap-xs">
|
||||
<dt class="wa-heading-m">How do I cancel my plan?</dt>
|
||||
<dd>You can cancel your Frontend Masters subscription by visiting the <a href="#">Subscription tab</a> in your My Account area.</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Grid List
|
||||
description: 'Improve browsing and selection by organizing data in a structured grid layout.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Cards with Footer Actions
|
||||
@@ -397,8 +398,8 @@ description: 'Improve browsing and selection by organizing data in a structured
|
||||
<div class="wa-stack">
|
||||
<div class="wa-cluster wa-gap-s"><span>Draft</span> <wa-badge appearance="filled outlined" variant="neutral">1</wa-badge></div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wa-card>
|
||||
<div class="wa-flank:end">
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
@@ -426,12 +427,12 @@ description: 'Improve browsing and selection by organizing data in a structured
|
||||
<wa-icon name="plus"></wa-icon>
|
||||
Add Task
|
||||
</wa-button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="wa-stack">
|
||||
<div class="wa-cluster wa-gap-s"><span>In Progress</span> <wa-badge appearance="filled outlined" variant="neutral">2</wa-badge></div>
|
||||
|
||||
|
||||
<wa-card>
|
||||
<div class="wa-flank:end">
|
||||
<div class="wa-stack wa-gap-2xs">
|
||||
@@ -481,7 +482,7 @@ description: 'Improve browsing and selection by organizing data in a structured
|
||||
<wa-icon name="plus"></wa-icon>
|
||||
Add Task
|
||||
</wa-button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="wa-stack">
|
||||
@@ -508,18 +509,17 @@ description: 'Improve browsing and selection by organizing data in a structured
|
||||
<wa-avatar initials="KK" label="Avatar with initials: KK"></wa-avatar>
|
||||
</div>
|
||||
</wa-card>
|
||||
|
||||
|
||||
|
||||
|
||||
<wa-button appearance="plain">
|
||||
<wa-icon name="plus"></wa-icon>
|
||||
Add Task
|
||||
</wa-button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
@@ -5,4 +5,5 @@ parent: patterns
|
||||
layout: overview
|
||||
override:tags: []
|
||||
listChildren: true
|
||||
isPro: false
|
||||
---
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Leaderboard
|
||||
description: 'Engage and motivate users by highlighting top performers, scores, and achievements.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Pagination
|
||||
description: 'Improve navigation and performance by breaking long lists or content into manageable pages.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Permissions
|
||||
description: 'Permission patterns provide or restrict access to users.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## With Form Inputs
|
||||
@@ -118,7 +119,7 @@ description: 'Permission patterns provide or restrict access to users.'
|
||||
<wa-button size="small" variant="brand" pill>Generate</wa-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</wa-card>
|
||||
```
|
||||
|
||||
@@ -170,7 +171,7 @@ description: 'Permission patterns provide or restrict access to users.'
|
||||
<wa-option value="moderator">Moderator</wa-option>
|
||||
<wa-option value="contributor">Contributor</wa-option>
|
||||
<wa-option value="reader">Reader</wa-option>
|
||||
</wa-select>
|
||||
</wa-select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -222,7 +223,7 @@ description: 'Permission patterns provide or restrict access to users.'
|
||||
</tbody>
|
||||
</table>
|
||||
</wa-tab-panel>
|
||||
|
||||
|
||||
</wa-tab-group>
|
||||
</div>
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Pricing
|
||||
description: 'Help users make informed purchasing decisions with clear, structured pricing.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Three Tiers
|
||||
@@ -164,4 +165,4 @@ description: 'Help users make informed purchasing decisions with clear, structur
|
||||
</wa-callout>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
```
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Blog
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -367,4 +368,4 @@ TODO Page Description
|
||||
}
|
||||
|
||||
</style>
|
||||
```
|
||||
```
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Business
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Category Filter
|
||||
description: 'Helps the user find the right products with filters to refine search results by specific attributes.'
|
||||
icon: checkbox
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Sidebar with Checkboxes & Expandable Filters
|
||||
@@ -80,4 +81,4 @@ icon: checkbox
|
||||
</div>
|
||||
<div class="wa-placeholder"></div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Category Preview
|
||||
description: 'Help shoppers discover your product offerings with showcases of product categories.'
|
||||
icon: preview
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Split with Image Grid
|
||||
@@ -159,4 +160,4 @@ icon: preview
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Checkout Form
|
||||
description: 'Let shoppers checkout with ease with streamlined forms to capture shipping and payment info.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
|
||||
@@ -241,4 +242,4 @@ description: 'Let shoppers checkout with ease with streamlined forms to capture
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Incentives
|
||||
description: 'Encourage shoppers to buy your products with value propositions, discounts, and promotions.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## 3 Column
|
||||
@@ -120,4 +121,4 @@ description: 'Encourage shoppers to buy your products with value propositions, d
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -4,4 +4,5 @@ description: Pre-built product overviews, shopping carts, and more to help you b
|
||||
parent: patterns
|
||||
layout: overview
|
||||
override:tags: []
|
||||
isPro: false
|
||||
---
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Order History
|
||||
description: 'Empower your customers to view past purchases and track upcoming orders with comprehensive order histories.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## List
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Order Summary
|
||||
description: 'Give shoppers confidence in their purchases with summaries of everything included in their order.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple
|
||||
@@ -291,4 +292,4 @@ description: 'Give shoppers confidence in their purchases with summaries of ever
|
||||
</div>
|
||||
</wa-callout>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Product Lists
|
||||
description: 'Let shoppers browse and compare products with detailed lists of the products in your store.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Simple Grid with Ratings
|
||||
@@ -179,4 +180,4 @@ description: 'Let shoppers browse and compare products with detailed lists of th
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Product Overview
|
||||
description: 'Showcase your products with overviews including images, ratings, features, options, and more.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Split with Image
|
||||
@@ -426,4 +427,4 @@ description: 'Showcase your products with overviews including images, ratings, f
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Product Preview
|
||||
description: 'Give shoppers a quick look at your products as they browse with modal previews.'
|
||||
icon: preview
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## With Product Options
|
||||
@@ -157,4 +158,4 @@ icon: preview
|
||||
</div>
|
||||
</div>
|
||||
</wa-card>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Product Reviews
|
||||
description: 'Help shoppers make informed decisions with ratings, reviews, and testimonials from your customers.'
|
||||
isPro: true
|
||||
---
|
||||
## Multi column
|
||||
|
||||
@@ -208,4 +209,4 @@ description: 'Help shoppers make informed decisions with ratings, reviews, and t
|
||||
</div>
|
||||
<wa-divider></wa-divider>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Shopping Cart
|
||||
description: 'Give shoppers an overview of selected items with shopping carts that let them edit items and proceed to checkout.'
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Two Columns with Summary Card
|
||||
@@ -274,4 +275,4 @@ description: 'Give shoppers an overview of selected items with shopping carts th
|
||||
</wa-button>
|
||||
</div>
|
||||
</wa-drawer>
|
||||
```
|
||||
```
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Store Navigation
|
||||
description: 'Help shoppers explore categories and find products with all of the links they need to navigate your store.'
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
## Popup Menu
|
||||
@@ -81,4 +82,4 @@ unlisted: true
|
||||
|
||||
|
||||
</style>
|
||||
```
|
||||
```
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Business
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Entertainment
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -3,6 +3,7 @@ title: Patterns
|
||||
description: Patterns are reusable UI solutions to common design problems, ready to copy and paste into any project.
|
||||
layout: overview
|
||||
override:tags: []
|
||||
isPro: false
|
||||
---
|
||||
|
||||
<div class="max-line-length">
|
||||
@@ -21,7 +22,7 @@ Patterns are written as standard HTML, so you can use them just as you would any
|
||||
|
||||
To use a pattern in your project, refer to each pattern's docs for a copyable code snippet. Paste the snippet wherever you'd like the pattern to appear in your project.
|
||||
|
||||
Because patterns use a combination of Web Awesome features, they work best when you have [native styles](/docs/native), [style utilities](/docs/utilities), and a [theme](/docs/themes) installed in addition to Web Awesome [components](/docs/components). Refer to the [Installation page](/docs/installation) to set up all of these features in your project.
|
||||
Because patterns use a combination of Web Awesome features, they work best when you have [native styles](/docs/native), [style utilities](/docs/utilities), and a [theme](/docs/themes) installed in addition to Web Awesome [components](/docs/components). Refer to the [Installation page](/docs/) to set up all of these features in your project.
|
||||
|
||||
{% endmarkdown %}
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Membership
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -2,6 +2,7 @@
|
||||
title: News
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
@@ -157,4 +158,4 @@ TODO Page Description
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
```
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Non-profit
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -2,5 +2,6 @@
|
||||
"layout": "patterns.njk",
|
||||
"tags": ["patterns"],
|
||||
"wide": true,
|
||||
"noAlpha": true
|
||||
"noAlpha": true,
|
||||
"isPro": true
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Portfolio
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -2,8 +2,9 @@
|
||||
title: Product Landing
|
||||
description: TODO
|
||||
unlisted: true
|
||||
isPro: true
|
||||
---
|
||||
|
||||
TODO Page Description
|
||||
|
||||
## Examples
|
||||
## Examples
|
||||
@@ -12,6 +12,25 @@ Components with the <wa-badge variant="warning" pill>Experimental</wa-badge> bad
|
||||
During the alpha period, things might break! We take breaking changes very seriously, but sometimes they're necessary to make the final product that much better. We appreciate your patience!
|
||||
:::
|
||||
|
||||
## Next
|
||||
|
||||
- All icon libraries can now declare **pre-fetched** icons and skip the HTTP request.
|
||||
When these icons are used, the pre-fetched version is automatically used, with no additional opt-in.
|
||||
- 🚨 BREAKING: No more `system` library, just use `default`.
|
||||
The improvement above allowed us to fold Web Awesome’s own `system` icon library into the `default` library
|
||||
so the performance benefits can be automatic and shared across all uses of the `default` library,
|
||||
rather then requiring a conscious decision to use a different library.
|
||||
This also makes WA components play better with different icon libraries and different default families and variants.
|
||||
- Fixed a bug that caused an undesired margin below radio groups
|
||||
- 🚨 BREAKING: Renamed `<image-comparer>` to `<wa-comparer>` and improved compatibility for non-image content
|
||||
- Added support for Duotone Thin, Light, and Regular styles and the Sharp Duotone family of styles to `<wa-icon>`
|
||||
- Fixed a bug that caused `<wa-radio-group>` to have an undesired margin below it
|
||||
- Fixed a bug in `<wa-select>` that caused incorrect spacing of icons
|
||||
- Fixed a bug in the Matter theme that prevented clicks on form control labels to not focus the control
|
||||
- Fixed a bug in `<wa-radio-group>` that prevented radio buttons from validating
|
||||
- Improved native radio alignment
|
||||
- Improved the `.wa-cloak` utility class so all FOUCE-related solutions are 100% opt-in
|
||||
|
||||
## 3.0.0-alpha.12
|
||||
|
||||
### Enhancements
|
||||
|
||||
@@ -31,7 +31,7 @@ The [issue tracker](https://github.com/shoelace-style/webawesome-alpha/issues) i
|
||||
- Please **do not** use the issue tracker for feature requests. Use [the discussion forum](https://github.com/shoelace-style/webawesome-alpha/discussions/categories/ideas) instead.
|
||||
- Please **do not** derail, hijack, or troll issues. Keep the discussion on topic and be respectful of others.
|
||||
- Please **do not** post comments with "+1" or "👍". Use [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) instead.
|
||||
- Please **do** use the issue tracker for feature requests, bug reports, and pull requests.
|
||||
- Please **do** use the issue tracker for bug reports and pull requests.
|
||||
|
||||
Issues that do not follow these guidelines are subject to closure. There simply aren't enough resources for the author and contributors to troubleshoot personal support requests.
|
||||
|
||||
@@ -352,13 +352,11 @@ Form controls should support submission and validation through the following con
|
||||
|
||||
### System Icons
|
||||
|
||||
Avoid inlining SVG icons inside of templates. If a component requires an icon, make sure `<wa-icon>` is a dependency of the component and use the [system library](/components/icon#customizing-the-system-library):
|
||||
Avoid inlining SVG icons inside of templates.
|
||||
If a component requires an icon, make sure `<wa-icon>` is a dependency of the component.
|
||||
|
||||
```html
|
||||
<wa-icon library="system" name="..." variant="..."></wa-icon>
|
||||
```
|
||||
|
||||
This will render the icons instantly whereas the default library will fetch them from a remote source. If an icon isn't available in the system library, you will need to add it to `library.system.ts`. Using the system library ensures that all icons load instantly and are customizable by users who wish to provide a custom resolver for the system library.
|
||||
If it is not one of the [pre-fetched icons](/components/icon#fetched) in the `default` library,
|
||||
you should add it. This will render the icons instantly rather than fetching them from a remote source.
|
||||
|
||||
### Writing tests
|
||||
|
||||
|
||||
71
docs/docs/test/benchmark.njk
Normal file
71
docs/docs/test/benchmark.njk
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: CSS Properties Benchmark
|
||||
unlisted: true
|
||||
wide: true
|
||||
---
|
||||
|
||||
{% set icons = {
|
||||
check: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>',
|
||||
'chevron-down': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg>',
|
||||
'chevron-left': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg>',
|
||||
'chevron-right': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/></svg>',
|
||||
circle: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg>',
|
||||
'eye-dropper': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6v42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480h42.4c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7H96V379.9c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"/></svg>',
|
||||
'grip-vertical': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M40 352l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zm192 0l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 320c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 192l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 160c-22.1 0-40-17.9-40-40L0 72C0 49.9 17.9 32 40 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40z"/></svg>',
|
||||
indeterminate: '<svg part="indeterminate-icon" class="icon" viewBox="0 0 16 16"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round"><g stroke="currentColor" stroke-width="2"><g transform="translate(2.285714, 6.857143)"><path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path></g></g></g></svg>',
|
||||
minus: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>',
|
||||
pause: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M48 64C21.5 64 0 85.5 0 112V400c0 26.5 21.5 48 48 48H80c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H48zm192 0c-26.5 0-48 21.5-48 48V400c0 26.5 21.5 48 48 48h32c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H240z"/></svg>',
|
||||
play: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>',
|
||||
star: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"/></svg>',
|
||||
user: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>',
|
||||
xmark: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>'
|
||||
} %}
|
||||
|
||||
<style>
|
||||
.icon-tests {
|
||||
font-size: .5rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
wa-icon {
|
||||
transition: 1s font-size;
|
||||
&:hover {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{% set repetitions = 200 %}
|
||||
|
||||
<h2>Setting everything via attributes</h2>
|
||||
|
||||
<div class="icon-tests">
|
||||
{% for icon, svg in icons %}
|
||||
{% for i in range(repetitions) %}
|
||||
<wa-icon name="{{ icon }}" variant="solid" family="classic"></wa-icon>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h2>Setting variant & family via CSS</h2>
|
||||
|
||||
<div class="icon-tests" style="--wa-icon-variant: regular; --wa-icon-family: classic">
|
||||
{% for icon, svg in icons %}
|
||||
{% for i in range(repetitions) %}
|
||||
<wa-icon name="{{ icon }}"></wa-icon>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h2>Setting name via CSS</h2>
|
||||
|
||||
<div class="icon-tests">
|
||||
{% for icon, svg in icons %}
|
||||
<span style="--wa-icon-name: {{ icon }}">
|
||||
{% for i in range(repetitions) %}
|
||||
<wa-icon variant="solid" family="classic"></wa-icon>
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
2
docs/docs/themes/active.md
vendored
2
docs/docs/themes/active.md
vendored
@@ -5,4 +5,6 @@ isPro: true
|
||||
tags: pro
|
||||
palette: rudimentary
|
||||
brand: green
|
||||
fonts:
|
||||
body: Inter
|
||||
---
|
||||
|
||||
2
docs/docs/themes/awesome.md
vendored
2
docs/docs/themes/awesome.md
vendored
@@ -4,4 +4,6 @@ description: Punchy and vibrant, the rockstar of themes.
|
||||
order: 0.2
|
||||
palette: bright
|
||||
brand: blue
|
||||
fonts:
|
||||
body: Quicksand
|
||||
---
|
||||
|
||||
4
docs/docs/themes/brutalist.md
vendored
4
docs/docs/themes/brutalist.md
vendored
@@ -5,4 +5,8 @@ isPro: true
|
||||
tags: pro
|
||||
palette: default
|
||||
brand: blue
|
||||
fonts:
|
||||
body: Space Grotesk
|
||||
heading: IBM Plex Sans Condensed
|
||||
code: Space Mono
|
||||
---
|
||||
|
||||
1
docs/docs/themes/classic.md
vendored
1
docs/docs/themes/classic.md
vendored
@@ -3,4 +3,5 @@ title: Classic
|
||||
description: Timeless elegance that never goes out of style.
|
||||
order: 0.1
|
||||
palette: classic
|
||||
brand: blue
|
||||
---
|
||||
|
||||
4
docs/docs/themes/default.md
vendored
4
docs/docs/themes/default.md
vendored
@@ -4,4 +4,8 @@ description: Your trusty companion, like a perfectly broken-in pair of jeans.
|
||||
order: 0
|
||||
palette: default
|
||||
brand: blue
|
||||
fonts:
|
||||
body: ui-sans-serif
|
||||
code: ui-monospace
|
||||
longform: ui-serif
|
||||
---
|
||||
|
||||
4
docs/docs/themes/demo.njk
vendored
4
docs/docs/themes/demo.njk
vendored
@@ -26,14 +26,14 @@ eleventyComputed:
|
||||
{% include 'theme-showcase.njk' %}
|
||||
{% endset %}
|
||||
|
||||
<wa-image-comparer style="width: 100%" position="90">
|
||||
<wa-comparer style="width: 100%" position="90">
|
||||
<div slot="after" class="theme-showcase wa-gap-xl">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
<div slot="before" class="theme-showcase wa-gap-xl wa-invert">
|
||||
{{ content | safe }}
|
||||
</div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
|
||||
<script type="module">
|
||||
import { urls as stylesheetURLs, docsURLs, icons } from "/assets/scripts/tweak/data.js";
|
||||
|
||||
2
docs/docs/themes/glossy.md
vendored
2
docs/docs/themes/glossy.md
vendored
@@ -5,4 +5,6 @@ isPro: true
|
||||
tags: pro
|
||||
palette: elegant
|
||||
brand: indigo
|
||||
fonts:
|
||||
body: Figtree
|
||||
---
|
||||
|
||||
4
docs/docs/themes/matter.md
vendored
4
docs/docs/themes/matter.md
vendored
@@ -5,6 +5,10 @@ isPro: true
|
||||
tags: pro
|
||||
palette: mild
|
||||
brand: indigo
|
||||
fonts:
|
||||
body: 'Wix Madefor Text'
|
||||
code: Roboto Mono
|
||||
longform: Roboto Serif
|
||||
---
|
||||
|
||||
Set the page theme to "{{ title }}" from the top right to preview the following examples.
|
||||
|
||||
4
docs/docs/themes/mellow.md
vendored
4
docs/docs/themes/mellow.md
vendored
@@ -4,4 +4,8 @@ description: Soft and soothing, like a lazy Sunday morning.
|
||||
isPro: true
|
||||
tags: pro
|
||||
palette: natural
|
||||
fonts:
|
||||
body: Mulish
|
||||
heading: Lora
|
||||
longform: Lora
|
||||
---
|
||||
|
||||
4
docs/docs/themes/playful.md
vendored
4
docs/docs/themes/playful.md
vendored
@@ -5,4 +5,8 @@ isPro: true
|
||||
tags: pro
|
||||
palette: rudimentary
|
||||
brand: purple
|
||||
fonts:
|
||||
body: Nunito
|
||||
heading: Fredoka
|
||||
code: Azeret Mono
|
||||
---
|
||||
|
||||
4
docs/docs/themes/premium.md
vendored
4
docs/docs/themes/premium.md
vendored
@@ -5,4 +5,8 @@ isPro: true
|
||||
tags: pro
|
||||
palette: anodized
|
||||
brand: cyan
|
||||
fonts:
|
||||
body: DM Sans
|
||||
heading: Playfair Display
|
||||
longform: Playfair
|
||||
---
|
||||
|
||||
17
docs/docs/themes/remix.js
vendored
17
docs/docs/themes/remix.js
vendored
@@ -30,8 +30,8 @@ function init() {
|
||||
|
||||
codeSnippets = document.querySelector('#usage ~ wa-tab-group.import-stylesheet-code:first-of-type');
|
||||
codeSnippets = {
|
||||
html: codeSnippets.querySelector('code.language-html'),
|
||||
css: codeSnippets.querySelector('code.language-css'),
|
||||
html: codeSnippets?.querySelector('code.language-html'),
|
||||
css: codeSnippets?.querySelector('code.language-css'),
|
||||
};
|
||||
|
||||
data = {
|
||||
@@ -73,11 +73,10 @@ function init() {
|
||||
|
||||
Promise.all(Object.values(selects).map(select => select.updateComplete)).then(() => render());
|
||||
|
||||
return { selects, codeSnippets, data, computed, render };
|
||||
globalThis.remixApp = { selects, codeSnippets, data, computed, render };
|
||||
}
|
||||
|
||||
globalThis.remixApp = init();
|
||||
|
||||
init();
|
||||
// Async load CSS for other themes *before* current theme stylesheet
|
||||
let themeStylesheet = document.querySelector('#theme-stylesheet');
|
||||
|
||||
@@ -151,12 +150,14 @@ function render(changedAspect) {
|
||||
// Update code snippets
|
||||
for (let language in codeSnippets) {
|
||||
let codeSnippet = codeSnippets[language];
|
||||
if (!codeSnippet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let code = getThemeCode(data.baseTheme, data.params, { language, cdnUrl });
|
||||
codeSnippet.textContent = code;
|
||||
Prism.highlightElement(codeSnippet);
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('turbo:render', event => {
|
||||
remixApp = init();
|
||||
});
|
||||
addEventListener('turbo:render', init);
|
||||
|
||||
2
docs/docs/themes/tailspin.md
vendored
2
docs/docs/themes/tailspin.md
vendored
@@ -5,4 +5,6 @@ isPro: true
|
||||
tags: pro
|
||||
palette: vogue
|
||||
brand: indigo
|
||||
fonts:
|
||||
body: Inter
|
||||
---
|
||||
|
||||
@@ -27,6 +27,7 @@ See your theme's focus ring in action by navigating this form example with your
|
||||
<style>
|
||||
form > * + * {
|
||||
display: block;
|
||||
--display: block;
|
||||
width: fit-content;
|
||||
margin-block-start: var(--wa-space-m);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ snippet: .wa-cloak
|
||||
---
|
||||
|
||||
Often, components are shown before their logic and styles have had a chance to load, also known as a [Flash of Undefined Custom Elements](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/).
|
||||
|
||||
The FOUCE style utility (which is automatically applied if you use our [style utilities](/docs/utilities/)) automatically takes care of hiding custom elements until **both they and their contents** have been registered, up to a maximum of two seconds.
|
||||
|
||||
In many cases, this is not enough, and you may wish to hide a broader wrapper element or even the entire page until all WA elements within it have loaded.
|
||||
|
||||
@@ -286,7 +286,7 @@ layout: page
|
||||
</wa-callout>
|
||||
</div>
|
||||
<div>
|
||||
<wa-button href="/docs/installation" appearance="outlined" class="tile">
|
||||
<wa-button href="/docs/" appearance="outlined" class="tile">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-block-end: 1rem;">
|
||||
<div class="icon-heading" style="margin-block-end: 0;">
|
||||
<wa-icon name="pen-ruler" fixed-width></wa-icon>
|
||||
|
||||
27
package-lock.json
generated
27
package-lock.json
generated
@@ -10,12 +10,13 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
"@floating-ui/dom": "^1.6.12",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@shoelace-style/animations": "^1.2.0",
|
||||
"@shoelace-style/localize": "^3.2.1",
|
||||
"composed-offset-position": "^0.0.6",
|
||||
"lit": "^3.2.1",
|
||||
"qr-creator": "^1.0.0"
|
||||
"qr-creator": "^1.0.0",
|
||||
"style-observer": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "3.0.0",
|
||||
@@ -1632,18 +1633,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.6.12",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz",
|
||||
"integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz",
|
||||
"integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.6.0",
|
||||
"@floating-ui/utils": "^0.2.8"
|
||||
"@floating-ui/utils": "^0.2.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz",
|
||||
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
|
||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@github/catalyst": {
|
||||
"version": "1.6.0",
|
||||
@@ -13085,6 +13088,12 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/style-observer": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/style-observer/-/style-observer-0.0.7.tgz",
|
||||
"integrity": "sha512-t75H3CRy+vd5q3yqyrf/De4tkz33hPQTiCcfh0NTesI5G7kJnZ227LEYTwqjKTtaFOCJvqZcYFHpJlF8bsk3bQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
|
||||
@@ -68,12 +68,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
"@floating-ui/dom": "^1.6.12",
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@shoelace-style/animations": "^1.2.0",
|
||||
"@shoelace-style/localize": "^3.2.1",
|
||||
"composed-offset-position": "^0.0.6",
|
||||
"lit": "^3.2.1",
|
||||
"qr-creator": "^1.0.0"
|
||||
"qr-creator": "^1.0.0",
|
||||
"style-observer": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "3.0.0",
|
||||
|
||||
@@ -108,15 +108,14 @@ export default class WaAnimatedImage extends WebAwesomeElement {
|
||||
<div part="control-box" class="control-box">
|
||||
<slot name="play-icon">
|
||||
<wa-icon
|
||||
name="play"
|
||||
library="system"
|
||||
name="system:play"
|
||||
variant="solid"
|
||||
class="default"
|
||||
style="margin-inline-start: 3px;"
|
||||
></wa-icon>
|
||||
</slot>
|
||||
<slot name="pause-icon">
|
||||
<wa-icon name="pause" library="system" variant="solid" class="default"></wa-icon>
|
||||
<wa-icon name="system:pause" variant="solid" class="default"></wa-icon>
|
||||
</slot>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -81,7 +81,7 @@ export default class WaAvatar extends WebAwesomeElement {
|
||||
} else {
|
||||
avatarWithoutImage = html`
|
||||
<slot name="icon" part="icon" class="icon" role="img" aria-label=${this.label}>
|
||||
<wa-icon name="user" library="system" variant="solid"></wa-icon>
|
||||
<wa-icon name="system:user" variant="solid"></wa-icon>
|
||||
</slot>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -92,8 +92,7 @@ export default class WaBreadcrumb extends WebAwesomeElement {
|
||||
<span hidden aria-hidden="true">
|
||||
<slot name="separator">
|
||||
<wa-icon
|
||||
name=${this.localize.dir() === 'rtl' ? 'chevron-left' : 'chevron-right'}
|
||||
library="system"
|
||||
name="system:${this.localize.dir() === 'rtl' ? 'chevron-left' : 'chevron-right'}"
|
||||
variant="solid"
|
||||
></wa-icon>
|
||||
</slot>
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
:host {
|
||||
display: contents;
|
||||
position: relative;
|
||||
}
|
||||
--display: inline-flex;
|
||||
|
||||
:where([part~='base']) {
|
||||
all: inherit;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,6 +7,7 @@ import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
|
||||
import nativeStyles from '../../styles/native/button.css';
|
||||
import passthroughStyles from '../../styles/shadow/passthrough.css';
|
||||
import appearanceStyles from '../../styles/utilities/appearance.css';
|
||||
import sizeStyles from '../../styles/utilities/size.css';
|
||||
import variantStyles from '../../styles/utilities/variants.css';
|
||||
@@ -39,6 +40,7 @@ import styles from './button.css';
|
||||
* @csspart caret - The button's caret icon, a `<wa-icon>` element.
|
||||
* @csspart spinner - The spinner that shows when the button is in the loading state.
|
||||
*
|
||||
* @cssproperty --display - Set to `none` to hide the element, or any other valid `display` value to override the internal `display` value of the `base` part.
|
||||
* @cssproperty --background-color - The button's background color when the button is not being interacted with.
|
||||
* @cssproperty --background-color-active - The button's background color when active.
|
||||
* @cssproperty --background-color-hover - The button's background color on hover.
|
||||
@@ -51,7 +53,7 @@ import styles from './button.css';
|
||||
*/
|
||||
@customElement('wa-button')
|
||||
export default class WaButton extends WebAwesomeFormAssociatedElement {
|
||||
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
|
||||
static shadowStyle = [passthroughStyles, variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
|
||||
static rectProxy = 'button';
|
||||
|
||||
static get validators() {
|
||||
@@ -263,9 +265,7 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
|
||||
<slot name="suffix" part="suffix" class="suffix"></slot>
|
||||
${
|
||||
this.caret
|
||||
? html`
|
||||
<wa-icon part="caret" class="caret" library="system" name="chevron-down" variant="solid"></wa-icon>
|
||||
`
|
||||
? html` <wa-icon part="caret" class="caret" name="system:chevron-down" variant="solid"></wa-icon> `
|
||||
: ''
|
||||
}
|
||||
${this.loading ? html`<wa-spinner part="spinner"></wa-spinner>` : ''}
|
||||
|
||||
@@ -608,7 +608,7 @@ export default class WaCarousel extends WebAwesomeElement {
|
||||
@click=${prevEnabled ? () => this.previous() : null}
|
||||
>
|
||||
<slot name="previous-icon">
|
||||
<wa-icon library="system" name="${isRTL ? 'chevron-right' : 'chevron-left'}"></wa-icon>
|
||||
<wa-icon name="system:${isRTL ? 'chevron-right' : 'chevron-left'}"></wa-icon>
|
||||
</slot>
|
||||
</button>
|
||||
|
||||
@@ -625,7 +625,7 @@ export default class WaCarousel extends WebAwesomeElement {
|
||||
@click=${nextEnabled ? () => this.next() : null}
|
||||
>
|
||||
<slot name="next-icon">
|
||||
<wa-icon library="system" name="${isRTL ? 'chevron-left' : 'chevron-right'}"></wa-icon>
|
||||
<wa-icon name="system:${isRTL ? 'chevron-left' : 'chevron-right'}"></wa-icon>
|
||||
</slot>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -234,7 +234,7 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement {
|
||||
@click=${this.handleClick}
|
||||
/>
|
||||
|
||||
<wa-icon part="${iconState}-icon icon" library="system" name=${iconName}></wa-icon>
|
||||
<wa-icon part="${iconState}-icon icon" name="system:${iconName}"></wa-icon>
|
||||
</span>
|
||||
|
||||
<slot part="label"></slot>
|
||||
|
||||
@@ -210,12 +210,6 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
|
||||
/** Disables the color picker. */
|
||||
@property({ type: Boolean }) disabled = false;
|
||||
|
||||
/**
|
||||
* Enable this option to prevent the panel from being clipped when the component is placed inside a container with
|
||||
* `overflow: auto|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all, scenarios.
|
||||
*/
|
||||
@property({ type: Boolean }) hoist = false;
|
||||
|
||||
/** Shows the opacity slider. Enabling this will cause the formatted value to be HEXA, RGBA, or HSLA. */
|
||||
@property({ type: Boolean }) opacity = false;
|
||||
|
||||
@@ -1047,8 +1041,7 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
|
||||
@focus=${this.stopNestedEventPropagation}
|
||||
>
|
||||
<wa-icon
|
||||
library="system"
|
||||
name="eye-dropper"
|
||||
name="system:eye-dropper"
|
||||
variant="solid"
|
||||
label=${this.localize.term('selectAColorFromTheScreen')}
|
||||
></wa-icon>
|
||||
@@ -1097,7 +1090,6 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
|
||||
aria-disabled=${this.disabled ? 'true' : 'false'}
|
||||
.containingElement=${this}
|
||||
?disabled=${this.disabled}
|
||||
?hoist=${this.hoist}
|
||||
@wa-after-show=${this.handleAfterShow}
|
||||
@wa-after-hide=${this.handleAfterHide}
|
||||
>
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-comparer {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
@@ -24,6 +21,10 @@
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&::slotted(:not(img, svg)) {
|
||||
isolation: isolate;
|
||||
}
|
||||
}
|
||||
|
||||
.after {
|
||||
@@ -1,18 +1,19 @@
|
||||
import { expect } from '@open-wc/testing';
|
||||
import { sendKeys } from '@web/test-runner-commands';
|
||||
import { html } from 'lit';
|
||||
import sinon from 'sinon';
|
||||
import { fixtures } from '../../internal/test/fixture.js';
|
||||
import type WaImageComparer from './image-comparer.js';
|
||||
import type WaComparer from './comparer.js';
|
||||
|
||||
describe('<wa-image-comparer>', () => {
|
||||
describe('<wa-comparer>', () => {
|
||||
for (const fixture of fixtures) {
|
||||
describe(`with "${fixture.type}" rendering`, () => {
|
||||
it('should render a basic before/after', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const afterPart = el.shadowRoot!.querySelector<HTMLElement>('[part~="after"]')!;
|
||||
@@ -29,11 +30,11 @@ describe('<wa-image-comparer>', () => {
|
||||
});
|
||||
|
||||
it('should emit change event when position changed manually', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
const handler = sinon.spy();
|
||||
|
||||
@@ -46,194 +47,166 @@ describe('<wa-image-comparer>', () => {
|
||||
});
|
||||
|
||||
it('should increment position on arrow right', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
}),
|
||||
);
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(51);
|
||||
});
|
||||
|
||||
it('should decrement position on arrow left', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(49);
|
||||
});
|
||||
|
||||
it('should set position to 0 on home key', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'Home',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Home' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(0);
|
||||
});
|
||||
|
||||
it('should set position to 100 on end key', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'End',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'End' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(100);
|
||||
});
|
||||
|
||||
it('should clamp to 100 on arrow right', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
el.position = 0;
|
||||
await el.updateComplete;
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(0);
|
||||
});
|
||||
|
||||
it('should clamp to 0 on arrow left', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
el.position = 100;
|
||||
await el.updateComplete;
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(100);
|
||||
});
|
||||
|
||||
it('should increment position by 10 on arrow right + shift', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowRight',
|
||||
shiftKey: true,
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Shift+ArrowRight' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(60);
|
||||
});
|
||||
|
||||
it('should decrement position by 10 on arrow left + shift', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
|
||||
base.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ArrowLeft',
|
||||
shiftKey: true,
|
||||
}),
|
||||
);
|
||||
handle.focus();
|
||||
await sendKeys({ press: 'Shift+ArrowLeft' });
|
||||
await el.updateComplete;
|
||||
|
||||
expect(el.position).to.equal(40);
|
||||
});
|
||||
|
||||
it('should set position by attribute', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer position="10">
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer position="10">
|
||||
<div slot="before"></div>
|
||||
<div slot="after"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
|
||||
expect(el.position).to.equal(10);
|
||||
});
|
||||
|
||||
it('should move position on drag', async () => {
|
||||
const el = await fixture<WaImageComparer>(html`
|
||||
<wa-image-comparer>
|
||||
const el = await fixture<WaComparer>(html`
|
||||
<wa-comparer>
|
||||
<div slot="before" style="width: 50px"></div>
|
||||
<div slot="after" style="width: 50px"></div>
|
||||
</wa-image-comparer>
|
||||
</wa-comparer>
|
||||
`);
|
||||
const handle = el.shadowRoot!.querySelector<HTMLElement>('[part~="handle"]')!;
|
||||
const base = el.shadowRoot!.querySelector<HTMLElement>('[part~="base"]')!;
|
||||
const rect = base.getBoundingClientRect();
|
||||
const rect = handle.getBoundingClientRect();
|
||||
const offsetX = rect.left + window.pageXOffset;
|
||||
const offsetY = rect.top + window.pageYOffset;
|
||||
|
||||
@@ -241,7 +214,7 @@ describe('<wa-image-comparer>', () => {
|
||||
|
||||
document.dispatchEvent(
|
||||
new PointerEvent('pointermove', {
|
||||
clientX: offsetX + 20,
|
||||
clientX: offsetX + 15,
|
||||
clientY: offsetY,
|
||||
}),
|
||||
);
|
||||
@@ -7,52 +7,50 @@ import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
import '../icon/icon.js';
|
||||
import styles from './image-comparer.css';
|
||||
import styles from './comparer.css';
|
||||
|
||||
/**
|
||||
* @summary Compare visual differences between similar photos with a sliding panel.
|
||||
* @documentation https://backers.webawesome.com/docs/components/image-comparer
|
||||
* @summary Compare visual differences between similar content with a sliding panel.
|
||||
* @documentation https://backers.webawesome.com/docs/components/comparer
|
||||
* @status stable
|
||||
* @since 2.0
|
||||
*
|
||||
* @dependency wa-icon
|
||||
*
|
||||
* @slot before - The before image, an `<img>` or `<svg>` element.
|
||||
* @slot after - The after image, an `<img>` or `<svg>` element.
|
||||
* @slot before - The before content, often an `<img>` or `<svg>` element.
|
||||
* @slot after - The after content, often an `<img>` or `<svg>` element.
|
||||
* @slot handle - The icon used inside the handle.
|
||||
*
|
||||
* @event change - Emitted when the position changes.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart before - The container that wraps the before image.
|
||||
* @csspart after - The container that wraps the after image.
|
||||
* @csspart divider - The divider that separates the images.
|
||||
* @csspart handle - The handle that the user drags to expose the after image.
|
||||
* @csspart before - The container that wraps the before content.
|
||||
* @csspart after - The container that wraps the after content.
|
||||
* @csspart divider - The divider that separates the before and after content.
|
||||
* @csspart handle - The handle that the user drags to expose the after content.
|
||||
*
|
||||
* @cssproperty --divider-color - The color of the divider.
|
||||
* @cssproperty --divider-width - The width of the dividing line.
|
||||
* @cssproperty --handle-color - The color of the icon used inside the handle.
|
||||
* @cssproperty --handle-size - The size of the compare handle.
|
||||
*/
|
||||
@customElement('wa-image-comparer')
|
||||
export default class WaImageComparer extends WebAwesomeElement {
|
||||
@customElement('wa-comparer')
|
||||
export default class WaComparer extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
|
||||
private readonly localize = new LocalizeController(this);
|
||||
|
||||
@query('.image-comparer') base: HTMLElement;
|
||||
@query('.handle') handle: HTMLElement;
|
||||
|
||||
/** The position of the divider as a percentage. */
|
||||
@property({ type: Number, reflect: true }) position = 50;
|
||||
|
||||
private handleDrag(event: PointerEvent) {
|
||||
const { width } = this.base.getBoundingClientRect();
|
||||
const { width } = this.getBoundingClientRect();
|
||||
const isRtl = this.localize.dir() === 'rtl';
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
drag(this.base, {
|
||||
drag(this, {
|
||||
onMove: x => {
|
||||
this.position = parseFloat(clamp((x / width) * 100, 0, 100).toFixed(2));
|
||||
if (isRtl) this.position = 100 - this.position;
|
||||
@@ -98,46 +96,45 @@ export default class WaImageComparer extends WebAwesomeElement {
|
||||
const isRtl = this.hasUpdated ? this.localize.dir() === 'rtl' : this.dir === 'rtl';
|
||||
|
||||
return html`
|
||||
<div part="base" id="image-comparer" class="image-comparer" @keydown=${this.handleKeyDown}>
|
||||
<div class="image">
|
||||
<div part="before" class="before">
|
||||
<slot name="before"></slot>
|
||||
</div>
|
||||
|
||||
<div
|
||||
part="after"
|
||||
class="after"
|
||||
style=${styleMap({
|
||||
clipPath: isRtl ? `inset(0 0 0 ${100 - this.position}%)` : `inset(0 ${100 - this.position}% 0 0)`,
|
||||
})}
|
||||
>
|
||||
<slot name="after"></slot>
|
||||
</div>
|
||||
<div class="image">
|
||||
<div part="before" class="before">
|
||||
<slot name="before"></slot>
|
||||
</div>
|
||||
|
||||
<div
|
||||
part="divider"
|
||||
class="divider"
|
||||
part="after"
|
||||
class="after"
|
||||
style=${styleMap({
|
||||
left: isRtl ? `${100 - this.position}%` : `${this.position}%`,
|
||||
clipPath: isRtl ? `inset(0 0 0 ${100 - this.position}%)` : `inset(0 ${100 - this.position}% 0 0)`,
|
||||
})}
|
||||
@mousedown=${this.handleDrag}
|
||||
@touchstart=${this.handleDrag}
|
||||
>
|
||||
<div
|
||||
part="handle"
|
||||
class="handle"
|
||||
role="scrollbar"
|
||||
aria-valuenow=${this.position}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
aria-controls="image-comparer"
|
||||
tabindex="0"
|
||||
>
|
||||
<slot name="handle">
|
||||
<wa-icon library="system" name="grip-vertical" variant="solid"></wa-icon>
|
||||
</slot>
|
||||
</div>
|
||||
<slot name="after"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
part="divider"
|
||||
class="divider"
|
||||
style=${styleMap({
|
||||
left: isRtl ? `${100 - this.position}%` : `${this.position}%`,
|
||||
})}
|
||||
@keydown=${this.handleKeyDown}
|
||||
@mousedown=${this.handleDrag}
|
||||
@touchstart=${this.handleDrag}
|
||||
>
|
||||
<div
|
||||
part="handle"
|
||||
class="handle"
|
||||
role="scrollbar"
|
||||
aria-valuenow=${this.position}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
aria-controls="comparer"
|
||||
tabindex="0"
|
||||
>
|
||||
<slot name="handle">
|
||||
<wa-icon name="system:grip-vertical" variant="solid"></wa-icon>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -146,6 +143,6 @@ export default class WaImageComparer extends WebAwesomeElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'wa-image-comparer': WaImageComparer;
|
||||
'wa-comparer': WaComparer;
|
||||
}
|
||||
}
|
||||
@@ -97,13 +97,6 @@ export default class WaCopyButton extends WebAwesomeElement {
|
||||
/** The preferred placement of the tooltip. */
|
||||
@property({ attribute: 'tooltip-placement' }) tooltipPlacement: 'top' | 'right' | 'bottom' | 'left' = 'top';
|
||||
|
||||
/**
|
||||
* Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with
|
||||
* `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all,
|
||||
* scenarios.
|
||||
*/
|
||||
@property({ type: Boolean }) hoist = false;
|
||||
|
||||
private async handleCopy() {
|
||||
if (this.disabled || this.isCopying) {
|
||||
return;
|
||||
@@ -203,13 +196,13 @@ export default class WaCopyButton extends WebAwesomeElement {
|
||||
<!-- Render a visually hidden label to appease the accessibility checking gods -->
|
||||
<span class="wa-visually-hidden">${this.currentLabel}</span>
|
||||
<slot part="copy-icon" name="copy-icon">
|
||||
<wa-icon library="system" name="copy" variant="regular" fixed-width></wa-icon>
|
||||
<wa-icon name="system:copy" variant="regular" fixed-width></wa-icon>
|
||||
</slot>
|
||||
<slot part="success-icon" name="success-icon" variant="solid" hidden>
|
||||
<wa-icon library="system" name="check" fixed-width></wa-icon>
|
||||
<wa-icon name="system:check" fixed-width></wa-icon>
|
||||
</slot>
|
||||
<slot part="error-icon" name="error-icon" variant="solid" hidden>
|
||||
<wa-icon library="system" name="xmark" fixed-width></wa-icon>
|
||||
<wa-icon name="system:xmark" fixed-width></wa-icon>
|
||||
</slot>
|
||||
<wa-tooltip
|
||||
class=${classMap({
|
||||
@@ -220,7 +213,6 @@ export default class WaCopyButton extends WebAwesomeElement {
|
||||
for="copy-button"
|
||||
placement=${this.tooltipPlacement}
|
||||
?disabled=${this.disabled}
|
||||
?hoist=${this.hoist}
|
||||
exportparts="
|
||||
base:tooltip__base,
|
||||
base__popup:tooltip__base__popup,
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
:host {
|
||||
--show-duration: 200ms;
|
||||
--hide-duration: 200ms;
|
||||
|
||||
display: contents !important;
|
||||
--display: block;
|
||||
}
|
||||
|
||||
details {
|
||||
all: inherit;
|
||||
display: block;
|
||||
overflow-anchor: none;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user